summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnup Patel <anup.patel@wdc.com>2018-12-11 16:54:06 +0300
committerAnup Patel <anup@brainfault.org>2018-12-11 16:54:06 +0300
commit9e8ff05cb61f157fb0bcb6b0071d7b6dc0763faa (patch)
treeb9513a86b3b36e569cb46387846fee9c5544f566
downloadopensbi-9e8ff05cb61f157fb0bcb6b0071d7b6dc0763faa.tar.xz
Initial commit.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
-rw-r--r--LICENSE37
-rw-r--r--Makefile296
-rw-r--r--README.md37
-rw-r--r--blob/fw_common.S305
-rw-r--r--blob/fw_common.ldS89
-rw-r--r--blob/fw_jump.S44
-rw-r--r--blob/fw_jump.elf.ldS16
-rw-r--r--blob/fw_payload.S46
-rw-r--r--blob/fw_payload.elf.ldS26
-rw-r--r--blob/objects.mk29
-rw-r--r--include/sbi/riscv_asm.h244
-rw-r--r--include/sbi/riscv_atomic.h38
-rw-r--r--include/sbi/riscv_barrier.h53
-rw-r--r--include/sbi/riscv_encoding.h423
-rw-r--r--include/sbi/riscv_io.h109
-rw-r--r--include/sbi/riscv_locks.h33
-rw-r--r--include/sbi/sbi_bits.h44
-rw-r--r--include/sbi/sbi_console.h37
-rw-r--r--include/sbi/sbi_const.h43
-rw-r--r--include/sbi/sbi_ecall.h26
-rw-r--r--include/sbi/sbi_emulate_csr.h27
-rw-r--r--include/sbi/sbi_error.h25
-rw-r--r--include/sbi/sbi_hart.h41
-rw-r--r--include/sbi/sbi_illegal_insn.h22
-rw-r--r--include/sbi/sbi_init.h19
-rw-r--r--include/sbi/sbi_ipi.h33
-rw-r--r--include/sbi/sbi_platform.h258
-rw-r--r--include/sbi/sbi_scratch.h35
-rw-r--r--include/sbi/sbi_system.h31
-rw-r--r--include/sbi/sbi_timer.h30
-rw-r--r--include/sbi/sbi_trap.h57
-rw-r--r--include/sbi/sbi_types.h57
-rw-r--r--include/sbi/sbi_unpriv.h111
-rw-r--r--lib/objects.mk23
-rw-r--r--lib/riscv_asm.c275
-rw-r--r--lib/riscv_atomic.c152
-rw-r--r--lib/riscv_locks.c46
-rw-r--r--lib/sbi_console.c367
-rw-r--r--lib/sbi_ecall.c98
-rw-r--r--lib/sbi_emulate_csr.c157
-rw-r--r--lib/sbi_hart.c294
-rw-r--r--lib/sbi_illegal_insn.c190
-rw-r--r--lib/sbi_init.c162
-rw-r--r--lib/sbi_ipi.c82
-rw-r--r--lib/sbi_system.c47
-rw-r--r--lib/sbi_timer.c78
-rw-r--r--lib/sbi_trap.c110
-rw-r--r--plat/common/fdt.c314
-rw-r--r--plat/common/include/plat/fdt.h73
-rw-r--r--plat/common/include/plat/irqchip/plic.h22
-rw-r--r--plat/common/include/plat/serial/sifive-uart.h22
-rw-r--r--plat/common/include/plat/serial/uart8250.h23
-rw-r--r--plat/common/include/plat/sys/clint.h35
-rw-r--r--plat/common/irqchip/objects.mk10
-rw-r--r--plat/common/irqchip/plic.c118
-rw-r--r--plat/common/objects.mk10
-rw-r--r--plat/common/serial/objects.mk11
-rw-r--r--plat/common/serial/sifive-uart.c73
-rw-r--r--plat/common/serial/uart8250.c117
-rw-r--r--plat/common/sys/clint.c136
-rw-r--r--plat/common/sys/objects.mk10
-rw-r--r--plat/qemu/virt/config.mk31
-rw-r--r--plat/qemu/virt/objects.mk10
-rw-r--r--plat/qemu/virt/platform.c112
-rw-r--r--plat/sifive/hifive_u540/config.mk31
-rw-r--r--plat/sifive/hifive_u540/objects.mk10
-rw-r--r--plat/sifive/hifive_u540/platform.c114
67 files changed, 6084 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1cdc70e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,37 @@
+Copyright (c) 2018 Western Digital Corporation or its affiliates.
+
+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 OWNER 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.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies,
+either expressed or implied, of the <project name> project.
+
+--------------
+
+Note:
+Individual files contain the following tag instead 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 here available: http://spdx.org/licenses/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ff41674
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,296 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Current Version
+MAJOR = 0
+MINOR = 1
+
+# Select Make Options:
+# o Do not use make's built-in rules and variables
+# o Do not print "Entering directory ...";
+MAKEFLAGS += -rR --no-print-directory
+
+# 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
+ifdef I
+ install_dir=$(shell readlink -f $(I))
+else
+ install_dir=$(CURDIR)/install
+endif
+ifeq ($(install_dir),$(CURDIR))
+$(error Install directory is same as source directory.)
+endif
+ifeq ($(install_dir),$(build_dir))
+$(error Install directory is same as build directory.)
+endif
+
+# Check if verbosity is ON for build process
+VERBOSE_DEFAULT := 0
+CMD_PREFIX_DEFAULT := @
+ifdef VERBOSE
+ ifeq ("$(origin VERBOSE)", "command line")
+ VB := $(VERBOSE)
+ else
+ VB := $(VERBOSE_DEFAULT)
+ endif
+else
+ VB := $(VERBOSE_DEFAULT)
+endif
+ifeq ($(VB), 1)
+ override V :=
+else
+ override V := $(CMD_PREFIX_DEFAULT)
+endif
+
+# Setup path of directories
+export plat_subdir=plat/$(PLAT)
+export plat_dir=$(CURDIR)/$(plat_subdir)
+export plat_common_dir=$(CURDIR)/plat/common
+export include_dir=$(CURDIR)/include
+export lib_dir=$(CURDIR)/lib
+export blob_dir=$(CURDIR)/blob
+
+# Setup list of objects.mk files
+ifdef PLAT
+plat-object-mks=$(shell if [ -d $(plat_dir) ]; then find $(plat_dir) -iname "objects.mk" | sort -r; fi)
+plat-common-object-mks=$(shell if [ -d $(plat_common_dir) ]; then find $(plat_common_dir) -iname "objects.mk" | sort -r; fi)
+endif
+lib-object-mks=$(shell if [ -d $(lib_dir) ]; then find $(lib_dir) -iname "objects.mk" | sort -r; fi)
+blob-object-mks=$(shell if [ -d $(blob_dir) ]; then find $(blob_dir) -iname "objects.mk" | sort -r; fi)
+
+# Include platform specifig config.mk
+ifdef PLAT
+include $(plat_dir)/config.mk
+endif
+
+# Include all object.mk files
+ifdef PLAT
+include $(plat-object-mks)
+include $(plat-common-object-mks)
+endif
+include $(lib-object-mks)
+include $(blob-object-mks)
+
+# Setup list of objects
+lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj))
+ifdef PLAT
+plat-objs-path-y=$(foreach obj,$(plat-objs-y),$(build_dir)/$(plat_subdir)/$(obj))
+plat-common-objs-path-y=$(foreach obj,$(plat-common-objs-y),$(build_dir)/plat/common/$(obj))
+blob-bins-path-y=$(foreach bin,$(blob-bins-y),$(build_dir)/$(plat_subdir)/blob/$(bin))
+endif
+blob-elfs-path-y=$(blob-bins-path-y:.bin=.elf)
+blob-objs-path-y=$(blob-bins-path-y:.bin=.o)
+
+# Setup list of deps files for objects
+deps-y=$(plat-objs-path-y:.o=.dep)
+deps-y+=$(plat-common-objs-path-y:.o=.dep)
+deps-y+=$(lib-objs-path-y:.o=.dep)
+deps-y+=$(blob-objs-path-y:.o=.dep)
+
+# Setup compilation environment
+cpp=$(CROSS_COMPILE)cpp
+cppflags+=-DOPENSBI_MAJOR=$(MAJOR)
+cppflags+=-DOPENSBI_MINOR=$(MINOR)
+cppflags+=-I$(plat_dir)/include
+cppflags+=-I$(plat_common_dir)/include
+cppflags+=-I$(include_dir)
+cppflags+=$(plat-cppflags-y)
+cppflags+=$(blob-cppflags-y)
+cc=$(CROSS_COMPILE)gcc
+cflags=-g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
+cflags+=-fno-omit-frame-pointer -fno-optimize-sibling-calls
+cflags+=-mno-save-restore -mstrict-align
+cflags+=$(cppflags)
+cflags+=$(plat-cflags-y)
+cflags+=$(blob-cflags-y)
+cflags+=$(EXTRA_CFLAGS)
+as=$(CROSS_COMPILE)gcc
+asflags=-g -Wall -nostdlib -D__ASSEMBLY__
+asflags+=-fno-omit-frame-pointer -fno-optimize-sibling-calls
+asflags+=-mno-save-restore -mstrict-align
+asflags+=$(cppflags)
+asflags+=$(plat-asflags-y)
+asflags+=$(blob-asflags-y)
+asflags+=$(EXTRA_ASFLAGS)
+ar=$(CROSS_COMPILE)ar
+arflags=rcs
+ld=$(CROSS_COMPILE)gcc
+ldflags=-g -Wall -nostdlib -Wl,--build-id=none
+ldflags+=$(plat-ldflags-y)
+ldflags+=$(blob-ldflags-y)
+merge=$(CROSS_COMPILE)ld
+mergeflags=-r
+objcopy=$(CROSS_COMPILE)objcopy
+
+# Setup functions for compilation
+define dynamic_flags
+-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
+endef
+merge_objs = $(V)mkdir -p `dirname $(1)`; \
+ echo " MERGE $(subst $(build_dir)/,,$(1))"; \
+ $(merge) $(mergeflags) $(2) -o $(1)
+merge_deps = $(V)mkdir -p `dirname $(1)`; \
+ echo " MERGE-DEP $(subst $(build_dir)/,,$(1))"; \
+ cat $(2) > $(1)
+copy_file = $(V)mkdir -p `dirname $(1)`; \
+ echo " COPY $(subst $(build_dir)/,,$(1))"; \
+ cp -f $(2) $(1)
+inst_file = $(V)mkdir -p `dirname $(1)`; \
+ echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
+ cp -f $(2) $(1)
+inst_file_list = $(V)if [ ! -z "$(3)" ]; then \
+ mkdir -p $(1); \
+ for f in $(3) ; do \
+ echo " INSTALL "$(2)"/"`basename $$f`; \
+ cp -f $$f $(1); \
+ done \
+ fi
+inst_header_dir = $(V)mkdir -p $(1); \
+ echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
+ cp -rf $(2) $(1)
+compile_cpp = $(V)mkdir -p `dirname $(1)`; \
+ echo " CPP $(subst $(build_dir)/,,$(1))"; \
+ $(cpp) $(cppflags) $(2) | grep -v "\#" > $(1)
+compile_cc_dep = $(V)mkdir -p `dirname $(1)`; \
+ echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
+ echo -n `dirname $(1)`/ > $(1) && \
+ $(cc) $(cflags) $(call dynamic_flags,$(1),$(2)) \
+ -MM $(2) >> $(1) || rm -f $(1)
+compile_cc = $(V)mkdir -p `dirname $(1)`; \
+ echo " CC $(subst $(build_dir)/,,$(1))"; \
+ $(cc) $(cflags) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_as_dep = $(V)mkdir -p `dirname $(1)`; \
+ echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
+ echo -n `dirname $(1)`/ > $(1) && \
+ $(as) $(asflags) $(call dynamic_flags,$(1),$(2)) \
+ -MM $(2) >> $(1) || rm -f $(1)
+compile_as = $(V)mkdir -p `dirname $(1)`; \
+ echo " AS $(subst $(build_dir)/,,$(1))"; \
+ $(as) $(asflags) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_ld = $(V)mkdir -p `dirname $(1)`; \
+ echo " LD $(subst $(build_dir)/,,$(1))"; \
+ $(ld) $(3) $(ldflags) -Wl,-T$(2) -o $(1)
+compile_ar = $(V)mkdir -p `dirname $(1)`; \
+ echo " AR $(subst $(build_dir)/,,$(1))"; \
+ $(ar) $(arflags) $(1) $(2)
+compile_objcopy = $(V)mkdir -p `dirname $(1)`; \
+ echo " OBJCOPY $(subst $(build_dir)/,,$(1))"; \
+ $(objcopy) -S -O binary $(2) $(1)
+
+targets-y = $(build_dir)/lib/libsbi.a
+ifdef PLAT
+targets-y += $(build_dir)/$(plat_subdir)/lib/libplatsbi.a
+endif
+targets-y += $(blob-bins-path-y)
+
+# Default rule "make" should always be first rule
+.PHONY: all
+all: $(targets-y)
+
+# Preserve all intermediate files
+.SECONDARY:
+
+$(build_dir)/%.bin: $(build_dir)/%.elf
+ $(call compile_objcopy,$@,$<)
+
+$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(plat_subdir)/lib/libplatsbi.a
+ $(call compile_ld,$@,$@.ld,$< $(build_dir)/$(plat_subdir)/lib/libplatsbi.a)
+
+$(build_dir)/$(plat_subdir)/%.ld: $(src_dir)/%.ldS
+ $(call compile_cpp,$@,$<)
+
+$(build_dir)/lib/libsbi.a: $(lib-objs-path-y)
+ $(call compile_ar,$@,$^)
+
+$(build_dir)/$(plat_subdir)/lib/libplatsbi.a: $(lib-objs-path-y) $(plat-common-objs-path-y) $(plat-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,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.dep: $(src_dir)/%.c
+ $(call compile_cc_dep,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.o: $(src_dir)/%.c
+ $(call compile_cc,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.dep: $(src_dir)/%.S
+ $(call compile_as_dep,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.o: $(src_dir)/%.S
+ $(call compile_as,$@,$<)
+
+# Dependency files should only be included after default Makefile rule
+# 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)
+
+install_targets-y = install_libsbi
+ifdef PLAT
+install_targets-y += install_libplatsbi
+install_targets-y += install_blobs
+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_dir)/include,$(include_dir)/sbi)
+ $(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
+
+.PHONY: install_libplatsbi
+install_libplatsbi: $(build_dir)/$(plat_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
+ $(call inst_header_dir,$(install_dir)/$(plat_subdir)/include,$(include_dir)/sbi)
+ $(call inst_file,$(install_dir)/$(plat_subdir)/lib/libplatsbi.a,$(build_dir)/$(plat_subdir)/lib/libplatsbi.a)
+
+.PHONY: install_blobs
+install_blobs: $(build_dir)/$(plat_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(blob-bins-path-y)
+ $(call inst_file_list,$(install_dir)/$(plat_subdir)/blob,$(plat_subdir)/blob,$(blob-elfs-path-y))
+ $(call inst_file_list,$(install_dir)/$(plat_subdir)/blob,$(plat_subdir)/blob,$(blob-bins-path-y))
+
+# Rule for "make clean"
+.PHONY: clean
+clean:
+ifeq ($(build_dir),$(CURDIR)/build)
+ $(V)mkdir -p $(build_dir)
+ $(if $(V), @echo " CLEAN $(build_dir)")
+ $(V)find $(build_dir) -maxdepth 1 -type f -exec rm -rf {} +
+endif
+
+# Rule for "make distclean"
+.PHONY: distclean
+distclean:
+ifeq ($(build_dir),$(CURDIR)/build)
+ $(if $(V), @echo " RM $(build_dir)")
+ $(V)rm -rf $(build_dir)
+endif
+ifeq ($(install_dir),$(CURDIR)/install)
+ $(if $(V), @echo " RM $(install_dir)")
+ $(V)rm -rf $(install_dir)
+endif
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3892273
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+RISC-V Open Source Supervisor Binary Interface (OpenSBI)
+========================================================
+
+The RISC-V Supervisor Binary Interface (SBI) is a recommended
+interface between:
+1. platform specific firmware running in M-mode and bootloader
+ running in S-mode
+2. platform specific firmware running in M-mode and general
+ purpose operating system running in S-mode
+3. hypervisor runnng in HS-mode and general purpose operating
+ system running in VS-mode.
+
+The RISC-V SBI spec is maintained as independent project by
+RISC-V Foundation at https://github.com/riscv/riscv-sbi-doc
+
+The RISC-V OpenSBI project aims to provides an open-source and
+extensible implementation of the SBI spec. This project can be
+easily extended by RISC-V platform or RISC-V System-on-Chip vendors.
+
+
+How to Build?
+-------------
+
+Below are the steps to cross-compile and install RISC-V OpenSBI:
+
+1. Setup build environment
+$ CROSS_COMPILE=riscv64-unknown-linux-gnu-
+
+2. Build sources
+$ make PLAT=<platform_name>
+OR
+$ make PLAT=<platform_name> O=<build_directory>
+
+3. Install blobs
+$ make PLAT=<platform_name> install
+OR
+$ make PLAT=<platform_name> I=<install_directory> install
diff --git a/blob/fw_common.S b/blob/fw_common.S
new file mode 100644
index 0000000..9cc2b09
--- /dev/null
+++ b/blob/fw_common.S
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .globl _start
+ .globl _start_warm
+_start:
+ /* Jump to warm-boot for mhartid != 0 */
+ csrr a6, mhartid
+ blt zero, a6, _wait_for_boot_hart
+
+ /* 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
+
+ /*
+ * Relocate FDT
+ * Note: We will preserve a0 and a1 passed by
+ * previous booting stage.
+ */
+ /* Mask values in a3 and a4 */
+ li a3, ~0xf
+ li a4, 0xff
+ /* t1 = destinetion FDT start address */
+ add s0, a0, zero
+ add s1, a1, zero
+ call fw_next_arg1
+ add t1, a0, zero
+ add a0, s0, zero
+ add a1, s1, zero
+ beqz t1, _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 */
+ lwu t2, 4(t0)
+ /* 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 = destinetion 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:
+
+ /* Update boot hart flag */
+ la a4, _boot_hart_done
+ li a5, 1
+ REG_S a5, (a4)
+ j _wait_for_boot_hart
+
+ .align 3
+_boot_hart_done:
+ RISCV_PTR 0
+ .align 3
+
+ /* Wait for boot hart */
+_wait_for_boot_hart:
+ la a4, _boot_hart_done
+ REG_L a5, (a4)
+ beqz a5, _wait_for_boot_hart
+
+_start_warm:
+ /* Disable and clear all interrupts */
+ csrw mie, zero
+ csrw mip, zero
+
+ /* HART ID should be withing expected limit */
+ csrr a6, mhartid
+ li a5, PLAT_HART_COUNT
+ bge a6, a5, _start_hang
+
+ /* Setup scratch space */
+ li a5, PLAT_HART_STACK_SIZE
+ la tp, _stack_end
+ mul a5, a5, a6
+ sub tp, tp, a5
+ li a5, RISCV_SCRATCH_SIZE
+ sub tp, tp, a5
+ csrw mscratch, tp
+
+ /* Initialize scratch space */
+ REG_S zero, RISCV_SCRATCH_TMP0_OFFSET(tp)
+ la a4, _fw_start
+ la a5, _fw_end
+ sub a5, a5, a4
+ REG_S a4, RISCV_SCRATCH_FW_START_OFFSET(tp)
+ REG_S a5, RISCV_SCRATCH_FW_SIZE_OFFSET(tp)
+ /* Note: fw_next_arg1() uses a0, a1, and ra */
+ call fw_next_arg1
+ REG_S a0, RISCV_SCRATCH_NEXT_ARG1_OFFSET(tp)
+ /* Note: fw_next_addr() uses a0, a1, and ra */
+ call fw_next_addr
+ REG_S a0, RISCV_SCRATCH_NEXT_ADDR_OFFSET(tp)
+ li a4, PRV_S
+ REG_S a4, RISCV_SCRATCH_NEXT_MODE_OFFSET(tp)
+ la a4, _start_warm
+ REG_S a4, RISCV_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
+ la a4, platform
+ REG_S a4, RISCV_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
+ la a4, _hartid_to_scratch
+ REG_S a4, RISCV_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
+ REG_S zero, RISCV_SCRATCH_IPI_TYPE_OFFSET(tp)
+
+ /* Setup stack */
+ add sp, tp, zero
+
+ /* Setup trap handler */
+ la a4, _trap_handler
+ csrw mtvec, a4
+
+ /* Initialize SBI runtime */
+ csrr a0, mscratch
+ call sbi_init
+
+ /* We don't expect to reach here hence just hang */
+ j _start_hang
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .globl _hartid_to_scratch
+_hartid_to_scratch:
+ add sp, sp, -(2 * __SIZEOF_POINTER__)
+ REG_S a1, (sp)
+ REG_S a2, (__SIZEOF_POINTER__)(sp)
+ li a1, PLAT_HART_STACK_SIZE
+ la a2, _stack_end
+ mul a1, a1, a0
+ sub a2, a2, a1
+ li a1, RISCV_SCRATCH_SIZE
+ sub a0, a2, a1
+ REG_L a1, (sp)
+ REG_L a2, (__SIZEOF_POINTER__)(sp)
+ add sp, sp, (2 * __SIZEOF_POINTER__)
+ ret
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .globl _start_hang
+_start_hang:
+ wfi
+ j _start_hang
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .globl _trap_handler
+_trap_handler:
+ /* Swap SP and MSCRATCH */
+ csrrw sp, mscratch, sp
+
+ /* Setup exception stack */
+ add sp, sp, -(RISCV_TRAP_REGS_SIZE)
+
+ /* Save RA, T0, T1, and T2 */
+ REG_S ra, RISCV_TRAP_REGS_OFFSET(ra)(sp)
+ REG_S t0, RISCV_TRAP_REGS_OFFSET(t0)(sp)
+ REG_S t1, RISCV_TRAP_REGS_OFFSET(t1)(sp)
+ REG_S t2, RISCV_TRAP_REGS_OFFSET(t2)(sp)
+
+ /* Save original SP and restore MSCRATCH */
+ add t0, sp, RISCV_TRAP_REGS_SIZE
+ csrrw t0, mscratch, t0
+ REG_S t0, RISCV_TRAP_REGS_OFFSET(sp)(sp)
+
+ /* Save MEPC and MSTATUS CSRs */
+ csrr t0, mepc
+ csrr t1, mstatus
+
+ /*
+ * Note: Fast path trap handling can be done here
+ * using SP, RA, T0, T1, and T2 registers where
+ * T0 <- MEPC
+ * T1 <- MSTATUS
+ */
+
+ /* Save MEPC and MSTATUS CSRs */
+ REG_S t0, RISCV_TRAP_REGS_OFFSET(mepc)(sp)
+ REG_S t1, RISCV_TRAP_REGS_OFFSET(mstatus)(sp)
+
+ /* Save all general regisers except SP, RA, T0, T1, and T2 */
+ REG_S zero, RISCV_TRAP_REGS_OFFSET(zero)(sp)
+ REG_S gp, RISCV_TRAP_REGS_OFFSET(gp)(sp)
+ REG_S tp, RISCV_TRAP_REGS_OFFSET(tp)(sp)
+ REG_S s0, RISCV_TRAP_REGS_OFFSET(s0)(sp)
+ REG_S s1, RISCV_TRAP_REGS_OFFSET(s1)(sp)
+ REG_S a0, RISCV_TRAP_REGS_OFFSET(a0)(sp)
+ REG_S a1, RISCV_TRAP_REGS_OFFSET(a1)(sp)
+ REG_S a2, RISCV_TRAP_REGS_OFFSET(a2)(sp)
+ REG_S a3, RISCV_TRAP_REGS_OFFSET(a3)(sp)
+ REG_S a4, RISCV_TRAP_REGS_OFFSET(a4)(sp)
+ REG_S a5, RISCV_TRAP_REGS_OFFSET(a5)(sp)
+ REG_S a6, RISCV_TRAP_REGS_OFFSET(a6)(sp)
+ REG_S a7, RISCV_TRAP_REGS_OFFSET(a7)(sp)
+ REG_S s2, RISCV_TRAP_REGS_OFFSET(s2)(sp)
+ REG_S s3, RISCV_TRAP_REGS_OFFSET(s3)(sp)
+ REG_S s4, RISCV_TRAP_REGS_OFFSET(s4)(sp)
+ REG_S s5, RISCV_TRAP_REGS_OFFSET(s5)(sp)
+ REG_S s6, RISCV_TRAP_REGS_OFFSET(s6)(sp)
+ REG_S s7, RISCV_TRAP_REGS_OFFSET(s7)(sp)
+ REG_S s8, RISCV_TRAP_REGS_OFFSET(s8)(sp)
+ REG_S s9, RISCV_TRAP_REGS_OFFSET(s9)(sp)
+ REG_S s10, RISCV_TRAP_REGS_OFFSET(s10)(sp)
+ REG_S s11, RISCV_TRAP_REGS_OFFSET(s11)(sp)
+ REG_S t3, RISCV_TRAP_REGS_OFFSET(t3)(sp)
+ REG_S t4, RISCV_TRAP_REGS_OFFSET(t4)(sp)
+ REG_S t5, RISCV_TRAP_REGS_OFFSET(t5)(sp)
+ REG_S t6, RISCV_TRAP_REGS_OFFSET(t6)(sp)
+
+ /* Call C routine */
+ add a0, sp, zero
+ csrr a1, mscratch
+ call sbi_trap_handler
+
+ /* Restore all general regisers except SP, RA, T0, T1, T2, and T3 */
+ REG_L gp, RISCV_TRAP_REGS_OFFSET(gp)(sp)
+ REG_L tp, RISCV_TRAP_REGS_OFFSET(tp)(sp)
+ REG_L s0, RISCV_TRAP_REGS_OFFSET(s0)(sp)
+ REG_L s1, RISCV_TRAP_REGS_OFFSET(s1)(sp)
+ REG_L a0, RISCV_TRAP_REGS_OFFSET(a0)(sp)
+ REG_L a1, RISCV_TRAP_REGS_OFFSET(a1)(sp)
+ REG_L a2, RISCV_TRAP_REGS_OFFSET(a2)(sp)
+ REG_L a3, RISCV_TRAP_REGS_OFFSET(a3)(sp)
+ REG_L a4, RISCV_TRAP_REGS_OFFSET(a4)(sp)
+ REG_L a5, RISCV_TRAP_REGS_OFFSET(a5)(sp)
+ REG_L a6, RISCV_TRAP_REGS_OFFSET(a6)(sp)
+ REG_L a7, RISCV_TRAP_REGS_OFFSET(a7)(sp)
+ REG_L s2, RISCV_TRAP_REGS_OFFSET(s2)(sp)
+ REG_L s3, RISCV_TRAP_REGS_OFFSET(s3)(sp)
+ REG_L s4, RISCV_TRAP_REGS_OFFSET(s4)(sp)
+ REG_L s5, RISCV_TRAP_REGS_OFFSET(s5)(sp)
+ REG_L s6, RISCV_TRAP_REGS_OFFSET(s6)(sp)
+ REG_L s7, RISCV_TRAP_REGS_OFFSET(s7)(sp)
+ REG_L s8, RISCV_TRAP_REGS_OFFSET(s8)(sp)
+ REG_L s9, RISCV_TRAP_REGS_OFFSET(s9)(sp)
+ REG_L s10, RISCV_TRAP_REGS_OFFSET(s10)(sp)
+ REG_L s11, RISCV_TRAP_REGS_OFFSET(s11)(sp)
+ REG_L t3, RISCV_TRAP_REGS_OFFSET(t3)(sp)
+ REG_L t4, RISCV_TRAP_REGS_OFFSET(t4)(sp)
+ REG_L t5, RISCV_TRAP_REGS_OFFSET(t5)(sp)
+ REG_L t6, RISCV_TRAP_REGS_OFFSET(t6)(sp)
+
+ /* Load T0 and T1 with MEPC and MSTATUS */
+ REG_L t0, RISCV_TRAP_REGS_OFFSET(mepc)(sp)
+ REG_L t1, RISCV_TRAP_REGS_OFFSET(mstatus)(sp)
+
+ /*
+ * Note: Jump here after fast trap handling
+ * using SP, RA, T0, T1, and T2
+ * T0 <- MEPC
+ * T1 <- MSTATUS
+ */
+
+ /* Restore MEPC and MSTATUS CSRs */
+ csrw mepc, t0
+ csrw mstatus, t1
+
+ /* Restore RA, T0, T1, and T2 */
+ REG_L ra, RISCV_TRAP_REGS_OFFSET(ra)(sp)
+ REG_L t0, RISCV_TRAP_REGS_OFFSET(t0)(sp)
+ REG_L t1, RISCV_TRAP_REGS_OFFSET(t1)(sp)
+ REG_L t2, RISCV_TRAP_REGS_OFFSET(t2)(sp)
+
+ /* Restore SP */
+ REG_L sp, RISCV_TRAP_REGS_OFFSET(sp)(sp)
+
+ mret
diff --git a/blob/fw_common.ldS b/blob/fw_common.ldS
new file mode 100644
index 0000000..eac7ede
--- /dev/null
+++ b/blob/fw_common.ldS
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+ . = PLAT_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 = .);
+
+ *(.data)
+ *(.data.*)
+ *(.readmostly.data)
+ *(*.data)
+ . = ALIGN(8);
+
+ PROVIDE(_data_end = .);
+ }
+
+ . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+ .stack :
+ {
+ PROVIDE(_stack_start = .);
+ *(.stack)
+ *(.stack.*)
+ . = . + (PLAT_HART_STACK_SIZE * PLAT_HART_COUNT);
+ . = ALIGN(8);
+ PROVIDE(_stack_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(_fw_end = .);
diff --git a/blob/fw_jump.S b/blob/fw_jump.S
new file mode 100644
index 0000000..960e594
--- /dev/null
+++ b/blob/fw_jump.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "fw_common.S"
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .global fw_next_arg1
+fw_next_arg1:
+ /* We return FDT destinetion address in 'a0' */
+#ifdef FW_JUMP_FDT_OFFSET
+ /* a0 = destinetion FDT start address */
+ la a0, _jump_addr
+ REG_L a0, (a0)
+ li a1, FW_JUMP_FDT_OFFSET
+ add a0, a0, a1
+#else
+ add a0, zero, zero
+#endif
+ ret
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .global fw_next_addr
+fw_next_addr:
+ /* We return next address in 'a0' */
+ la a0, _jump_addr
+ REG_L a0, (a0)
+ ret
+
+#ifndef FW_JUMP_ADDR
+#error "Must define FW_JUMP_ADDR"
+#endif
+
+ .align 3
+ .section .entry, "ax", %progbits
+_jump_addr:
+ RISCV_PTR FW_JUMP_ADDR
diff --git a/blob/fw_jump.elf.ldS b/blob/fw_jump.elf.ldS
new file mode 100644
index 0000000..dfffbf6
--- /dev/null
+++ b/blob/fw_jump.elf.ldS
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+ #include "fw_common.ldS"
+}
diff --git a/blob/fw_payload.S b/blob/fw_payload.S
new file mode 100644
index 0000000..abc2495
--- /dev/null
+++ b/blob/fw_payload.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "fw_common.S"
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .global fw_next_arg1
+fw_next_arg1:
+ /* We return FDT destinetion address in 'a0' */
+#ifdef FW_PAYLOAD_FDT_OFFSET
+ /* a0 = destinetion FDT start address */
+ la a0, payload_bin
+ li a1, FW_PAYLOAD_FDT_OFFSET
+ add a0, a0, a1
+#else
+ add a0, zero, zero
+#endif
+ ret
+
+ .align 3
+ .section .entry, "ax", %progbits
+ .global fw_next_addr
+fw_next_addr:
+ /* We return next address in 'a0' */
+ la a0, payload_bin
+ ret
+
+#define str(s) #s
+#define stringify(s) str(s)
+
+ .section .payload, "ax", %progbits
+ .globl payload_bin
+payload_bin:
+#ifndef FW_PAYLOAD_PATH
+ wfi
+ j payload_bin
+#else
+ .incbin stringify(FW_PAYLOAD_PATH)
+#endif
diff --git a/blob/fw_payload.elf.ldS b/blob/fw_payload.elf.ldS
new file mode 100644
index 0000000..2196e9c
--- /dev/null
+++ b/blob/fw_payload.elf.ldS
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+ #include "fw_common.ldS"
+
+ . = ALIGN(0x200000);
+
+ .payload :
+ {
+ PROVIDE(_payload_start = .);
+ *(.payload)
+ . = ALIGN(8);
+ PROVIDE(_payload_end = .);
+ }
+}
diff --git a/blob/objects.mk b/blob/objects.mk
new file mode 100644
index 0000000..7376213
--- /dev/null
+++ b/blob/objects.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+blob-cppflags-y =
+blob-cflags-y =
+blob-asflags-y =
+blob-ldflags-y =
+
+blob-bins-$(FW_JUMP) += fw_jump.bin
+ifdef FW_JUMP_ADDR
+blob-cppflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
+endif
+ifdef FW_JUMP_FDT_OFFSET
+blob-cppflags-$(FW_JUMP) += -DFW_JUMP_FDT_OFFSET=$(FW_JUMP_FDT_OFFSET)
+endif
+
+blob-bins-$(FW_PAYLOAD) += fw_payload.bin
+ifdef FW_PAYLOAD_PATH
+blob-cppflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=$(FW_PAYLOAD_PATH)
+endif
+ifdef FW_PAYLOAD_FDT_OFFSET
+blob-cppflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_OFFSET=$(FW_PAYLOAD_FDT_OFFSET)
+endif
diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
new file mode 100644
index 0000000..516bf6f
--- /dev/null
+++ b/include/sbi/riscv_asm.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ASM_H__
+#define __RISCV_ASM_H__
+
+#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 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
+
+#define RISCV_SCRATCH_TMP0_OFFSET (0 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_START_OFFSET (1 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_SIZE_OFFSET (2 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_IPI_TYPE_OFFSET (9 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_SIZE 256
+
+#define RISCV_TRAP_REGS_zero 0
+#define RISCV_TRAP_REGS_ra 1
+#define RISCV_TRAP_REGS_sp 2
+#define RISCV_TRAP_REGS_gp 3
+#define RISCV_TRAP_REGS_tp 4
+#define RISCV_TRAP_REGS_t0 5
+#define RISCV_TRAP_REGS_t1 6
+#define RISCV_TRAP_REGS_t2 7
+#define RISCV_TRAP_REGS_s0 8
+#define RISCV_TRAP_REGS_s1 9
+#define RISCV_TRAP_REGS_a0 10
+#define RISCV_TRAP_REGS_a1 11
+#define RISCV_TRAP_REGS_a2 12
+#define RISCV_TRAP_REGS_a3 13
+#define RISCV_TRAP_REGS_a4 14
+#define RISCV_TRAP_REGS_a5 15
+#define RISCV_TRAP_REGS_a6 16
+#define RISCV_TRAP_REGS_a7 17
+#define RISCV_TRAP_REGS_s2 18
+#define RISCV_TRAP_REGS_s3 19
+#define RISCV_TRAP_REGS_s4 20
+#define RISCV_TRAP_REGS_s5 21
+#define RISCV_TRAP_REGS_s6 22
+#define RISCV_TRAP_REGS_s7 23
+#define RISCV_TRAP_REGS_s8 24
+#define RISCV_TRAP_REGS_s9 25
+#define RISCV_TRAP_REGS_s10 26
+#define RISCV_TRAP_REGS_s11 27
+#define RISCV_TRAP_REGS_t3 28
+#define RISCV_TRAP_REGS_t4 29
+#define RISCV_TRAP_REGS_t5 30
+#define RISCV_TRAP_REGS_t6 31
+#define RISCV_TRAP_REGS_mepc 32
+#define RISCV_TRAP_REGS_mstatus 33
+#define RISCV_TRAP_REGS_last 34
+
+#define RISCV_TRAP_REGS_OFFSET(x) \
+ ((RISCV_TRAP_REGS_##x) * __SIZEOF_POINTER__)
+#define RISCV_TRAP_REGS_SIZE RISCV_TRAP_REGS_OFFSET(last)
+
+#ifndef __ASSEMBLY__
+
+#define csr_swap(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_read(csr) \
+({ \
+ register unsigned long __v; \
+ __asm__ __volatile__ ("csrr %0, " #csr \
+ : "=r" (__v) : \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_read_n(csr_num) \
+({ \
+ register unsigned long __v; \
+ __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr_num) \
+ : "=r" (__v) : \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_write(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrw " #csr ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_write_n(csr_num, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrw " __ASM_STR(csr_num) ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_read_set(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_set(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrs " #csr ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_read_clear(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_clear(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrc " #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)
+
+static inline int misa_extension(char ext)
+{
+ return csr_read(misa) & (1 << (ext - 'A'));
+}
+
+static inline int misa_xlen(void)
+{
+ return ((long)csr_read(misa) < 0) ? 64 : 32;
+}
+
+static inline void misa_string(char *out, unsigned int out_sz)
+{
+ unsigned long i, val = csr_read(misa);
+
+ for (i = 0; i < 26; i++) {
+ if (val & (1 << i)) {
+ *out = 'A' + i;
+ out++;
+ }
+ }
+ *out = '\0';
+ out++;
+}
+
+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_out);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/include/sbi/riscv_atomic.h b/include/sbi/riscv_atomic.h
new file mode 100644
index 0000000..775cd6f
--- /dev/null
+++ b/include/sbi/riscv_atomic.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#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 arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
+
+long arch_atomic_xchg(atomic_t *atom, long newval);
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+ unsigned int newval);
+
+#endif
diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h
new file mode 100644
index 0000000..993cbda
--- /dev/null
+++ b/include/sbi/riscv_barrier.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_BARRIER_H__
+#define __RISCV_BARRIER_H__
+
+#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")
+
+#define __smp_store_release(p, v) \
+do { \
+ RISCV_FENCE(rw,w); \
+ *(p) = (v); \
+} while (0)
+
+#define __smp_load_acquire(p) \
+({ \
+ typeof(*p) ___p1 = *(p); \
+ RISCV_FENCE(r,rw); \
+ ___p1; \
+})
+
+#endif
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
new file mode 100644
index 0000000..a4407d2
--- /dev/null
+++ b/include/sbi/riscv_encoding.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ENCODING_H__
+#define __RISCV_ENCODING_H__
+
+#include <sbi/sbi_const.h>
+
+/* TODO: Make constants usable in assembly with _AC() macro */
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_SUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_TVM 0x00100000
+#define MSTATUS_TW 0x00200000
+#define MSTATUS_TSR 0x00400000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS_UXL 0x0000000300000000
+#define MSTATUS_SXL 0x0000000C00000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000
+#define SSTATUS_MXR 0x00080000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS_UXL 0x0000000300000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define SATP32_MODE 0x80000000
+#define SATP32_ASID 0x7FC00000
+#define SATP32_PPN 0x003FFFFF
+#define SATP64_MODE 0xF000000000000000
+#define SATP64_ASID 0x0FFFF00000000000
+#define SATP64_PPN 0x00000FFFFFFFFFFF
+
+#define SATP_MODE_OFF 0
+#define SATP_MODE_SV32 1
+#define SATP_MODE_SV39 8
+#define SATP_MODE_SV48 9
+#define SATP_MODE_SV57 10
+#define SATP_MODE_SV64 11
+
+#define PMP_R 0x01
+#define PMP_W 0x02
+#define PMP_X 0x04
+#define PMP_A 0x18
+#define PMP_A_TOR 0x08
+#define PMP_A_NA4 0x10
+#define PMP_A_NAPOT 0x18
+#define PMP_L 0x80
+
+#define PMP_SHIFT 2
+#define PMP_COUNT 16
+
+/* page table entry (PTE) fields */
+#define PTE_V 0x001 /* Valid */
+#define PTE_R 0x002 /* Read */
+#define PTE_W 0x004 /* Write */
+#define PTE_X 0x008 /* Execute */
+#define PTE_U 0x010 /* User */
+#define PTE_G 0x020 /* Global */
+#define PTE_A 0x040 /* Accessed */
+#define PTE_D 0x080 /* Dirty */
+#define PTE_SOFT 0x300 /* Reserved for Software */
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) \
+ (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#if __riscv_xlen == 64
+#define MSTATUS_SD MSTATUS64_SD
+#define SSTATUS_SD SSTATUS64_SD
+#define RISCV_PGLEVEL_BITS 9
+#define SATP_MODE SATP64_MODE
+#else
+#define MSTATUS_SD MSTATUS32_SD
+#define SSTATUS_SD SSTATUS32_SD
+#define RISCV_PGLEVEL_BITS 10
+#define SATP_MODE SATP32_MODE
+#endif
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#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_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SCOUNTEREN 0x106
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_STVAL 0x143
+#define CSR_SIP 0x144
+#define CSR_SATP 0x180
+#define CSR_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_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MTVAL 0x343
+#define CSR_MIP 0x344
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPCFG1 0x3a1
+#define CSR_PMPCFG2 0x3a2
+#define CSR_PMPCFG3 0x3a3
+#define CSR_PMPADDR0 0x3b0
+#define CSR_PMPADDR1 0x3b1
+#define CSR_PMPADDR2 0x3b2
+#define CSR_PMPADDR3 0x3b3
+#define CSR_PMPADDR4 0x3b4
+#define CSR_PMPADDR5 0x3b5
+#define CSR_PMPADDR6 0x3b6
+#define CSR_PMPADDR7 0x3b7
+#define CSR_PMPADDR8 0x3b8
+#define CSR_PMPADDR9 0x3b9
+#define CSR_PMPADDR10 0x3ba
+#define CSR_PMPADDR11 0x3bb
+#define CSR_PMPADDR12 0x3bc
+#define CSR_PMPADDR13 0x3bd
+#define CSR_PMPADDR14 0x3be
+#define CSR_PMPADDR15 0x3bf
+#define CSR_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#define CSR_MCYCLE 0xb00
+#define CSR_MINSTRET 0xb02
+#define CSR_MHPMCOUNTER3 0xb03
+#define CSR_MHPMCOUNTER4 0xb04
+#define CSR_MHPMCOUNTER5 0xb05
+#define CSR_MHPMCOUNTER6 0xb06
+#define CSR_MHPMCOUNTER7 0xb07
+#define CSR_MHPMCOUNTER8 0xb08
+#define CSR_MHPMCOUNTER9 0xb09
+#define CSR_MHPMCOUNTER10 0xb0a
+#define CSR_MHPMCOUNTER11 0xb0b
+#define CSR_MHPMCOUNTER12 0xb0c
+#define CSR_MHPMCOUNTER13 0xb0d
+#define CSR_MHPMCOUNTER14 0xb0e
+#define CSR_MHPMCOUNTER15 0xb0f
+#define CSR_MHPMCOUNTER16 0xb10
+#define CSR_MHPMCOUNTER17 0xb11
+#define CSR_MHPMCOUNTER18 0xb12
+#define CSR_MHPMCOUNTER19 0xb13
+#define CSR_MHPMCOUNTER20 0xb14
+#define CSR_MHPMCOUNTER21 0xb15
+#define CSR_MHPMCOUNTER22 0xb16
+#define CSR_MHPMCOUNTER23 0xb17
+#define CSR_MHPMCOUNTER24 0xb18
+#define CSR_MHPMCOUNTER25 0xb19
+#define CSR_MHPMCOUNTER26 0xb1a
+#define CSR_MHPMCOUNTER27 0xb1b
+#define CSR_MHPMCOUNTER28 0xb1c
+#define CSR_MHPMCOUNTER29 0xb1d
+#define CSR_MHPMCOUNTER30 0xb1e
+#define CSR_MHPMCOUNTER31 0xb1f
+#define CSR_MHPMEVENT3 0x323
+#define CSR_MHPMEVENT4 0x324
+#define CSR_MHPMEVENT5 0x325
+#define CSR_MHPMEVENT6 0x326
+#define CSR_MHPMEVENT7 0x327
+#define CSR_MHPMEVENT8 0x328
+#define CSR_MHPMEVENT9 0x329
+#define CSR_MHPMEVENT10 0x32a
+#define CSR_MHPMEVENT11 0x32b
+#define CSR_MHPMEVENT12 0x32c
+#define CSR_MHPMEVENT13 0x32d
+#define CSR_MHPMEVENT14 0x32e
+#define CSR_MHPMEVENT15 0x32f
+#define CSR_MHPMEVENT16 0x330
+#define CSR_MHPMEVENT17 0x331
+#define CSR_MHPMEVENT18 0x332
+#define CSR_MHPMEVENT19 0x333
+#define CSR_MHPMEVENT20 0x334
+#define CSR_MHPMEVENT21 0x335
+#define CSR_MHPMEVENT22 0x336
+#define CSR_MHPMEVENT23 0x337
+#define CSR_MHPMEVENT24 0x338
+#define CSR_MHPMEVENT25 0x339
+#define CSR_MHPMEVENT26 0x33a
+#define CSR_MHPMEVENT27 0x33b
+#define CSR_MHPMEVENT28 0x33c
+#define CSR_MHPMEVENT29 0x33d
+#define CSR_MHPMEVENT30 0x33e
+#define CSR_MHPMEVENT31 0x33f
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#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
+#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
+
+#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_HYPERVISOR_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
+
+#endif
diff --git a/include/sbi/riscv_io.h b/include/sbi/riscv_io.h
new file mode 100644
index 0000000..08f1a2f
--- /dev/null
+++ b/include/sbi/riscv_io.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#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 */
+#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
+
+#endif
diff --git a/include/sbi/riscv_locks.h b/include/sbi/riscv_locks.h
new file mode 100644
index 0000000..4a683d9
--- /dev/null
+++ b/include/sbi/riscv_locks.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_LOCKS_H__
+#define __RISCV_LOCKS_H__
+
+typedef struct {
+ volatile long lock;
+} spinlock_t;
+
+#define __RISCV_SPIN_UNLOCKED 0
+
+#define SPIN_LOCK_INIT(_lptr) \
+ (_lptr)->lock = __RISCV_SPIN_UNLOCKED
+
+#define SPIN_LOCK_INITIALIZER \
+ { .lock = __RISCV_SPIN_UNLOCKED, }
+
+int spin_lock_check(spinlock_t *lock);
+
+int spin_trylock(spinlock_t *lock);
+
+void spin_lock(spinlock_t *lock);
+
+void spin_unlock(spinlock_t *lock);
+
+#endif
diff --git a/include/sbi/sbi_bits.h b/include/sbi/sbi_bits.h
new file mode 100644
index 0000000..118fab2
--- /dev/null
+++ b/include/sbi/sbi_bits.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_BITS_H__
+#define __SBI_BITS_H__
+
+#define likely(x) __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+
+#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
+#define ROUNDDOWN(a, b) ((a)/(b)*(b))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
+
+#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
+#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#if __riscv_xlen == 64
+#define SLL32 sllw
+#define STORE sd
+#define LOAD ld
+#define LWU lwu
+#define LOG_REGBYTES 3
+#else
+#define SLL32 sll
+#define STORE sw
+#define LOAD lw
+#define LWU lw
+#define LOG_REGBYTES 2
+#endif
+#define REGBYTES (1 << LOG_REGBYTES)
+
+#endif
diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h
new file mode 100644
index 0000000..df258ba
--- /dev/null
+++ b/include/sbi/sbi_console.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#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);
+
+char 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, ...);
+
+struct sbi_scratch;
+int sbi_console_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_const.h b/include/sbi/sbi_const.h
new file mode 100644
index 0000000..3071094
--- /dev/null
+++ b/include/sbi/sbi_const.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#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.
+ */
+
+#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)
+
+#endif
diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
new file mode 100644
index 0000000..4f39329
--- /dev/null
+++ b/include/sbi/sbi_ecall.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ECALL_H__
+#define __SBI_ECALL_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+u16 sbi_ecall_version_major(void);
+
+u16 sbi_ecall_version_minor(void);
+
+int sbi_ecall_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_emulate_csr.h b/include/sbi/sbi_emulate_csr.h
new file mode 100644
index 0000000..c6fe419
--- /dev/null
+++ b/include/sbi/sbi_emulate_csr.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_EMULATE_CSR_H__
+#define __SBI_EMULATE_CSR_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_emulate_csr_read(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong *csr_val);
+
+int sbi_emulate_csr_write(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong csr_val);
+
+#endif
diff --git a/include/sbi/sbi_error.h b/include/sbi/sbi_error.h
new file mode 100644
index 0000000..955674e
--- /dev/null
+++ b/include/sbi/sbi_error.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ERROR_H__
+#define __SBI_ERROR_H__
+
+#define SBI_OK 0
+#define SBI_EUNKNOWN -1
+#define SBI_EFAIL -2
+#define SBI_EINVAL -3
+#define SBI_ENOENT -4
+#define SBI_ENOTSUPP -5
+#define SBI_ENODEV -6
+#define SBI_ENOSYS -7
+#define SBI_ETIMEDOUT -8
+#define SBI_EIO -9
+#define SBI_EILL -10
+
+#endif
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
new file mode 100644
index 0000000..38032ed
--- /dev/null
+++ b/include/sbi/sbi_hart.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_HART_H__
+#define __SBI_HART_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_pmp_dump(void);
+
+void __attribute__((noreturn)) sbi_hart_hang(void);
+
+void __attribute__((noreturn)) sbi_hart_boot_next(unsigned long arg0,
+ unsigned long arg1,
+ unsigned long next_addr,
+ unsigned long next_mode);
+
+void sbi_hart_mark_available(u32 hartid);
+
+ulong sbi_hart_available_mask(void);
+
+void sbi_hart_unmark_available(u32 hartid);
+
+struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
+ u32 hartid);
+
+void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_illegal_insn.h b/include/sbi/sbi_illegal_insn.h
new file mode 100644
index 0000000..1b8837f
--- /dev/null
+++ b/include/sbi/sbi_illegal_insn.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ILLEGAl_INSN_H__
+#define __SBI_ILLEGAl_INSN_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_init.h b/include/sbi/sbi_init.h
new file mode 100644
index 0000000..b3aafdc
--- /dev/null
+++ b/include/sbi/sbi_init.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_INIT_H__
+#define __SBI_INIT_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+void __attribute__((noreturn)) sbi_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
new file mode 100644
index 0000000..4058194
--- /dev/null
+++ b/include/sbi/sbi_ipi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_IPI_H__
+#define __SBI_IPI_H__
+
+#include <sbi/sbi_types.h>
+
+#define SBI_IPI_EVENT_SOFT 0x1
+#define SBI_IPI_EVENT_FENCE_I 0x2
+#define SBI_IPI_EVENT_SFENCE_VMA 0x4
+#define SBI_IPI_EVENT_HALT 0x8
+
+struct sbi_scratch;
+
+int sbi_ipi_send_many(struct sbi_scratch *scratch,
+ u32 hartid, ulong *pmask, u32 event);
+
+void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
new file mode 100644
index 0000000..57b8e6b
--- /dev/null
+++ b/include/sbi/sbi_platform.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_PLATFORM_H__
+#define __SBI_PLATFORM_H__
+
+#include <sbi/sbi_scratch.h>
+
+enum sbi_platform_features {
+ SBI_PLATFORM_HAS_MMIO_TIMER_VALUE = (1 << 0),
+ SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
+};
+
+struct sbi_platform {
+ char name[64];
+ u64 features;
+ u32 hart_count;
+ u32 hart_stack_size;
+ int (*cold_early_init)(void);
+ int (*cold_final_init)(void);
+ int (*warm_early_init)(u32 target_hart);
+ int (*warm_final_init)(u32 target_hart);
+ u32 (*pmp_region_count)(u32 target_hart);
+ int (*pmp_region_info)(u32 target_hart, u32 index,
+ ulong *prot, ulong *addr, ulong *log2size);
+ void (*console_putc)(char ch);
+ char (*console_getc)(void);
+ int (*console_init)(void);
+ int (*cold_irqchip_init)(void);
+ int (*warm_irqchip_init)(u32 target_hart);
+ void (*ipi_inject)(u32 target_hart, u32 source_hart);
+ void (*ipi_sync)(u32 target_hart, u32 source_hart);
+ void (*ipi_clear)(u32 target_hart);
+ int (*cold_ipi_init)(void);
+ int (*warm_ipi_init)(u32 target_hart);
+ u64 (*timer_value)(void);
+ void (*timer_event_stop)(u32 target_hart);
+ void (*timer_event_start)(u32 target_hart, u64 next_event);
+ int (*cold_timer_init)(void);
+ int (*warm_timer_init)(u32 target_hart);
+ int (*system_reboot)(u32 type);
+ int (*system_shutdown)(u32 type);
+} __attribute__((packed));
+
+#define sbi_platform_ptr(__s) \
+((struct sbi_platform *)((__s)->platform_addr))
+
+#define sbi_platform_thishart_ptr() \
+((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr))
+
+#define sbi_platform_has_mmio_timer_value(__p) \
+((__p)->features & SBI_PLATFORM_HAS_MMIO_TIMER_VALUE)
+
+#define sbi_platform_has_hart_hotplug(__p) \
+((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
+
+static inline const char *sbi_platform_name(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->name;
+ return NULL;
+}
+
+static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_count;
+ return 0;
+}
+
+static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_stack_size;
+ return 0;
+}
+
+static inline int sbi_platform_cold_early_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_early_init)
+ return plat->cold_early_init();
+ return 0;
+}
+
+static inline int sbi_platform_cold_final_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_final_init)
+ return plat->cold_final_init();
+ return 0;
+}
+
+static inline int sbi_platform_warm_early_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_early_init)
+ return plat->warm_early_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_warm_final_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_final_init)
+ return plat->warm_final_init(target_hart);
+ return 0;
+}
+
+static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->pmp_region_count)
+ return plat->pmp_region_count(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
+ u32 target_hart, u32 index,
+ ulong *prot, ulong *addr,
+ ulong *log2size)
+{
+ if (plat && plat->pmp_region_info)
+ return plat->pmp_region_info(target_hart, index,
+ prot, addr, log2size);
+ return 0;
+}
+
+static inline void sbi_platform_console_putc(struct sbi_platform *plat,
+ char ch)
+{
+ if (plat && plat->console_putc)
+ plat->console_putc(ch);
+}
+
+static inline char sbi_platform_console_getc(struct sbi_platform *plat)
+{
+ if (plat && plat->console_getc)
+ return plat->console_getc();
+ return 0;
+}
+
+static inline int sbi_platform_console_init(struct sbi_platform *plat)
+{
+ if (plat && plat->console_init)
+ return plat->console_init();
+ return 0;
+}
+
+static inline int sbi_platform_warm_irqchip_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_irqchip_init)
+ return plat->warm_irqchip_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_irqchip_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_irqchip_init)
+ return plat->cold_irqchip_init();
+ return 0;
+}
+
+static inline void sbi_platform_ipi_inject(struct sbi_platform *plat,
+ u32 target_hart, u32 source_hart)
+{
+ if (plat && plat->ipi_inject)
+ plat->ipi_inject(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
+ u32 target_hart, u32 source_hart)
+{
+ if (plat && plat->ipi_sync)
+ plat->ipi_sync(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->ipi_clear)
+ plat->ipi_clear(target_hart);
+}
+
+static inline int sbi_platform_warm_ipi_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_ipi_init)
+ return plat->warm_ipi_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_ipi_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_ipi_init)
+ return plat->cold_ipi_init();
+ return 0;
+}
+
+static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
+{
+ if (plat && plat->timer_value)
+ return plat->timer_value();
+ return 0;
+}
+
+static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->timer_event_stop)
+ plat->timer_event_stop(target_hart);
+}
+
+static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
+ u32 target_hart,
+ u64 next_event)
+{
+ if (plat && plat->timer_event_start)
+ plat->timer_event_start(target_hart, next_event);
+}
+
+static inline int sbi_platform_warm_timer_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_timer_init)
+ return plat->warm_timer_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_timer_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_timer_init)
+ return plat->cold_timer_init();
+ return 0;
+}
+
+static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
+ u32 type)
+{
+ if (plat && plat->system_reboot)
+ return plat->system_reboot(type);
+ return 0;
+}
+
+static inline int sbi_platform_system_shutdown(struct sbi_platform *plat,
+ u32 type)
+{
+ if (plat && plat->system_shutdown)
+ return plat->system_shutdown(type);
+ return 0;
+}
+
+#endif
diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
new file mode 100644
index 0000000..d5c6f35
--- /dev/null
+++ b/include/sbi/sbi_scratch.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SCRATCH_H__
+#define __SBI_SCRATCH_H__
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch {
+ unsigned long tmp0;
+ unsigned long fw_start;
+ unsigned long fw_size;
+ unsigned long next_arg1;
+ unsigned long next_addr;
+ unsigned long next_mode;
+ unsigned long warmboot_addr;
+ unsigned long platform_addr;
+ unsigned long hartid_to_scratch;
+ unsigned long ipi_type;
+} __attribute__((packed));
+
+#define sbi_scratch_thishart_ptr() \
+((struct sbi_scratch *)csr_read(mscratch))
+
+#define sbi_scratch_thishart_arg1_ptr() \
+((void *)(sbi_scratch_thishart_ptr()->next_arg1))
+
+#endif
diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h
new file mode 100644
index 0000000..ac1fb36
--- /dev/null
+++ b/include/sbi/sbi_system.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SYSTEM_H__
+#define __SBI_SYSTEM_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_system_warm_early_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_warm_final_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_cold_early_init(struct sbi_scratch *scratch);
+
+int sbi_system_cold_final_init(struct sbi_scratch *scratch);
+
+void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
+ u32 type);
+
+void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
+ u32 type);
+
+#endif
diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
new file mode 100644
index 0000000..914e9c0
--- /dev/null
+++ b/include/sbi/sbi_timer.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TIMER_H__
+#define __SBI_TIMER_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+u64 sbi_timer_value(struct sbi_scratch *scratch);
+
+void sbi_timer_event_stop(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_timer_event_start(struct sbi_scratch *scratch, u32 hartid,
+ u64 next_event);
+
+void sbi_timer_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_trap.h b/include/sbi/sbi_trap.h
new file mode 100644
index 0000000..a6b22e4
--- /dev/null
+++ b/include/sbi/sbi_trap.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TRAP_H__
+#define __SBI_TRAP_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs {
+ unsigned long zero;
+ unsigned long ra;
+ unsigned long sp;
+ unsigned long gp;
+ unsigned long tp;
+ unsigned long t0;
+ unsigned long t1;
+ unsigned long t2;
+ unsigned long s0;
+ unsigned long s1;
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+ unsigned long a4;
+ unsigned long a5;
+ unsigned long a6;
+ unsigned long a7;
+ unsigned long s2;
+ unsigned long s3;
+ unsigned long s4;
+ unsigned long s5;
+ unsigned long s6;
+ unsigned long s7;
+ unsigned long s8;
+ unsigned long s9;
+ unsigned long s10;
+ unsigned long s11;
+ unsigned long t3;
+ unsigned long t4;
+ unsigned long t5;
+ unsigned long t6;
+ unsigned long mepc;
+ unsigned long mstatus;
+} __attribute__((packed));
+
+struct sbi_scratch;
+
+void sbi_trap_handler(struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h
new file mode 100644
index 0000000..ddcdea2
--- /dev/null
+++ b/include/sbi/sbi_types.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TYPES_H__
+#define __SBI_TYPES_H__
+
+typedef char s8;
+typedef unsigned char u8;
+typedef char int8_t;
+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;
+#elif __riscv_xlen == 32
+typedef long long s64;
+typedef unsigned long long u64;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#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 NULL ((void *)0)
+
+#endif
diff --git a/include/sbi/sbi_unpriv.h b/include/sbi/sbi_unpriv.h
new file mode 100644
index 0000000..2b925c5
--- /dev/null
+++ b/include/sbi/sbi_unpriv.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_UNPRIV_H__
+#define __SBI_UNPRIV_H__
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_types.h>
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
+static inline type load_##type(const type *addr, ulong mepc) \
+{ \
+ register ulong __mepc asm ("a2") = mepc; \
+ register ulong __mstatus asm ("a3"); \
+ type val; \
+ asm ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus), "=&r" (val) \
+ : "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
+ return val; \
+}
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
+static inline void store_##type(type *addr, type val, ulong mepc) \
+{ \
+ register ulong __mepc asm ("a2") = mepc; \
+ register ulong __mstatus asm ("a3"); \
+ asm volatile ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus) \
+ : "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
+}
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
+#if __riscv_xlen == 64
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
+#else
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
+
+static inline u64 load_u64(const u64 *addr, ulong mepc)
+{
+ return load_u32((u32 *)addr, mepc)
+ + ((u64)load_u32((u32 *)addr + 1, mepc) << 32);
+}
+
+static inline void store_u64(u64 *addr, u64 val, ulong mepc)
+{
+ store_u32((u32 *)addr, val, mepc);
+ store_u32((u32 *)addr + 1, val >> 32, mepc);
+}
+#endif
+
+static inline ulong get_insn(ulong mepc, ulong *mstatus)
+{
+ register ulong __mepc asm ("a2") = mepc;
+ register ulong __mstatus asm ("a3");
+ ulong val;
+#ifndef __riscv_compressed
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
+#else
+ ulong rvc_mask = 3, tmp;
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ "and %[tmp], %[addr], 2\n"
+ "bnez %[tmp], 1f\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "beq %[tmp], %[rvc_mask], 2f\n"
+ "sll %[insn], %[insn], %[xlen_minus_16]\n"
+ "srl %[insn], %[insn], %[xlen_minus_16]\n"
+ "j 2f\n"
+ "1:\n"
+ "lhu %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "bne %[tmp], %[rvc_mask], 2f\n"
+ "lhu %[tmp], 2(%[addr])\n"
+ "sll %[tmp], %[tmp], 16\n"
+ "add %[insn], %[insn], %[tmp]\n"
+ "2: csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
+ [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
+#endif
+ *mstatus = __mstatus;
+ return val;
+}
+
+#endif
diff --git a/lib/objects.mk b/lib/objects.mk
new file mode 100644
index 0000000..ed14677
--- /dev/null
+++ b/lib/objects.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+lib-objs-y += riscv_asm.o
+lib-objs-y += riscv_atomic.o
+lib-objs-y += riscv_locks.o
+
+lib-objs-y += sbi_console.o
+lib-objs-y += sbi_ecall.o
+lib-objs-y += sbi_emulate_csr.o
+lib-objs-y += sbi_hart.o
+lib-objs-y += sbi_illegal_insn.o
+lib-objs-y += sbi_init.o
+lib-objs-y += sbi_ipi.o
+lib-objs-y += sbi_system.o
+lib-objs-y += sbi_timer.o
+lib-objs-y += sbi_trap.o
diff --git a/lib/riscv_asm.c b/lib/riscv_asm.c
new file mode 100644
index 0000000..0fbdb31
--- /dev/null
+++ b/lib/riscv_asm.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_error.h>
+
+unsigned long csr_read_num(int csr_num)
+{
+ unsigned long ret = 0;
+
+ switch (csr_num) {
+ case CSR_PMPCFG0:
+ ret = csr_read_n(CSR_PMPCFG0);
+ break;
+ case CSR_PMPCFG1:
+ ret = csr_read_n(CSR_PMPCFG1);
+ break;
+ case CSR_PMPCFG2:
+ ret = csr_read_n(CSR_PMPCFG2);
+ break;
+ case CSR_PMPCFG3:
+ ret = csr_read_n(CSR_PMPCFG3);
+ break;
+ case CSR_PMPADDR0:
+ ret = csr_read_n(CSR_PMPADDR0);
+ break;
+ case CSR_PMPADDR1:
+ ret = csr_read_n(CSR_PMPADDR1);
+ break;
+ case CSR_PMPADDR2:
+ ret = csr_read_n(CSR_PMPADDR2);
+ break;
+ case CSR_PMPADDR3:
+ ret = csr_read_n(CSR_PMPADDR3);
+ break;
+ case CSR_PMPADDR4:
+ ret = csr_read_n(CSR_PMPADDR4);
+ break;
+ case CSR_PMPADDR5:
+ ret = csr_read_n(CSR_PMPADDR5);
+ break;
+ case CSR_PMPADDR6:
+ ret = csr_read_n(CSR_PMPADDR6);
+ break;
+ case CSR_PMPADDR7:
+ ret = csr_read_n(CSR_PMPADDR7);
+ break;
+ case CSR_PMPADDR8:
+ ret = csr_read_n(CSR_PMPADDR8);
+ break;
+ case CSR_PMPADDR9:
+ ret = csr_read_n(CSR_PMPADDR9);
+ break;
+ case CSR_PMPADDR10:
+ ret = csr_read_n(CSR_PMPADDR10);
+ break;
+ case CSR_PMPADDR11:
+ ret = csr_read_n(CSR_PMPADDR11);
+ break;
+ case CSR_PMPADDR12:
+ ret = csr_read_n(CSR_PMPADDR12);
+ break;
+ case CSR_PMPADDR13:
+ ret = csr_read_n(CSR_PMPADDR13);
+ break;
+ case CSR_PMPADDR14:
+ ret = csr_read_n(CSR_PMPADDR14);
+ break;
+ case CSR_PMPADDR15:
+ ret = csr_read_n(CSR_PMPADDR15);
+ break;
+ default:
+ break;
+ };
+
+ return ret;
+}
+
+void csr_write_num(int csr_num, unsigned long val)
+{
+ switch (csr_num) {
+ case CSR_PMPCFG0:
+ csr_write_n(CSR_PMPCFG0, val);
+ break;
+ case CSR_PMPCFG1:
+ csr_write_n(CSR_PMPCFG1, val);
+ break;
+ case CSR_PMPCFG2:
+ csr_write_n(CSR_PMPCFG2, val);
+ break;
+ case CSR_PMPCFG3:
+ csr_write_n(CSR_PMPCFG3, val);
+ break;
+ case CSR_PMPADDR0:
+ csr_write_n(CSR_PMPADDR0, val);
+ break;
+ case CSR_PMPADDR1:
+ csr_write_n(CSR_PMPADDR1, val);
+ break;
+ case CSR_PMPADDR2:
+ csr_write_n(CSR_PMPADDR2, val);
+ break;
+ case CSR_PMPADDR3:
+ csr_write_n(CSR_PMPADDR3, val);
+ break;
+ case CSR_PMPADDR4:
+ csr_write_n(CSR_PMPADDR4, val);
+ break;
+ case CSR_PMPADDR5:
+ csr_write_n(CSR_PMPADDR5, val);
+ break;
+ case CSR_PMPADDR6:
+ csr_write_n(CSR_PMPADDR6, val);
+ break;
+ case CSR_PMPADDR7:
+ csr_write_n(CSR_PMPADDR7, val);
+ break;
+ case CSR_PMPADDR8:
+ csr_write_n(CSR_PMPADDR8, val);
+ break;
+ case CSR_PMPADDR9:
+ csr_write_n(CSR_PMPADDR9, val);
+ break;
+ case CSR_PMPADDR10:
+ csr_write_n(CSR_PMPADDR10, val);
+ break;
+ case CSR_PMPADDR11:
+ csr_write_n(CSR_PMPADDR11, val);
+ break;
+ case CSR_PMPADDR12:
+ csr_write_n(CSR_PMPADDR12, val);
+ break;
+ case CSR_PMPADDR13:
+ csr_write_n(CSR_PMPADDR13, val);
+ break;
+ case CSR_PMPADDR14:
+ csr_write_n(CSR_PMPADDR14, val);
+ break;
+ case CSR_PMPADDR15:
+ csr_write_n(CSR_PMPADDR15, val);
+ break;
+ default:
+ break;
+ };
+}
+
+static unsigned long ctz(unsigned long x)
+{
+ unsigned long ret = 0;
+
+ while (!(x & 1UL)) {
+ ret++;
+ x = x >> 1;
+ }
+
+ return ret;
+}
+
+int pmp_set(unsigned int n, unsigned long prot,
+ unsigned long addr, unsigned long log2len)
+{
+ int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+ unsigned long cfgmask, pmpcfg;
+ unsigned long addrmask, pmpaddr;
+
+ /* check parameters */
+ if (n >= PMP_COUNT ||
+ log2len > __riscv_xlen ||
+ log2len < PMP_SHIFT)
+ return SBI_EINVAL;
+
+ /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+ pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+ pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+ pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+ pmpcfg_shift = (n & 7) << 3;
+#else
+ pmpcfg_csr = -1;
+ pmpcfg_shift = -1;
+#endif
+ pmpaddr_csr = CSR_PMPADDR0 + n;
+ if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+ return SBI_ENOTSUPP;
+
+ /* encode PMP config */
+ prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
+ cfgmask = ~(0xff << pmpcfg_shift);
+ pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
+ pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
+
+ /* encode PMP address */
+ if (log2len == PMP_SHIFT) {
+ pmpaddr = (addr >> PMP_SHIFT);
+ } else {
+ if (log2len == __riscv_xlen) {
+ pmpaddr = -1UL;
+ } else {
+ addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
+ pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
+ pmpaddr |= (addrmask >> 1);
+ }
+ }
+
+ /* write csrs */
+ csr_write_num(pmpaddr_csr, pmpaddr);
+ csr_write_num(pmpcfg_csr, pmpcfg);
+
+ return 0;
+}
+
+int pmp_get(unsigned int n, unsigned long *prot_out,
+ unsigned long *addr_out, unsigned long *log2len_out)
+{
+ int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+ unsigned long cfgmask, pmpcfg, prot;
+ unsigned long t1, addr, log2len;
+
+ /* check parameters */
+ if (n >= PMP_COUNT || !prot_out ||
+ !addr_out || !log2len_out)
+ return SBI_EINVAL;
+ *prot_out = *addr_out = *log2len_out = 0;
+
+ /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+ pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+ pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+ pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+ pmpcfg_shift = (n & 7) << 3;
+#else
+ pmpcfg_csr = -1;
+ pmpcfg_shift = -1;
+#endif
+ pmpaddr_csr = CSR_PMPADDR0 + n;
+ if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+ return SBI_ENOTSUPP;
+
+ /* decode PMP config */
+ cfgmask = (0xff << pmpcfg_shift);
+ pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
+ prot = pmpcfg >> pmpcfg_shift;
+
+ /* decode PMP address */
+ if ((prot & PMP_A) == PMP_A_NAPOT) {
+ addr = csr_read_num(pmpaddr_csr);
+ if (addr == -1UL) {
+ addr = 0;
+ log2len = __riscv_xlen;
+ } else {
+ t1 = ctz(~addr);
+ addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
+ log2len = (t1 + PMP_SHIFT + 1);
+ }
+ } else {
+ addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
+ log2len = PMP_SHIFT;
+ }
+
+ /* return details */
+ *prot_out = prot;
+ *addr_out = addr;
+ *log2len_out = log2len;
+
+ return 0;
+}
diff --git a/lib/riscv_atomic.c b/lib/riscv_atomic.c
new file mode 100644
index 0000000..3a599f5
--- /dev/null
+++ b/lib/riscv_atomic.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_types.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_barrier.h>
+
+long atomic_read(atomic_t *atom)
+{
+ long ret = atom->counter;
+ rmb();
+ return ret;
+}
+
+void atomic_write(atomic_t *atom, long value)
+{
+ atom->counter = value;
+ wmb();
+}
+
+long atomic_add_return(atomic_t *atom, long value)
+{
+ long ret;
+
+ __asm__ __volatile__ (
+ " amoadd.w.aqrl %1, %2, %0"
+ : "+A" (atom->counter), "=r" (ret)
+ : "r" (value)
+ : "memory");
+
+ return ret + value;
+}
+
+long atomic_sub_return(atomic_t *atom, long value)
+{
+ long ret;
+
+ __asm__ __volatile__ (
+ " amoadd.w.aqrl %1, %2, %0"
+ : "+A" (atom->counter), "=r" (ret)
+ : "r" (-value)
+ : "memory");
+
+ return ret - value;
+}
+
+#define __xchg(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ "0: lr.w %0, %2\n" \
+ " sc.w.rl %1, %z3, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ "0: lr.d %0, %2\n" \
+ " sc.d.rl %1, %z3, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ break; \
+ } \
+ __ret; \
+})
+
+#define xchg(ptr, n) \
+({ \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr))); \
+})
+
+#define __cmpxchg(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ break; \
+ } \
+ __ret; \
+})
+
+#define cmpxchg(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
+})
+
+long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
+{
+ return cmpxchg(&atom->counter, oldval, newval);
+}
+
+long arch_atomic_xchg(atomic_t *atom, long newval)
+{
+ return xchg(&atom->counter, newval);
+}
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+ unsigned int newval)
+{
+ return xchg(ptr, newval);
+}
diff --git a/lib/riscv_locks.c b/lib/riscv_locks.c
new file mode 100644
index 0000000..0f94986
--- /dev/null
+++ b/lib/riscv_locks.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_locks.h>
+
+int spin_lock_check(spinlock_t *lock)
+{
+ return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+ int tmp = 1, busy;
+
+ __asm__ __volatile__ (
+ " amoswap.w %0, %2, %1\n"
+ RISCV_ACQUIRE_BARRIER
+ : "=r" (busy), "+A" (lock->lock)
+ : "r" (tmp)
+ : "memory");
+
+ return !busy;
+}
+
+void spin_lock(spinlock_t *lock)
+{
+ while (1) {
+ if (spin_lock_check(lock))
+ continue;
+
+ if (spin_trylock(lock))
+ break;
+ }
+}
+
+void spin_unlock(spinlock_t *lock)
+{
+ __smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
+}
diff --git a/lib/sbi_console.c b/lib/sbi_console.c
new file mode 100644
index 0000000..24b9d3c
--- /dev/null
+++ b/lib/sbi_console.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_console.h>
+
+static struct sbi_platform *console_plat = NULL;
+
+bool sbi_isprintable(char c)
+{
+ if (((31 < c) && (c < 127)) ||
+ (c == '\f') ||
+ (c == '\r') ||
+ (c == '\n') ||
+ (c == '\t')) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+char sbi_getc(void)
+{
+ return sbi_platform_console_getc(console_plat);
+}
+
+void sbi_putc(char ch)
+{
+ sbi_platform_console_putc(console_plat, ch);
+}
+
+void sbi_puts(const char *str)
+{
+ while (*str) {
+ sbi_putc(*str);
+ str++;
+ }
+}
+
+void sbi_gets(char *s, int maxwidth, char endchar)
+{
+ char *retval;
+ char ch;
+ retval = s;
+ ch = sbi_getc();
+ while (ch != endchar && maxwidth > 0) {
+ *retval = ch;
+ retval++;
+ maxwidth--;
+ if (maxwidth == 0)
+ break;
+ ch = sbi_getc();
+ }
+ *retval = '\0';
+ return;
+}
+
+#define PAD_RIGHT 1
+#define PAD_ZERO 2
+#define PAD_ALTERNATE 4
+#define PRINT_BUF_LEN 64
+
+#define va_start(v,l) __builtin_va_start((v),l)
+#define va_end __builtin_va_end
+#define va_arg __builtin_va_arg
+typedef __builtin_va_list va_list;
+
+static void printc(char **out, u32 *out_len, char ch)
+{
+ if (out) {
+ if (*out) {
+ if (out_len && (0 < *out_len)) {
+ **out = ch;
+ ++(*out);
+ (*out_len)--;
+ } else {
+ **out = ch;
+ ++(*out);
+ }
+ }
+ } else {
+ sbi_putc(ch);
+ }
+}
+
+static int prints(char **out, u32 *out_len, const char *string, int width, int flags)
+{
+ int pc = 0;
+ char padchar = ' ';
+
+ if (width > 0) {
+ int len = 0;
+ const char *ptr;
+ for (ptr = string; *ptr; ++ptr)
+ ++len;
+ if (len >= width)
+ width = 0;
+ else
+ width -= len;
+ if (flags & PAD_ZERO)
+ padchar = '0';
+ }
+ if (!(flags & PAD_RIGHT)) {
+ for (; width > 0; --width) {
+ printc(out, out_len, padchar);
+ ++pc;
+ }
+ }
+ for (; *string; ++string) {
+ printc(out, out_len, *string);
+ ++pc;
+ }
+ for (; width > 0; --width) {
+ printc(out, out_len, padchar);
+ ++pc;
+ }
+
+ return pc;
+}
+
+static int printi(char **out, u32 *out_len, long long i, int b, int sg,
+ int width, int flags, int letbase)
+{
+ char print_buf[PRINT_BUF_LEN];
+ char *s;
+ int neg = 0, pc = 0;
+ u64 t;
+ unsigned long long u = i;
+
+ if (sg && b == 10 && i < 0) {
+ neg = 1;
+ u = -i;
+ }
+
+ s = print_buf + PRINT_BUF_LEN - 1;
+ *s = '\0';
+
+ if (!u) {
+ *--s = '0';
+ } else {
+ while (u) {
+ t = u % b;
+ u = u / b;
+ if (t >= 10)
+ t += letbase - '0' - 10;
+ *--s = t + '0';
+ }
+ }
+
+ if (flags & PAD_ALTERNATE) {
+ if ((b == 16) && (letbase == 'A')) {
+ *--s = 'X';
+ } else if ((b == 16) && (letbase == 'a')) {
+ *--s = 'x';
+ }
+ *--s = '0';
+ }
+
+ if (neg) {
+ if (width && (flags & PAD_ZERO)) {
+ printc(out, out_len, '-');
+ ++pc;
+ --width;
+ } else {
+ *--s = '-';
+ }
+ }
+
+ return pc + prints(out, out_len, s, width, flags);
+}
+
+static int print(char **out, u32 *out_len, const char *format, va_list args)
+{
+ int width, flags, acnt = 0;
+ int pc = 0;
+ char scr[2];
+ unsigned long long tmp;
+
+ for (; *format != 0; ++format) {
+ if (*format == '%') {
+ ++format;
+ width = flags = 0;
+ if (*format == '\0')
+ break;
+ if (*format == '%')
+ goto out;
+ /* Get flags */
+ if (*format == '-') {
+ ++format;
+ flags = PAD_RIGHT;
+ }
+ if (*format == '#') {
+ ++format;
+ flags |= PAD_ALTERNATE;
+ }
+ while (*format == '0') {
+ ++format;
+ flags |= PAD_ZERO;
+ }
+ /* Get width */
+ for (; *format >= '0' && *format <= '9'; ++format) {
+ width *= 10;
+ width += *format - '0';
+ }
+ if (*format == 's') {
+ char *s = va_arg(args, char *);
+ acnt += sizeof(char *);
+ pc += prints(out, out_len,
+ s ? s : "(null)", width, flags);
+ continue;
+ }
+ if ((*format == 'd') || (*format == 'i')) {
+ pc += printi(out, out_len,
+ va_arg(args, int),
+ 10, 1, width, flags, '0');
+ acnt += sizeof(int);
+ continue;
+ }
+ if (*format == 'x') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int),
+ 16, 0, width, flags, 'a');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'X') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int),
+ 16, 0, width, flags, 'A');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'u') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned int),
+ 10, 0, width, flags, 'a');
+ acnt += sizeof(unsigned int);
+ continue;
+ }
+ if (*format == 'p') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long),
+ 16, 0, width, flags, 'a');
+ acnt += sizeof(unsigned long);
+ continue;
+ }
+ if (*format == 'P') {
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long),
+ 16, 0, width, flags, 'A');
+ acnt += sizeof(unsigned long);
+ continue;
+ }
+ if (*format == 'l' && *(format + 1) == 'l') {
+ while (acnt & (sizeof(unsigned long long)-1)) {
+ va_arg(args, int);
+ acnt += sizeof(int);
+ }
+ if (sizeof(unsigned long long) ==
+ sizeof(unsigned long)) {
+ tmp = va_arg(args, unsigned long long);
+ acnt += sizeof(unsigned long long);
+ } else {
+ ((unsigned long *)&tmp)[0] =
+ va_arg(args, unsigned long);
+ ((unsigned long *)&tmp)[1] =
+ va_arg(args, unsigned long);
+ acnt += 2*sizeof(unsigned long);
+ }
+ if (*(format + 2) == 'u') {
+ format += 2;
+ pc += printi(out, out_len, tmp,
+ 10, 0, width, flags, 'a');
+ } else if (*(format + 2) == 'x') {
+ format += 2;
+ pc += printi(out, out_len, tmp,
+ 16, 0, width, flags, 'a');
+ } else if (*(format + 2) == 'X') {
+ format += 2;
+ pc += printi(out, out_len, tmp,
+ 16, 0, width, flags, 'A');
+ } else {
+ format += 1;
+ pc += printi(out, out_len, tmp,
+ 10, 1, width, flags, '0');
+ }
+ continue;
+ } else if (*format == 'l') {
+ if (*(format + 1) == 'x') {
+ format += 1;
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long),
+ 16, 0, width, flags, 'a');
+ acnt += sizeof(unsigned long);
+ } else if (*(format + 1) == 'X') {
+ format += 1;
+ pc += printi(out, out_len,
+ va_arg(args, unsigned long),
+ 16, 0, width, flags, 'A');
+ acnt += sizeof(unsigned long);
+ } else {
+ pc += printi(out, out_len,
+ va_arg(args, long),
+ 10, 1, width, flags, '0');
+ acnt += sizeof(long);
+ }
+ }
+ if (*format == 'c') {
+ /* char are converted to int then pushed on the stack */
+ scr[0] = va_arg(args, int);
+ scr[1] = '\0';
+ pc += prints(out, out_len, scr, width, flags);
+ acnt += sizeof(int);
+ continue;
+ }
+ } else {
+out:
+ printc(out, out_len, *format);
+ ++pc;
+ }
+ }
+ if (out)
+ **out = '\0';
+ return pc;
+}
+
+int sbi_sprintf(char *out, const char *format, ...)
+{
+ va_list args;
+ int retval;
+ va_start(args, format);
+ retval = print(&out, NULL, format, args);
+ va_end(args);
+ return retval;
+}
+
+int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
+{
+ va_list args;
+ int retval;
+ va_start(args, format);
+ retval = print(&out, &out_sz, format, args);
+ va_end(args);
+ return retval;
+}
+
+int sbi_printf(const char *format, ...)
+{
+ va_list args;
+ int retval;
+ va_start(args, format);
+ retval = print(NULL, NULL, format, args);
+ va_end(args);
+ return retval;
+}
+
+int sbi_console_init(struct sbi_scratch *scratch)
+{
+ console_plat = sbi_platform_ptr(scratch);
+
+ return sbi_platform_console_init(console_plat);
+}
diff --git a/lib/sbi_ecall.c b/lib/sbi_ecall.c
new file mode 100644
index 0000000..928a8b7
--- /dev/null
+++ b/lib/sbi_ecall.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_trap.h>
+
+#define SBI_ECALL_VERSION_MAJOR 0
+#define SBI_ECALL_VERSION_MINOR 1
+
+#define SBI_ECALL_SET_TIMER 0
+#define SBI_ECALL_CONSOLE_PUTCHAR 1
+#define SBI_ECALL_CONSOLE_GETCHAR 2
+#define SBI_ECALL_CLEAR_IPI 3
+#define SBI_ECALL_SEND_IPI 4
+#define SBI_ECALL_REMOTE_FENCE_I 5
+#define SBI_ECALL_REMOTE_SFENCE_VMA 6
+#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_ECALL_SHUTDOWN 8
+
+u16 sbi_ecall_version_major(void)
+{
+ return SBI_ECALL_VERSION_MAJOR;
+}
+
+u16 sbi_ecall_version_minor(void)
+{
+ return SBI_ECALL_VERSION_MINOR;
+}
+
+int sbi_ecall_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch)
+{
+ int ret = SBI_ENOTSUPP;
+
+ switch (regs->a7) {
+ case SBI_ECALL_SET_TIMER:
+#if __riscv_xlen == 32
+ sbi_timer_event_start(scratch, hartid,
+ (((u64)regs->a1 << 32) || (u64)regs->a0));
+#else
+ sbi_timer_event_start(scratch, hartid, (u64)regs->a0);
+#endif
+ ret = 0;
+ break;
+ case SBI_ECALL_CONSOLE_PUTCHAR:
+ sbi_putc(regs->a0);
+ ret = 0;
+ break;
+ case SBI_ECALL_CONSOLE_GETCHAR:
+ regs->a0 = sbi_getc();
+ ret = 0;
+ break;
+ case SBI_ECALL_CLEAR_IPI:
+ sbi_ipi_clear_smode(scratch, hartid);
+ ret = 0;
+ break;
+ case SBI_ECALL_SEND_IPI:
+ ret = sbi_ipi_send_many(scratch, hartid,
+ (ulong *)regs->a0,
+ SBI_IPI_EVENT_SOFT);
+ break;
+ case SBI_ECALL_REMOTE_FENCE_I:
+ ret = sbi_ipi_send_many(scratch, hartid,
+ (ulong *)regs->a0,
+ SBI_IPI_EVENT_FENCE_I);
+ break;
+ case SBI_ECALL_REMOTE_SFENCE_VMA:
+ case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
+ ret = sbi_ipi_send_many(scratch, hartid,
+ (ulong *)regs->a0,
+ SBI_IPI_EVENT_SFENCE_VMA);
+ break;
+ case SBI_ECALL_SHUTDOWN:
+ sbi_system_shutdown(scratch, 0);
+ ret = 0;
+ break;
+ default:
+ break;
+ };
+
+ if (!ret) {
+ regs->mepc += 4;
+ }
+
+ return ret;
+}
diff --git a/lib/sbi_emulate_csr.c b/lib/sbi_emulate_csr.c
new file mode 100644
index 0000000..cc74f96
--- /dev/null
+++ b/lib/sbi_emulate_csr.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_emulate_csr.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_timer.h>
+
+int sbi_emulate_csr_read(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong *csr_val)
+{
+ ulong cen = -1UL;
+
+ if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
+ cen = csr_read(scounteren);
+
+ switch (csr_num) {
+ case CSR_MISA:
+ *csr_val = csr_read(misa);
+ break;
+ case CSR_MVENDORID:
+ *csr_val = csr_read(mvendorid);
+ break;
+ case CSR_MARCHID:
+ *csr_val = csr_read(marchid);
+ break;
+ case CSR_MIMPID:
+ *csr_val = csr_read(mimpid);
+ break;
+ case CSR_MHARTID:
+ *csr_val = csr_read(mhartid);
+ break;
+ case CSR_CYCLE:
+ if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = csr_read(mcycle);
+ break;
+ case CSR_TIME:
+ if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = sbi_timer_value(scratch);
+ break;
+ case CSR_INSTRET:
+ if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = csr_read(minstret);
+ break;
+ case CSR_MHPMCOUNTER3:
+ if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
+ return -1;
+ *csr_val = csr_read(mhpmcounter3);
+ break;
+ case CSR_MHPMCOUNTER4:
+ if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
+ return -1;
+ *csr_val = csr_read(mhpmcounter4);
+ break;
+#if __riscv_xlen == 32
+ case CSR_CYCLEH:
+ if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = csr_read(mcycleh);
+ break;
+ case CSR_TIMEH:
+ if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = sbi_timer_value(scratch);
+ *csr_val = *csr_val >> 32;
+ break;
+ case CSR_INSTRETH:
+ if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
+ return -1;
+ *csr_val = csr_read(minstreth);
+ break;
+ case CSR_MHPMCOUNTER3H:
+ if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
+ return -1;
+ *csr_val = csr_read(mhpmcounter3h);
+ break;
+ case CSR_MHPMCOUNTER4H:
+ if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
+ return -1;
+ *csr_val = csr_read(mhpmcounter4h);
+ break;
+#endif
+ case CSR_MHPMEVENT3:
+ *csr_val = csr_read(mhpmevent3);
+ break;
+ case CSR_MHPMEVENT4:
+ *csr_val = csr_read(mhpmevent4);
+ break;
+ default:
+ sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
+ __func__, hartid, csr_num);
+ return SBI_ENOTSUPP;
+ };
+
+ return 0;
+}
+
+int sbi_emulate_csr_write(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong csr_val)
+{
+ switch (csr_num) {
+ case CSR_CYCLE:
+ csr_write(mcycle, csr_val);
+ break;
+ case CSR_INSTRET:
+ csr_write(minstret, csr_val);
+ break;
+ case CSR_MHPMCOUNTER3:
+ csr_write(mhpmcounter3, csr_val);
+ break;
+ case CSR_MHPMCOUNTER4:
+ csr_write(mhpmcounter4, csr_val);
+ break;
+#if __riscv_xlen == 32
+ case CSR_CYCLEH:
+ csr_write(mcycleh, csr_val);
+ break;
+ case CSR_INSTRETH:
+ csr_write(minstreth, csr_val);
+ break;
+ case CSR_MHPMCOUNTER3H:
+ csr_write(mhpmcounter3h, csr_val);
+ break;
+ case CSR_MHPMCOUNTER4H:
+ csr_write(mhpmcounter4h, csr_val);
+ break;
+#endif
+ case CSR_MHPMEVENT3:
+ csr_write(mhpmevent3, csr_val);
+ break;
+ case CSR_MHPMEVENT4:
+ csr_write(mhpmevent4, csr_val);
+ break;
+ default:
+ sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
+ __func__, hartid, csr_num);
+ return SBI_ENOTSUPP;
+ };
+
+ return 0;
+}
diff --git a/lib/sbi_hart.c b/lib/sbi_hart.c
new file mode 100644
index 0000000..db833c7
--- /dev/null
+++ b/lib/sbi_hart.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+
+static int mstatus_init(u32 hartid)
+{
+ /* Enable FPU */
+ if (misa_extension('D') || misa_extension('F'))
+ csr_write(mstatus, MSTATUS_FS);
+
+ /* Enable user/supervisor use of perf counters */
+ if (misa_extension('S'))
+ csr_write(scounteren, -1);
+ csr_write(mcounteren, -1);
+
+ /* Disable all interrupts */
+ csr_write(mie, 0);
+
+ /* Disable S-mode paging */
+ if (misa_extension('S'))
+ csr_write(sptbr, 0);
+
+ return 0;
+}
+
+#ifdef __riscv_flen
+static void init_fp_reg(int i)
+{
+ /* TODO: */
+}
+#endif
+
+static int fp_init(u32 hartid)
+{
+#ifdef __riscv_flen
+ int i;
+#else
+ unsigned long fd_mask;
+#endif
+
+ if (!misa_extension('D') && !misa_extension('F'))
+ return 0;
+
+ if (!(csr_read(mstatus) & MSTATUS_FS))
+ return SBI_EINVAL;
+
+#ifdef __riscv_flen
+ for (i = 0; i < 32; i++)
+ init_fp_reg(i);
+ csr_write(fcsr, 0);
+#else
+ fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
+ csr_clear(misa, fd_mask);
+ if (csr_read(misa) & fd_mask)
+ return SBI_ENOTSUPP;
+#endif
+
+ return 0;
+}
+
+static int delegate_traps(u32 hartid)
+{
+ /* send S-mode interrupts and most exceptions straight to S-mode */
+ unsigned long interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
+ unsigned long exceptions = (1U << CAUSE_MISALIGNED_FETCH) |
+ (1U << CAUSE_FETCH_PAGE_FAULT) |
+ (1U << CAUSE_BREAKPOINT) |
+ (1U << CAUSE_LOAD_PAGE_FAULT) |
+ (1U << CAUSE_STORE_PAGE_FAULT) |
+ (1U << CAUSE_USER_ECALL);
+
+ if (!misa_extension('S'))
+ return 0;
+
+ csr_write(mideleg, interrupts);
+ csr_write(medeleg, exceptions);
+
+ if (csr_read(mideleg) != interrupts)
+ return SBI_EFAIL;
+ if (csr_read(medeleg) != exceptions)
+ return SBI_EFAIL;
+
+ return 0;
+}
+
+unsigned long log2roundup(unsigned long x)
+{
+ unsigned long ret = 0;
+
+ while (ret < __riscv_xlen) {
+ if (x <= (1UL << ret))
+ break;
+ ret++;
+ }
+
+ return ret;
+}
+
+void sbi_hart_pmp_dump(void)
+{
+ unsigned int i;
+ unsigned long prot, addr, size, l2l;
+
+ for (i = 0; i < PMP_COUNT; i++) {
+ pmp_get(i, &prot, &addr, &l2l);
+ if (!(prot & PMP_A))
+ continue;
+ if (l2l < __riscv_xlen)
+ size = (1UL << l2l);
+ else
+ size = 0;
+#if __riscv_xlen == 32
+ sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
+#else
+ sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
+#endif
+ i, addr, addr + size - 1);
+ if (prot & PMP_L)
+ sbi_printf(",L");
+ if (prot & PMP_R)
+ sbi_printf(",R");
+ if (prot & PMP_W)
+ sbi_printf(",W");
+ if (prot & PMP_X)
+ sbi_printf(",X");
+ sbi_printf(")\n");
+ }
+}
+
+static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ u32 i, count;
+ unsigned long fw_start, fw_size_log2;
+ ulong prot, addr, log2size;
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ fw_size_log2 = log2roundup(scratch->fw_size);
+ fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
+
+ pmp_set(0, 0, fw_start, fw_size_log2);
+
+ count = sbi_platform_pmp_region_count(plat, hartid);
+ if ((PMP_COUNT - 1) < count)
+ count = (PMP_COUNT - 1);
+
+ for (i = 0; i < count; i++) {
+ if (sbi_platform_pmp_region_info(plat, hartid, i,
+ &prot, &addr, &log2size))
+ continue;
+ pmp_set(i + 1, prot, addr, log2size);
+ }
+
+ return 0;
+}
+
+int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ int rc;
+
+ rc = mstatus_init(hartid);
+ if (rc)
+ return rc;
+
+ rc = fp_init(hartid);
+ if (rc)
+ return rc;
+
+ rc = delegate_traps(hartid);
+ if (rc)
+ return rc;
+
+ return pmp_init(scratch, hartid);
+}
+
+void __attribute__((noreturn)) sbi_hart_hang(void)
+{
+ while (1)
+ wfi();
+ __builtin_unreachable();
+}
+
+void __attribute__((noreturn)) sbi_hart_boot_next(unsigned long arg0,
+ unsigned long arg1,
+ unsigned long next_addr,
+ unsigned long next_mode)
+{
+ unsigned long val;
+
+ if (next_mode != PRV_S && next_mode != PRV_M && next_mode != PRV_U)
+ sbi_hart_hang();
+
+ val = csr_read(mstatus);
+ val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
+ val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
+ csr_write(mstatus, val);
+ csr_write(mepc, next_addr);
+
+ if (next_mode == PRV_S) {
+ csr_write(stvec, next_addr);
+ csr_write(sscratch, 0);
+ csr_write(sie, 0);
+ csr_write(satp, 0);
+ } else if (next_mode == PRV_U) {
+ csr_write(utvec, next_addr);
+ csr_write(uscratch, 0);
+ csr_write(uie, 0);
+ }
+
+ register unsigned long a0 asm ("a0") = arg0;
+ register unsigned long a1 asm ("a1") = arg1;
+ __asm__ __volatile__ ("mret" : : "r" (a0), "r" (a1));
+ __builtin_unreachable();
+}
+
+static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
+static volatile unsigned long avail_hart_mask = 0;
+
+void sbi_hart_mark_available(u32 hartid)
+{
+ spin_lock(&avail_hart_mask_lock);
+ avail_hart_mask |= (1UL << hartid);
+ spin_unlock(&avail_hart_mask_lock);
+}
+
+void sbi_hart_unmark_available(u32 hartid)
+{
+ spin_lock(&avail_hart_mask_lock);
+ avail_hart_mask &= ~(1UL << hartid);
+ spin_unlock(&avail_hart_mask_lock);
+}
+
+ulong sbi_hart_available_mask(void)
+{
+ ulong ret;
+
+ spin_lock(&avail_hart_mask_lock);
+ ret = avail_hart_mask;
+ spin_unlock(&avail_hart_mask_lock);
+
+ return ret;
+}
+
+typedef struct sbi_scratch *(*h2s)(ulong hartid);
+
+struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
+ u32 hartid)
+{
+ return ((h2s)scratch->hartid_to_scratch)(hartid);
+}
+
+#define NO_HOTPLUG_BITMAP_SIZE __riscv_xlen
+static spinlock_t coldboot_holding_pen_lock = SPIN_LOCK_INITIALIZER;
+static volatile unsigned long coldboot_holding_pen = 0;
+
+void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
+{
+ unsigned long done;
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if ((sbi_platform_hart_count(plat) <= hartid) ||
+ (NO_HOTPLUG_BITMAP_SIZE <= hartid))
+ sbi_hart_hang();
+
+ while (1) {
+ spin_lock(&coldboot_holding_pen_lock);
+ done = coldboot_holding_pen;
+ spin_unlock(&coldboot_holding_pen_lock);
+ if (done)
+ break;
+ cpu_relax();
+ }
+}
+
+void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch)
+{
+ spin_lock(&coldboot_holding_pen_lock);
+ coldboot_holding_pen = 1;
+ spin_unlock(&coldboot_holding_pen_lock);
+}
diff --git a/lib/sbi_illegal_insn.c b/lib/sbi_illegal_insn.c
new file mode 100644
index 0000000..e8edd0e
--- /dev/null
+++ b/lib/sbi_illegal_insn.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_emulate_csr.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_illegal_insn.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+
+#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
+
+typedef int (*illegal_insn_func)(ulong insn,
+ u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+static int truly_illegal_insn(ulong insn,
+ u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch)
+{
+ /* For now, always fails */
+ return SBI_ENOTSUPP;
+}
+
+static int system_opcode_insn(ulong insn,
+ u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch)
+{
+ int do_write, rs1_num = (insn >> 15) & 0x1f;
+ ulong rs1_val = GET_RS1(insn, regs);
+ int csr_num = (u32)insn >> 20;
+ ulong csr_val, new_csr_val;
+
+ if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus,
+ scratch, &csr_val))
+ return truly_illegal_insn(insn, hartid, mcause,
+ regs, scratch);
+
+ do_write = rs1_num;
+ switch (GET_RM(insn)) {
+ case 1:
+ new_csr_val = rs1_val;
+ do_write = 1;
+ break;
+ case 2:
+ new_csr_val = csr_val | rs1_val;
+ break;
+ case 3: new_csr_val = csr_val & ~rs1_val;
+ break;
+ case 5:
+ new_csr_val = rs1_num;
+ do_write = 1;
+ break;
+ case 6:
+ new_csr_val = csr_val | rs1_num;
+ break;
+ case 7:
+ new_csr_val = csr_val & ~rs1_num;
+ break;
+ default:
+ return truly_illegal_insn(insn, hartid, mcause,
+ regs, scratch);
+ };
+
+ if (do_write &&
+ sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
+ scratch, new_csr_val))
+ return truly_illegal_insn(insn, hartid, mcause,
+ regs, scratch);
+
+ SET_RD(insn, regs, csr_val);
+
+ regs->mepc += 4;
+
+ return 0;
+}
+
+static illegal_insn_func illegal_insn_table[32] = {
+ truly_illegal_insn, /* 0 */
+ truly_illegal_insn, /* 1 */
+ truly_illegal_insn, /* 2 */
+ truly_illegal_insn, /* 3 */
+ truly_illegal_insn, /* 4 */
+ truly_illegal_insn, /* 5 */
+ truly_illegal_insn, /* 6 */
+ truly_illegal_insn, /* 7 */
+ truly_illegal_insn, /* 8 */
+ truly_illegal_insn, /* 9 */
+ truly_illegal_insn, /* 10 */
+ truly_illegal_insn, /* 11 */
+ truly_illegal_insn, /* 12 */
+ truly_illegal_insn, /* 13 */
+ truly_illegal_insn, /* 14 */
+ truly_illegal_insn, /* 15 */
+ truly_illegal_insn, /* 16 */
+ truly_illegal_insn, /* 17 */
+ truly_illegal_insn, /* 18 */
+ truly_illegal_insn, /* 19 */
+ truly_illegal_insn, /* 20 */
+ truly_illegal_insn, /* 21 */
+ truly_illegal_insn, /* 22 */
+ truly_illegal_insn, /* 23 */
+ truly_illegal_insn, /* 24 */
+ truly_illegal_insn, /* 25 */
+ truly_illegal_insn, /* 26 */
+ truly_illegal_insn, /* 27 */
+ system_opcode_insn, /* 28 */
+ truly_illegal_insn, /* 29 */
+ truly_illegal_insn, /* 30 */
+ truly_illegal_insn /* 31 */
+};
+
+int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch)
+{
+ ulong mstatus;
+ ulong insn = csr_read(mbadaddr);
+
+ if (unlikely((insn & 3) != 3)) {
+ if (insn == 0) {
+ mstatus = csr_read(mstatus);
+ insn = get_insn(regs->mepc, &mstatus);
+ }
+ if ((insn & 3) != 3)
+ return SBI_ENOTSUPP;
+ }
+
+ return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
+ regs, scratch);
+}
diff --git a/lib/sbi_init.c b/lib/sbi_init.c
new file mode 100644
index 0000000..52c63fa
--- /dev/null
+++ b/lib/sbi_init.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+
+static void __attribute__((noreturn)) init_coldboot(struct sbi_scratch *scratch,
+ u32 hartid)
+{
+ int rc;
+ char str[64];
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ rc = sbi_system_cold_early_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_system_warm_early_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_hart_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_console_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_cold_irqchip_init(plat);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_warm_irqchip_init(plat, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_ipi_cold_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_ipi_warm_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_timer_cold_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_timer_warm_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_system_cold_final_init(scratch);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_system_warm_final_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ misa_string(str, sizeof(str));
+ sbi_printf("OpenSBI v%d.%d (%s %s)\n",
+ OPENSBI_MAJOR, OPENSBI_MINOR,
+ __DATE__, __TIME__);
+ sbi_printf("\n");
+ /* Platform details */
+ sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
+ sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
+ sbi_printf("Platform Max HARTs : %d\n",
+ sbi_platform_hart_count(plat));
+ /* Firmware details */
+ sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
+ sbi_printf("Firmware Size : %d KB\n",
+ (u32)(scratch->fw_size / 1024));
+ /* Generic details */
+ sbi_printf("Runtime SBI Version : %d.%d\n",
+ sbi_ecall_version_major(), sbi_ecall_version_minor());
+ sbi_printf("\n");
+
+ sbi_hart_pmp_dump();
+
+ sbi_hart_mark_available(hartid);
+
+ if (!sbi_platform_has_hart_hotplug(plat))
+ sbi_hart_wake_coldboot_harts(scratch);
+
+ sbi_hart_boot_next(hartid, scratch->next_arg1,
+ scratch->next_addr, scratch->next_mode);
+}
+
+static void __attribute__((noreturn)) init_warmboot(struct sbi_scratch *scratch,
+ u32 hartid)
+{
+ int rc;
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (!sbi_platform_has_hart_hotplug(plat))
+ sbi_hart_wait_for_coldboot(scratch, hartid);
+
+ rc = sbi_system_warm_early_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_hart_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_platform_warm_irqchip_init(plat, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_ipi_warm_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_timer_warm_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ rc = sbi_system_warm_final_init(scratch, hartid);
+ if (rc)
+ sbi_hart_hang();
+
+ sbi_hart_mark_available(hartid);
+
+ if (sbi_platform_has_hart_hotplug(plat))
+ /* TODO: To be implemented in-future. */
+ sbi_hart_hang();
+ else
+ sbi_hart_boot_next(hartid, scratch->next_arg1,
+ scratch->next_addr, scratch->next_mode);
+}
+
+static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
+
+void __attribute__((noreturn)) sbi_init(struct sbi_scratch *scratch)
+{
+ bool coldboot = FALSE;
+ u32 hartid = csr_read(mhartid);
+
+ if (atomic_add_return(&coldboot_lottery, 1) == 1)
+ coldboot = TRUE;
+
+ if (coldboot)
+ init_coldboot(scratch, hartid);
+ else
+ init_warmboot(scratch, hartid);
+}
diff --git a/lib/sbi_ipi.c b/lib/sbi_ipi.c
new file mode 100644
index 0000000..f3e68de
--- /dev/null
+++ b/lib/sbi_ipi.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_unpriv.h>
+
+int sbi_ipi_send_many(struct sbi_scratch *scratch,
+ u32 hartid, ulong *pmask, u32 event)
+{
+ ulong i, m;
+ struct sbi_scratch *oth;
+ ulong mask = sbi_hart_available_mask();
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (pmask)
+ mask &= load_ulong(pmask, csr_read(mepc));
+
+ /* send IPIs to everyone */
+ for (i = 0, m = mask; m; i++, m >>= 1) {
+ if ((m & 1) && (i != hartid)) {
+ oth = sbi_hart_id_to_scratch(scratch, i);
+ oth->ipi_type = event;
+ mb();
+ sbi_platform_ipi_inject(plat, i, hartid);
+ if (event != SBI_IPI_EVENT_SOFT)
+ sbi_platform_ipi_sync(plat, i, hartid);
+ }
+ }
+
+ return 0;
+}
+
+void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid)
+{
+ csr_clear(mip, MIP_SSIP);
+}
+
+void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
+{
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ sbi_platform_ipi_clear(plat, hartid);
+ switch (scratch->ipi_type) {
+ case SBI_IPI_EVENT_SOFT:
+ csr_set(mip, MIP_SSIP);
+ break;
+ case SBI_IPI_EVENT_FENCE_I:
+ __asm__ __volatile("fence.i");
+ break;
+ case SBI_IPI_EVENT_SFENCE_VMA:
+ __asm__ __volatile("sfence.vma");
+ break;
+ case SBI_IPI_EVENT_HALT:
+ sbi_hart_hang();
+ break;
+ };
+ scratch->ipi_type = 0;
+}
+
+int sbi_ipi_warm_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ /* Enable software interrupts */
+ csr_set(mie, MIP_MSIP);
+
+ return sbi_platform_warm_ipi_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_ipi_cold_init(struct sbi_scratch *scratch)
+{
+ return sbi_platform_cold_ipi_init(sbi_platform_ptr(scratch));
+}
diff --git a/lib/sbi_system.c b/lib/sbi_system.c
new file mode 100644
index 0000000..cd250f5
--- /dev/null
+++ b/lib/sbi_system.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+
+int sbi_system_warm_early_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ return sbi_platform_warm_early_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_system_warm_final_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ return sbi_platform_warm_final_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_system_cold_early_init(struct sbi_scratch *scratch)
+{
+ return sbi_platform_cold_early_init(sbi_platform_ptr(scratch));
+}
+
+int sbi_system_cold_final_init(struct sbi_scratch *scratch)
+{
+ return sbi_platform_cold_final_init(sbi_platform_ptr(scratch));
+}
+
+void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
+ u32 type)
+
+{
+ sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
+ sbi_hart_hang();
+}
+
+void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
+ u32 type)
+{
+ sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
+ sbi_hart_hang();
+}
diff --git a/lib/sbi_timer.c b/lib/sbi_timer.c
new file mode 100644
index 0000000..355bc64
--- /dev/null
+++ b/lib/sbi_timer.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_timer.h>
+
+#if __riscv_xlen == 32
+u64 get_ticks(void)
+{
+ u32 lo, hi, tmp;
+ __asm__ __volatile__ (
+ "1:\n"
+ "rdtimeh %0\n"
+ "rdtime %1\n"
+ "rdtimeh %2\n"
+ "bne %0, %2, 1b"
+ : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+ return ((u64)hi << 32) | lo;
+}
+#else
+u64 get_ticks(void)
+{
+ unsigned long n;
+
+ __asm__ __volatile__ (
+ "rdtime %0"
+ : "=r" (n));
+ return n;
+}
+#endif
+
+u64 sbi_timer_value(struct sbi_scratch *scratch)
+{
+ struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+ if (sbi_platform_has_mmio_timer_value(plat))
+ return sbi_platform_timer_value(plat);
+ else
+ return get_ticks();
+}
+
+void sbi_timer_event_stop(struct sbi_scratch *scratch, u32 hartid)
+{
+ sbi_platform_timer_event_stop(sbi_platform_ptr(scratch), hartid);
+}
+
+void sbi_timer_event_start(struct sbi_scratch *scratch, u32 hartid,
+ u64 next_event)
+{
+ sbi_platform_timer_event_start(sbi_platform_ptr(scratch),
+ hartid, next_event);
+ csr_clear(mip, MIP_STIP);
+ csr_set(mie, MIP_MTIP);
+}
+
+void sbi_timer_process(struct sbi_scratch *scratch, u32 hartid)
+{
+ csr_clear(mie, MIP_MTIP);
+ csr_set(mip, MIP_STIP);
+}
+
+int sbi_timer_warm_init(struct sbi_scratch *scratch, u32 hartid)
+{
+ return sbi_platform_warm_timer_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_timer_cold_init(struct sbi_scratch *scratch)
+{
+ return sbi_platform_cold_timer_init(sbi_platform_ptr(scratch));
+}
diff --git a/lib/sbi_trap.c b/lib/sbi_trap.c
new file mode 100644
index 0000000..f9c70a6
--- /dev/null
+++ b/lib/sbi_trap.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_illegal_insn.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_trap.h>
+
+static void __attribute__((noreturn)) sbi_trap_error(const char *msg,
+ int rc, u32 hartid,
+ ulong mcause,
+ struct sbi_trap_regs *regs)
+{
+ sbi_printf("%s: hart%d: %s (error %d)\n",
+ __func__, hartid, msg, rc);
+ sbi_printf("%s: hart%d: mcause=0x%lx mepc=0x%lx mstatus=0x%lx\n",
+ __func__, hartid, mcause, regs->mepc, regs->mstatus);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "ra", regs->ra, "sp", regs->sp);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "gp", regs->gp, "tp", regs->tp);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s0", regs->s0, "s1", regs->s1);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "a0", regs->a0, "a1", regs->a1);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "a2", regs->a2, "a3", regs->a3);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "a4", regs->a4, "a5", regs->a5);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "a6", regs->a6, "a7", regs->a7);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s2", regs->s2, "s3", regs->s3);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s4", regs->s4, "s5", regs->s5);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s6", regs->s6, "s7", regs->s7);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s8", regs->s8, "s9", regs->s9);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "s10", regs->s10, "s11", regs->s11);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "t0", regs->t0, "t1", regs->t1);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "t2", regs->t2, "t3", regs->t3);
+ sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+ __func__, hartid, "t4", regs->t4, "t5", regs->t5);
+ sbi_printf("%s: hart%d: %s=0x%lx\n",
+ __func__, hartid, "t6", regs->t6);
+
+ sbi_hart_hang();
+}
+
+void sbi_trap_handler(struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch)
+{
+ int rc;
+ const char *msg;
+ u32 hartid = csr_read(mhartid);
+ ulong mcause = csr_read(mcause);
+
+ if (mcause & (1UL << (__riscv_xlen - 1))) {
+ mcause &= ~(1UL << (__riscv_xlen - 1));
+ switch (mcause) {
+ case IRQ_M_TIMER:
+ sbi_timer_process(scratch, hartid);
+ break;
+ case IRQ_M_SOFT:
+ sbi_ipi_process(scratch, hartid);
+ break;
+ default:
+ sbi_trap_error("unhandled external interrupt",
+ SBI_ENOTSUPP, hartid, mcause, regs);
+ break;
+ };
+ return;
+ }
+
+ rc = SBI_ENOTSUPP;
+ msg = "trap handler failed";
+ switch (mcause) {
+ case CAUSE_ILLEGAL_INSTRUCTION:
+ rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
+ msg = "illegal instruction handler failed";
+ break;
+ case CAUSE_SUPERVISOR_ECALL:
+ case CAUSE_HYPERVISOR_ECALL:
+ rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
+ msg = "ecall handler failed";
+ break;
+ default:
+ break;
+ };
+
+ if (rc) {
+ sbi_trap_error(msg, rc, hartid, mcause, regs);
+ }
+}
diff --git a/plat/common/fdt.c b/plat/common/fdt.c
new file mode 100644
index 0000000..4f6017c
--- /dev/null
+++ b/plat/common/fdt.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <plat/fdt.h>
+
+#define FDT_MAGIC 0xd00dfeed
+#define FDT_VERSION 17
+
+struct fdt_header {
+ u32 magic;
+ u32 totalsize;
+ u32 off_dt_struct;
+ u32 off_dt_strings;
+ u32 off_mem_rsvmap;
+ u32 version;
+ u32 last_comp_version; /* <= 17 */
+ u32 boot_cpuid_phys;
+ u32 size_dt_strings;
+ u32 size_dt_struct;
+} __attribute__((packed));
+
+#define FDT_BEGIN_NODE 1
+#define FDT_END_NODE 2
+#define FDT_PROP 3
+#define FDT_NOP 4
+#define FDT_END 9
+
+u32 fdt_rev32(u32 v)
+{
+ return ((v & 0x000000FF) << 24) |
+ ((v & 0x0000FF00) << 8) |
+ ((v & 0x00FF0000) >> 8) |
+ ((v & 0xFF000000) >> 24);
+}
+
+ulong fdt_strlen(const char *str)
+{
+ ulong ret = 0;
+
+ while (*str != '\0') {
+ ret++;
+ str++;
+ }
+
+ return ret;
+}
+
+int fdt_strcmp(const char *a, const char *b)
+{
+ /* search first diff or end of string */
+ for (; *a == *b && *a != '\0'; a++, b++);
+ return *a - *b;
+}
+
+int fdt_prop_string_index(const struct fdt_prop *prop,
+ const char *str)
+{
+ int i;
+ ulong l = 0;
+ const char *p, *end;
+
+ p = prop->value;
+ end = p + prop->len;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = fdt_strlen(p) + 1;
+ if (p + l > end)
+ return -1;
+ if (fdt_strcmp(str, p) == 0)
+ return i; /* Found it; return index */
+ }
+
+ return -1;
+}
+
+struct recursive_iter_info {
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv);
+ void *fn_priv;
+ const char *str;
+};
+
+#define DATA32(ptr) fdt_rev32(*((u32*)ptr))
+
+static void recursive_iter(char **data, struct recursive_iter_info *info,
+ const struct fdt_node *parent)
+{
+ struct fdt_node node;
+ struct fdt_prop prop;
+
+ if (DATA32(*data) != FDT_BEGIN_NODE)
+ return;
+
+ node.data = *data;
+
+ (*data) += sizeof(u32);
+
+ node.parent = parent;
+ node.name = *data;
+
+ *data += fdt_strlen(*data) + 1;
+ while ((ulong)(*data) % sizeof(u32) != 0)
+ (*data)++;
+
+ node.depth = (parent) ? (parent->depth + 1) : 1;
+
+ /* Default cell counts, as per the FDT spec */
+ node.address_cells = 2;
+ node.size_cells = 1;
+
+ info->fn(&node, NULL, info->fn_priv);
+
+ while (DATA32(*data) != FDT_END_NODE) {
+ switch (DATA32(*data)) {
+ case FDT_PROP:
+ prop.node = &node;
+ *data += sizeof(u32);
+ prop.len = DATA32(*data);
+ *data += sizeof(u32);
+ prop.name = &info->str[DATA32(*data)];
+ *data += sizeof(u32);
+ prop.value = *data;
+ *data += prop.len;
+ while ((ulong)(*data) % sizeof(u32) != 0)
+ (*data)++;
+ info->fn(&node, &prop, info->fn_priv);
+ break;
+ case FDT_NOP:
+ *data += sizeof(u32);
+ break;
+ case FDT_BEGIN_NODE:
+ recursive_iter(data, info, &node);
+ break;
+ default:
+ return;
+ };
+ }
+
+ *data += sizeof(u32);
+}
+
+struct match_iter_info {
+ int (*match)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv);
+ void *match_priv;
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv);
+ void *fn_priv;
+ const char *str;
+};
+
+static void match_iter(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv)
+{
+ char *data;
+ struct match_iter_info *minfo = priv;
+ struct fdt_prop nprop;
+
+ /* Do nothing if node+prop dont match */
+ if (!minfo->match(node, prop, minfo->match_priv))
+ return;
+
+ /* Call function for node */
+ if (minfo->fn)
+ minfo->fn(node, NULL, minfo->fn_priv);
+
+ /* Convert node to character stream */
+ data = node->data;
+ data += sizeof(u32);
+
+ /* Skip node name */
+ data += fdt_strlen(data) + 1;
+ while ((ulong)(data) % sizeof(u32) != 0)
+ data++;
+
+ /* Find node property and its value */
+ while (DATA32(data) == FDT_PROP) {
+ nprop.node = node;
+ data += sizeof(u32);
+ nprop.len = DATA32(data);
+ data += sizeof(u32);
+ nprop.name = &minfo->str[DATA32(data)];
+ data += sizeof(u32);
+ nprop.value = data;
+ data += nprop.len;
+ while ((ulong)(data) % sizeof(u32) != 0)
+ (data)++;
+ /* Call function for every property */
+ if (minfo->fn)
+ minfo->fn(node, &nprop, minfo->fn_priv);
+ }
+}
+
+int fdt_match_node_prop(void *fdt,
+ int (*match)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *match_priv,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv)
+{
+ char *data;
+ u32 string_offset, data_offset;
+ struct fdt_header *header;
+ struct match_iter_info minfo;
+ struct recursive_iter_info rinfo;
+
+ if (!fdt || !match)
+ return -1;
+
+ header = fdt;
+ if (fdt_rev32(header->magic) != FDT_MAGIC ||
+ fdt_rev32(header->last_comp_version) > FDT_VERSION)
+ return -1;
+ string_offset = fdt_rev32(header->off_dt_strings);
+ data_offset = fdt_rev32(header->off_dt_struct);
+
+ minfo.match = match;
+ minfo.match_priv = match_priv;
+ minfo.fn = fn;
+ minfo.fn_priv = fn_priv;
+ minfo.str = (const char *)(fdt + string_offset);
+
+ rinfo.fn = match_iter;
+ rinfo.fn_priv = &minfo;
+ rinfo.str = minfo.str;
+
+ data = (char *)(fdt + data_offset);
+ recursive_iter(&data, &rinfo, NULL);
+
+ return 0;
+}
+
+struct match_compat_info {
+ const char *compat;
+};
+
+static int match_compat(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv)
+{
+ struct match_compat_info *cinfo = priv;
+
+ if (!prop)
+ return 0;
+
+ if (fdt_strcmp(prop->name, "compatible"))
+ return 0;
+
+ if (fdt_prop_string_index(prop, cinfo->compat) < 0)
+ return 0;
+
+ return 1;
+}
+
+int fdt_compat_node_prop(void *fdt,
+ const char *compat,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv)
+{
+ struct match_compat_info cinfo = { .compat = compat };
+
+ return fdt_match_node_prop(fdt, match_compat, &cinfo,
+ fn, fn_priv);
+}
+
+static int match_walk(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv)
+{
+ if (!prop)
+ return 1;
+
+ return 0;
+}
+
+int fdt_walk(void *fdt,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv)
+{
+ return fdt_match_node_prop(fdt, match_walk, NULL,
+ fn, fn_priv);
+}
+
+u32 fdt_size(void *fdt)
+{
+ struct fdt_header *header;
+
+ if (!fdt)
+ return 0;
+
+ header = fdt;
+ if (fdt_rev32(header->magic) != FDT_MAGIC ||
+ fdt_rev32(header->last_comp_version) > FDT_VERSION)
+ return 0;
+
+ return fdt_rev32(header->totalsize);
+}
diff --git a/plat/common/include/plat/fdt.h b/plat/common/include/plat/fdt.h
new file mode 100644
index 0000000..246243f
--- /dev/null
+++ b/plat/common/include/plat/fdt.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __FDT_H__
+#define __FDT_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_node {
+ char *data;
+ const struct fdt_node *parent;
+ const char *name;
+ int depth;
+ int address_cells;
+ int size_cells;
+};
+
+struct fdt_prop {
+ const struct fdt_node *node;
+ const char *name;
+ void *value;
+ u32 len;
+};
+
+/* Reverse byte-order of 32bit number */
+u32 fdt_rev32(u32 v);
+
+/* Length of a string */
+ulong fdt_strlen(const char *str);
+
+/* Compate two strings */
+int fdt_strcmp(const char *a, const char *b);
+
+/* Find index of matching string from a list of strings */
+int fdt_prop_string_index(const struct fdt_prop *prop,
+ const char *str);
+
+/* Iterate over each property of matching node */
+int fdt_match_node_prop(void *fdt,
+ int (*match)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *match_priv,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv);
+
+/* Iterate over each property of compatible node */
+int fdt_compat_node_prop(void *fdt,
+ const char *compat,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv);
+
+/* Iterate over each node and property */
+int fdt_walk(void *fdt,
+ void (*fn)(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv),
+ void *fn_priv);
+
+/* Get size of FDT */
+u32 fdt_size(void *fdt);
+
+#endif
diff --git a/plat/common/include/plat/irqchip/plic.h b/plat/common/include/plat/irqchip/plic.h
new file mode 100644
index 0000000..7c062aa
--- /dev/null
+++ b/plat/common/include/plat/irqchip/plic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __IRQCHIP_PLIC_H__
+#define __IRQCHIP_PLIC_H__
+
+#include <sbi/sbi_types.h>
+
+int plic_fdt_fixup(void *fdt, const char *compat);
+
+int plic_warm_irqchip_init(u32 target_hart);
+
+int plic_cold_irqchip_init(unsigned long base,
+ u32 num_sources, u32 hart_count);
+
+#endif
diff --git a/plat/common/include/plat/serial/sifive-uart.h b/plat/common/include/plat/serial/sifive-uart.h
new file mode 100644
index 0000000..b932b16
--- /dev/null
+++ b/plat/common/include/plat/serial/sifive-uart.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_SIFIVE_UART_H__
+#define __SERIAL_SIFIVE_UART_H__
+
+#include <sbi/sbi_types.h>
+
+void sifive_uart_putc(char ch);
+
+char sifive_uart_getc(void);
+
+int sifive_uart_init(unsigned long base,
+ u32 in_freq, u32 baudrate);
+
+#endif
diff --git a/plat/common/include/plat/serial/uart8250.h b/plat/common/include/plat/serial/uart8250.h
new file mode 100644
index 0000000..ca19a9f
--- /dev/null
+++ b/plat/common/include/plat/serial/uart8250.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_UART8250_H__
+#define __SERIAL_UART8250_H__
+
+#include <sbi/sbi_types.h>
+
+void uart8250_putc(char ch);
+
+char uart8250_getc(void);
+
+int uart8250_init(unsigned long base,
+ u32 in_freq, u32 baudrate,
+ u32 reg_shift, u32 reg_width);
+
+#endif
diff --git a/plat/common/include/plat/sys/clint.h b/plat/common/include/plat/sys/clint.h
new file mode 100644
index 0000000..642d83a
--- /dev/null
+++ b/plat/common/include/plat/sys/clint.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SYS_CLINT_H__
+#define __SYS_CLINT_H__
+
+#include <sbi/sbi_types.h>
+
+void clint_ipi_inject(u32 target_hart, u32 source_hart);
+
+void clint_ipi_sync(u32 target_hart, u32 source_hart);
+
+void clint_ipi_clear(u32 target_hart);
+
+int clint_warm_ipi_init(u32 target_hart);
+
+int clint_cold_ipi_init(unsigned long base, u32 hart_count);
+
+u64 clint_timer_value(void);
+
+void clint_timer_event_stop(u32 target_hart);
+
+void clint_timer_event_start(u32 target_hart, u64 next_event);
+
+int clint_warm_timer_init(u32 target_hart);
+
+int clint_cold_timer_init(unsigned long base, u32 hart_count);
+
+#endif
diff --git a/plat/common/irqchip/objects.mk b/plat/common/irqchip/objects.mk
new file mode 100644
index 0000000..3950734
--- /dev/null
+++ b/plat/common/irqchip/objects.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_IRQCHIP_PLIC) += irqchip/plic.o
diff --git a/plat/common/irqchip/plic.c b/plat/common/irqchip/plic.c
new file mode 100644
index 0000000..404d1b7
--- /dev/null
+++ b/plat/common/irqchip/plic.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/fdt.h>
+#include <plat/irqchip/plic.h>
+
+#define PLIC_PRIORITY_BASE 0x0
+#define PLIC_PENDING_BASE 0x1000
+#define PLIC_ENABLE_BASE 0x2000
+#define PLIC_ENABLE_STRIDE 0x80
+#define PLIC_CONTEXT_BASE 0x200000
+#define PLIC_CONTEXT_STRIDE 0x1000
+
+static u32 plic_hart_count;
+static u32 plic_num_sources;
+static volatile void *plic_base;
+
+static void plic_set_priority(u32 source, u32 val)
+{
+ writel(val, plic_base);
+}
+
+static void plic_set_m_thresh(u32 hartid, u32 val)
+{
+ volatile void *plic_m_thresh = plic_base +
+ PLIC_CONTEXT_BASE +
+ PLIC_CONTEXT_STRIDE * (2 * hartid);
+ writel(val, plic_m_thresh);
+}
+
+static void plic_set_s_thresh(u32 hartid, u32 val)
+{
+ volatile void *plic_s_thresh = plic_base +
+ PLIC_CONTEXT_BASE +
+ PLIC_CONTEXT_STRIDE * (2 * hartid + 1);
+ writel(val, plic_s_thresh);
+}
+
+static void plic_set_s_ie(u32 hartid, u32 word_index, u32 val)
+{
+ volatile void *plic_s_ie = plic_base +
+ PLIC_ENABLE_BASE +
+ PLIC_ENABLE_STRIDE * (2 * hartid + 1);
+ writel(val, plic_s_ie + word_index * 4);
+}
+
+static void plic_fdt_fixup_prop(const struct fdt_node *node,
+ const struct fdt_prop *prop,
+ void *priv)
+{
+ u32 *cells;
+ u32 i, cells_count;
+
+ if (!prop)
+ return;
+ if (fdt_strcmp(prop->name, "interrupts-extended"))
+ return;
+
+ cells = prop->value;
+ cells_count = prop->len / sizeof(u32);
+
+ if (!cells_count)
+ return;
+
+ for (i = 0; i < cells_count; i++) {
+ if (i % 4 == 1)
+ cells[i] = fdt_rev32(0xffffffff);
+ }
+}
+
+int plic_fdt_fixup(void *fdt, const char *compat)
+{
+ fdt_compat_node_prop(fdt, compat, plic_fdt_fixup_prop, NULL);
+ return 0;
+}
+
+int plic_warm_irqchip_init(u32 target_hart)
+{
+ size_t i, ie_words = plic_num_sources / 32 + 1;
+
+ if (plic_hart_count <= target_hart)
+ return -1;
+
+ /* By default, enable all IRQs for S-mode of target HART */
+ for (i = 0; i < ie_words; i++)
+ plic_set_s_ie(target_hart, i, -1);
+
+ /* By default, enable M-mode threshold */
+ plic_set_m_thresh(target_hart, 1);
+
+ /* By default, disable S-mode threshold */
+ plic_set_s_thresh(target_hart, 0);
+
+ return 0;
+}
+
+int plic_cold_irqchip_init(unsigned long base,
+ u32 num_sources, u32 hart_count)
+{
+ int i;
+
+ plic_hart_count = hart_count;
+ plic_num_sources = num_sources;
+ plic_base = (void *)base;
+
+ /* Configure default priorities of all IRQs */
+ for (i = 0; i < plic_num_sources; i++)
+ plic_set_priority(i, 1);
+
+ return 0;
+}
diff --git a/plat/common/objects.mk b/plat/common/objects.mk
new file mode 100644
index 0000000..18fcd0c
--- /dev/null
+++ b/plat/common/objects.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-y += fdt.o
diff --git a/plat/common/serial/objects.mk b/plat/common/serial/objects.mk
new file mode 100644
index 0000000..61d5d37
--- /dev/null
+++ b/plat/common/serial/objects.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_SERIAL_UART8250) += serial/uart8250.o
+plat-common-objs-$(PLAT_SERIAL_SIFIVE_UART) += serial/sifive-uart.o
diff --git a/plat/common/serial/sifive-uart.c b/plat/common/serial/sifive-uart.c
new file mode 100644
index 0000000..50c7cad
--- /dev/null
+++ b/plat/common/serial/sifive-uart.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/serial/sifive-uart.h>
+
+#define UART_REG_TXFIFO 0
+#define UART_REG_RXFIFO 1
+#define UART_REG_TXCTRL 2
+#define UART_REG_RXCTRL 3
+#define UART_REG_IE 4
+#define UART_REG_IP 5
+#define UART_REG_DIV 6
+
+#define UART_TXFIFO_FULL 0x80000000
+#define UART_RXFIFO_EMPTY 0x80000000
+#define UART_RXFIFO_DATA 0x000000ff
+#define UART_TXCTRL_TXEN 0x1
+#define UART_RXCTRL_RXEN 0x1
+
+static volatile void *uart_base;
+static u32 uart_in_freq;
+static u32 uart_baudrate;
+
+static u32 get_reg(u32 num)
+{
+ return readl(uart_base + (num * 0x4));
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ writel(val, uart_base + (num * 0x4));
+}
+
+void sifive_uart_putc(char ch)
+{
+ while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL);
+
+ set_reg(UART_REG_TXFIFO, ch);
+}
+
+char sifive_uart_getc(void)
+{
+ u32 ret = get_reg(UART_REG_RXFIFO);
+ if (!(ret & UART_RXFIFO_EMPTY))
+ return ret & UART_RXFIFO_DATA;
+ return 0;
+}
+
+int sifive_uart_init(unsigned long base,
+ u32 in_freq, u32 baudrate)
+{
+ uart_base = (volatile void *)base;
+ uart_in_freq = in_freq;
+ uart_baudrate = baudrate;
+
+ /* Configure baudrate */
+ set_reg(UART_REG_DIV, (in_freq / baudrate) - 1);
+ /* Disable interrupts */
+ set_reg(UART_REG_IE, 0);
+ /* Enable TX */
+ set_reg(UART_REG_TXCTRL, UART_TXCTRL_TXEN);
+ /* Enable Rx */
+ set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
+
+ return 0;
+}
diff --git a/plat/common/serial/uart8250.c b/plat/common/serial/uart8250.c
new file mode 100644
index 0000000..7a99045
--- /dev/null
+++ b/plat/common/serial/uart8250.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/serial/uart8250.h>
+
+#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
+#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
+#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
+#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
+#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */
+#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */
+#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */
+#define UART_LCR_OFFSET 3 /* Out: Line Control Register */
+#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */
+#define UART_LSR_OFFSET 5 /* In: Line Status Register */
+#define UART_MSR_OFFSET 6 /* In: Modem Status Register */
+#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
+#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
+
+#define UART_LSR_FIFOE 0x80 /* Fifo error */
+#define UART_LSR_TEMT 0x40 /* Transmitter empty */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI 0x10 /* Break interrupt indicator */
+#define UART_LSR_FE 0x08 /* Frame error indicator */
+#define UART_LSR_PE 0x04 /* Parity error indicator */
+#define UART_LSR_OE 0x02 /* Overrun error indicator */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
+
+static volatile void *uart8250_base;
+static u32 uart8250_in_freq;
+static u32 uart8250_baudrate;
+static u32 uart8250_reg_width;
+static u32 uart8250_reg_shift;
+
+static u32 get_reg(u32 num)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ return readb(uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ return readw(uart8250_base + offset);
+ else
+ return readl(uart8250_base + offset);
+}
+
+static void set_reg(u32 num, u32 val)
+{
+ u32 offset = num << uart8250_reg_shift;
+
+ if (uart8250_reg_width == 1)
+ writeb(val, uart8250_base + offset);
+ else if (uart8250_reg_width == 2)
+ writew(val, uart8250_base + offset);
+ else
+ writel(val, uart8250_base + offset);
+}
+
+void uart8250_putc(char ch)
+{
+ while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0);
+
+ set_reg(UART_THR_OFFSET, ch);
+}
+
+char uart8250_getc(void)
+{
+ if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
+ return get_reg(UART_RBR_OFFSET);
+ return 0;
+}
+
+int uart8250_init(unsigned long base,
+ u32 in_freq, u32 baudrate,
+ u32 reg_shift, u32 reg_width)
+{
+ u16 bdiv;
+
+ uart8250_base = (volatile void *)base;
+ uart8250_reg_shift = reg_shift;
+ uart8250_reg_width = reg_width;
+ uart8250_in_freq = in_freq;
+ uart8250_baudrate = baudrate;
+
+ bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
+
+ /* Disable all interrupts */
+ set_reg(UART_IER_OFFSET, 0x00);
+ /* Enable DLAB */
+ set_reg(UART_LCR_OFFSET, 0x80);
+ /* Set divisor low byte */
+ set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+ /* Set divisor high byte */
+ set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+ /* 8 bits, no parity, one stop bit */
+ set_reg(UART_LCR_OFFSET, 0x03);
+ /* Enable FIFO */
+ set_reg(UART_FCR_OFFSET, 0x01);
+ /* No modem control DTR RTS */
+ set_reg(UART_MCR_OFFSET, 0x00);
+ /* Clear line status */
+ get_reg(UART_LSR_OFFSET);
+ /* Read receive buffer */
+ get_reg(UART_RBR_OFFSET);
+ /* Set scratchpad */
+ set_reg(UART_SCR_OFFSET, 0x00);
+
+ return 0;
+}
diff --git a/plat/common/sys/clint.c b/plat/common/sys/clint.c
new file mode 100644
index 0000000..b6c6e9b
--- /dev/null
+++ b/plat/common/sys/clint.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_atomic.h>
+#include <plat/sys/clint.h>
+
+static u32 clint_ipi_hart_count;
+static volatile void *clint_ipi_base;
+static volatile u32 *clint_ipi;
+
+void clint_ipi_inject(u32 target_hart, u32 source_hart)
+{
+ if ((clint_ipi_hart_count <= target_hart) ||
+ (clint_ipi_hart_count <= source_hart))
+ return;
+
+ /* Set CLINT IPI */
+ __io_bw();
+ atomic_raw_xchg_uint(&clint_ipi[target_hart], 1);
+}
+
+void clint_ipi_sync(u32 target_hart, u32 source_hart)
+{
+ u32 target_ipi, incoming_ipi;
+
+ if ((clint_ipi_hart_count <= target_hart) ||
+ (clint_ipi_hart_count <= source_hart))
+ return;
+
+ /* Wait until target HART has handled IPI */
+ incoming_ipi = 0;
+ while (1) {
+ target_ipi = readl(&clint_ipi[target_hart]);
+ if (!target_ipi)
+ break;
+
+ __io_bw();
+ incoming_ipi |=
+ atomic_raw_xchg_uint(&clint_ipi[source_hart], 0);
+ }
+
+ if (incoming_ipi) {
+ __io_bw();
+ atomic_raw_xchg_uint(&clint_ipi[source_hart], incoming_ipi);
+ }
+}
+
+void clint_ipi_clear(u32 target_hart)
+{
+ if (clint_ipi_hart_count <= target_hart)
+ return;
+
+ /* Clear CLINT IPI */
+ __io_bw();
+ atomic_raw_xchg_uint(&clint_ipi[target_hart], 0);
+}
+
+int clint_warm_ipi_init(u32 target_hart)
+{
+ if (clint_ipi_hart_count <= target_hart ||
+ !clint_ipi_base)
+ return -1;
+
+ /* Clear CLINT IPI */
+ clint_ipi_clear(target_hart);
+
+ return 0;
+}
+
+int clint_cold_ipi_init(unsigned long base, u32 hart_count)
+{
+ /* Figure-out CLINT IPI register address */
+ clint_ipi_hart_count = hart_count;
+ clint_ipi_base = (void *)base;
+ clint_ipi = (u32 *)clint_ipi_base;
+
+ return 0;
+}
+
+static u32 clint_time_hart_count;
+static volatile void *clint_time_base;
+static volatile u64 *clint_time_val;
+static volatile u64 *clint_time_cmp;
+
+u64 clint_timer_value(void)
+{
+ return readq_relaxed(clint_time_val);
+}
+
+void clint_timer_event_stop(u32 target_hart)
+{
+ if (clint_time_hart_count <= target_hart)
+ return;
+
+ /* Clear CLINT Time Compare */
+ writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
+}
+
+void clint_timer_event_start(u32 target_hart, u64 next_event)
+{
+ if (clint_time_hart_count <= target_hart)
+ return;
+
+ /* Program CLINT Time Compare */
+ writeq_relaxed(next_event, &clint_time_cmp[target_hart]);
+}
+
+int clint_warm_timer_init(u32 target_hart)
+{
+ if (clint_time_hart_count <= target_hart ||
+ !clint_time_base)
+ return -1;
+
+ /* Clear CLINT Time Compare */
+ writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
+
+ return 0;
+}
+
+int clint_cold_timer_init(unsigned long base, u32 hart_count)
+{
+ /* Figure-out CLINT Time register address */
+ clint_time_hart_count = hart_count;
+ clint_time_base = (void *)base;
+ clint_time_val = (u64 *)(clint_time_base + 0xbff8);
+ clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
+
+ return 0;
+}
diff --git a/plat/common/sys/objects.mk b/plat/common/sys/objects.mk
new file mode 100644
index 0000000..451adbb
--- /dev/null
+++ b/plat/common/sys/objects.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_SYS_CLINT) += sys/clint.o
diff --git a/plat/qemu/virt/config.mk b/plat/qemu/virt/config.mk
new file mode 100644
index 0000000..3e33157
--- /dev/null
+++ b/plat/qemu/virt/config.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Essential defines required by SBI platform
+plat-cppflags-y = -DPLAT_NAME="QEMU Virt Machine"
+plat-cppflags-y+= -DPLAT_HART_COUNT=8
+plat-cppflags-y+= -DPLAT_HART_STACK_SIZE=8192
+plat-cppflags-y+= -DPLAT_TEXT_START=0x80000000
+
+# Compiler flags
+plat-cflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-asflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-ldflags-y =
+
+# Common drivers to enable
+PLAT_IRQCHIP_PLIC=y
+PLAT_SERIAL_UART8250=y
+PLAT_SYS_CLINT=y
+
+# Blobs to build
+FW_JUMP=y
+FW_JUMP_ADDR=0x80200000
+FW_JUMP_FDT_OFFSET=0x2000000
+FW_PAYLOAD=y
+FW_PAYLOAD_FDT_OFFSET=0x2000000
diff --git a/plat/qemu/virt/objects.mk b/plat/qemu/virt/objects.mk
new file mode 100644
index 0000000..03ee2fe
--- /dev/null
+++ b/plat/qemu/virt/objects.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-objs-y += platform.o
diff --git a/plat/qemu/virt/platform.c b/plat/qemu/virt/platform.c
new file mode 100644
index 0000000..e59cdfd
--- /dev/null
+++ b/plat/qemu/virt/platform.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+#include <plat/irqchip/plic.h>
+#include <plat/serial/uart8250.h>
+#include <plat/sys/clint.h>
+
+#define VIRT_TEST_ADDR 0x100000
+
+#define VIRT_CLINT_ADDR 0x2000000
+
+#define VIRT_PLIC_ADDR 0xc000000
+#define VIRT_PLIC_NUM_SOURCES 127
+#define VIRT_PLIC_NUM_PRIORITIES 7
+
+#define VIRT_UART16550_ADDR 0x10000000
+
+static int virt_cold_final_init(void)
+{
+ return plic_fdt_fixup(sbi_scratch_thishart_arg1_ptr(), "riscv,plic0");
+}
+
+static u32 virt_pmp_region_count(u32 target_hart)
+{
+ return 1;
+}
+
+static int virt_pmp_region_info(u32 target_hart, u32 index,
+ ulong *prot, ulong *addr, ulong *log2size)
+{
+ int ret = 0;
+
+ switch (index) {
+ case 0:
+ *prot = PMP_R | PMP_W | PMP_X;
+ *addr = 0;
+ *log2size = __riscv_xlen;
+ break;
+ default:
+ ret = -1;
+ break;
+ };
+
+ return ret;
+}
+
+static int virt_console_init(void)
+{
+ return uart8250_init(VIRT_UART16550_ADDR,
+ 1843200, 115200, 0, 1);
+}
+
+static int virt_cold_irqchip_init(void)
+{
+ return plic_cold_irqchip_init(VIRT_PLIC_ADDR,
+ VIRT_PLIC_NUM_SOURCES,
+ PLAT_HART_COUNT);
+}
+
+static int virt_cold_ipi_init(void)
+{
+ return clint_cold_ipi_init(VIRT_CLINT_ADDR,
+ PLAT_HART_COUNT);
+}
+
+static int virt_cold_timer_init(void)
+{
+ return clint_cold_timer_init(VIRT_CLINT_ADDR,
+ PLAT_HART_COUNT);
+}
+
+static int virt_system_down(u32 type)
+{
+ /* For now nothing to do. */
+ return 0;
+}
+
+struct sbi_platform platform = {
+ .name = STRINGIFY(PLAT_NAME),
+ .features = SBI_PLATFORM_HAS_MMIO_TIMER_VALUE,
+ .hart_count = PLAT_HART_COUNT,
+ .hart_stack_size = PLAT_HART_STACK_SIZE,
+ .pmp_region_count = virt_pmp_region_count,
+ .pmp_region_info = virt_pmp_region_info,
+ .cold_final_init = virt_cold_final_init,
+ .console_putc = uart8250_putc,
+ .console_getc = uart8250_getc,
+ .console_init = virt_console_init,
+ .cold_irqchip_init = virt_cold_irqchip_init,
+ .warm_irqchip_init = plic_warm_irqchip_init,
+ .ipi_inject = clint_ipi_inject,
+ .ipi_sync = clint_ipi_sync,
+ .ipi_clear = clint_ipi_clear,
+ .warm_ipi_init = clint_warm_ipi_init,
+ .cold_ipi_init = virt_cold_ipi_init,
+ .timer_value = clint_timer_value,
+ .timer_event_stop = clint_timer_event_stop,
+ .timer_event_start = clint_timer_event_start,
+ .warm_timer_init = clint_warm_timer_init,
+ .cold_timer_init = virt_cold_timer_init,
+ .system_reboot = virt_system_down,
+ .system_shutdown = virt_system_down
+};
diff --git a/plat/sifive/hifive_u540/config.mk b/plat/sifive/hifive_u540/config.mk
new file mode 100644
index 0000000..fe5e040
--- /dev/null
+++ b/plat/sifive/hifive_u540/config.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Essential defines required by SBI platform
+plat-cppflags-y = -DPLAT_NAME="SiFive HiFive U540"
+plat-cppflags-y+= -DPLAT_HART_COUNT=1
+plat-cppflags-y+= -DPLAT_HART_STACK_SIZE=8192
+plat-cppflags-y+= -DPLAT_TEXT_START=0x80000000
+
+# Compiler flags
+plat-cflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-asflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-ldflags-y =
+
+# Common drivers to enable
+PLAT_IRQCHIP_PLIC=y
+PLAT_SERIAL_SIFIVE_UART=y
+PLAT_SYS_CLINT=y
+
+# Blobs to build
+FW_JUMP=y
+FW_JUMP_ADDR=0x80200000
+FW_JUMP_FDT_OFFSET=0x2000000
+FW_PAYLOAD=y
+FW_PAYLOAD_FDT_OFFSET=0x2000000
diff --git a/plat/sifive/hifive_u540/objects.mk b/plat/sifive/hifive_u540/objects.mk
new file mode 100644
index 0000000..03ee2fe
--- /dev/null
+++ b/plat/sifive/hifive_u540/objects.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-objs-y += platform.o
diff --git a/plat/sifive/hifive_u540/platform.c b/plat/sifive/hifive_u540/platform.c
new file mode 100644
index 0000000..a4a401e
--- /dev/null
+++ b/plat/sifive/hifive_u540/platform.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+#include <plat/irqchip/plic.h>
+#include <plat/serial/sifive-uart.h>
+#include <plat/sys/clint.h>
+
+#define SIFIVE_U_SYS_CLK 1000000000
+#define SIFIVE_U_PERIPH_CLK (SIFIVE_U_SYS_CLK / 2)
+
+#define SIFIVE_U_CLINT_ADDR 0x2000000
+
+#define SIFIVE_U_PLIC_ADDR 0xc000000
+#define SIFIVE_U_PLIC_NUM_SOURCES 0x35
+#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
+
+#define SIFIVE_U_UART0_ADDR 0x10013000
+#define SIFIVE_U_UART1_ADDR 0x10023000
+
+static int sifive_u_cold_final_init(void)
+{
+ return plic_fdt_fixup(sbi_scratch_thishart_arg1_ptr(), "riscv,plic0");
+}
+
+static u32 sifive_u_pmp_region_count(u32 target_hart)
+{
+ return 1;
+}
+
+static int sifive_u_pmp_region_info(u32 target_hart, u32 index,
+ ulong *prot, ulong *addr, ulong *log2size)
+{
+ int ret = 0;
+
+ switch (index) {
+ case 0:
+ *prot = PMP_R | PMP_W | PMP_X;
+ *addr = 0;
+ *log2size = __riscv_xlen;
+ break;
+ default:
+ ret = -1;
+ break;
+ };
+
+ return ret;
+}
+
+static int sifive_u_console_init(void)
+{
+ return sifive_uart_init(SIFIVE_U_UART0_ADDR,
+ SIFIVE_U_PERIPH_CLK, 115200);
+}
+
+static int sifive_u_cold_irqchip_init(void)
+{
+ return plic_cold_irqchip_init(SIFIVE_U_PLIC_ADDR,
+ SIFIVE_U_PLIC_NUM_SOURCES,
+ PLAT_HART_COUNT);
+}
+
+static int sifive_u_cold_ipi_init(void)
+{
+ return clint_cold_ipi_init(SIFIVE_U_CLINT_ADDR,
+ PLAT_HART_COUNT);
+}
+
+static int sifive_u_cold_timer_init(void)
+{
+ return clint_cold_timer_init(SIFIVE_U_CLINT_ADDR,
+ PLAT_HART_COUNT);
+}
+
+static int sifive_u_system_down(u32 type)
+{
+ /* For now nothing to do. */
+ return 0;
+}
+
+struct sbi_platform platform = {
+ .name = STRINGIFY(PLAT_NAME),
+ .features = SBI_PLATFORM_HAS_MMIO_TIMER_VALUE,
+ .hart_count = PLAT_HART_COUNT,
+ .hart_stack_size = PLAT_HART_STACK_SIZE,
+ .pmp_region_count = sifive_u_pmp_region_count,
+ .pmp_region_info = sifive_u_pmp_region_info,
+ .cold_final_init = sifive_u_cold_final_init,
+ .console_putc = sifive_uart_putc,
+ .console_getc = sifive_uart_getc,
+ .console_init = sifive_u_console_init,
+ .cold_irqchip_init = sifive_u_cold_irqchip_init,
+ .warm_irqchip_init = plic_warm_irqchip_init,
+ .ipi_inject = clint_ipi_inject,
+ .ipi_sync = clint_ipi_sync,
+ .ipi_clear = clint_ipi_clear,
+ .warm_ipi_init = clint_warm_ipi_init,
+ .cold_ipi_init = sifive_u_cold_ipi_init,
+ .timer_value = clint_timer_value,
+ .timer_event_stop = clint_timer_event_stop,
+ .timer_event_start = clint_timer_event_start,
+ .warm_timer_init = clint_warm_timer_init,
+ .cold_timer_init = sifive_u_cold_timer_init,
+ .system_reboot = sifive_u_system_down,
+ .system_shutdown = sifive_u_system_down
+};