Ver código fonte

Initial commit.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Anup Patel 5 anos atrás
commit
9e8ff05cb6
67 arquivos alterados com 6084 adições e 0 exclusões
  1. 37 0
      LICENSE
  2. 296 0
      Makefile
  3. 37 0
      README.md
  4. 305 0
      blob/fw_common.S
  5. 89 0
      blob/fw_common.ldS
  6. 44 0
      blob/fw_jump.S
  7. 16 0
      blob/fw_jump.elf.ldS
  8. 46 0
      blob/fw_payload.S
  9. 26 0
      blob/fw_payload.elf.ldS
  10. 29 0
      blob/objects.mk
  11. 244 0
      include/sbi/riscv_asm.h
  12. 38 0
      include/sbi/riscv_atomic.h
  13. 53 0
      include/sbi/riscv_barrier.h
  14. 423 0
      include/sbi/riscv_encoding.h
  15. 109 0
      include/sbi/riscv_io.h
  16. 33 0
      include/sbi/riscv_locks.h
  17. 44 0
      include/sbi/sbi_bits.h
  18. 37 0
      include/sbi/sbi_console.h
  19. 43 0
      include/sbi/sbi_const.h
  20. 26 0
      include/sbi/sbi_ecall.h
  21. 27 0
      include/sbi/sbi_emulate_csr.h
  22. 25 0
      include/sbi/sbi_error.h
  23. 41 0
      include/sbi/sbi_hart.h
  24. 22 0
      include/sbi/sbi_illegal_insn.h
  25. 19 0
      include/sbi/sbi_init.h
  26. 33 0
      include/sbi/sbi_ipi.h
  27. 258 0
      include/sbi/sbi_platform.h
  28. 35 0
      include/sbi/sbi_scratch.h
  29. 31 0
      include/sbi/sbi_system.h
  30. 30 0
      include/sbi/sbi_timer.h
  31. 57 0
      include/sbi/sbi_trap.h
  32. 57 0
      include/sbi/sbi_types.h
  33. 111 0
      include/sbi/sbi_unpriv.h
  34. 23 0
      lib/objects.mk
  35. 275 0
      lib/riscv_asm.c
  36. 152 0
      lib/riscv_atomic.c
  37. 46 0
      lib/riscv_locks.c
  38. 367 0
      lib/sbi_console.c
  39. 98 0
      lib/sbi_ecall.c
  40. 157 0
      lib/sbi_emulate_csr.c
  41. 294 0
      lib/sbi_hart.c
  42. 190 0
      lib/sbi_illegal_insn.c
  43. 162 0
      lib/sbi_init.c
  44. 82 0
      lib/sbi_ipi.c
  45. 47 0
      lib/sbi_system.c
  46. 78 0
      lib/sbi_timer.c
  47. 110 0
      lib/sbi_trap.c
  48. 314 0
      plat/common/fdt.c
  49. 73 0
      plat/common/include/plat/fdt.h
  50. 22 0
      plat/common/include/plat/irqchip/plic.h
  51. 22 0
      plat/common/include/plat/serial/sifive-uart.h
  52. 23 0
      plat/common/include/plat/serial/uart8250.h
  53. 35 0
      plat/common/include/plat/sys/clint.h
  54. 10 0
      plat/common/irqchip/objects.mk
  55. 118 0
      plat/common/irqchip/plic.c
  56. 10 0
      plat/common/objects.mk
  57. 11 0
      plat/common/serial/objects.mk
  58. 73 0
      plat/common/serial/sifive-uart.c
  59. 117 0
      plat/common/serial/uart8250.c
  60. 136 0
      plat/common/sys/clint.c
  61. 10 0
      plat/common/sys/objects.mk
  62. 31 0
      plat/qemu/virt/config.mk
  63. 10 0
      plat/qemu/virt/objects.mk
  64. 112 0
      plat/qemu/virt/platform.c
  65. 31 0
      plat/sifive/hifive_u540/config.mk
  66. 10 0
      plat/sifive/hifive_u540/objects.mk
  67. 114 0
      plat/sifive/hifive_u540/platform.c

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

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

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

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

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

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

+ 16 - 0
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"
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 275 - 0
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;
+}

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

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

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

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

+ 157 - 0
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;
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 118 - 0
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;
+}

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

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

+ 73 - 0
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;
+}

+ 117 - 0
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;
+}

+ 136 - 0
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;
+}

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

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

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

+ 112 - 0
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
+};

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

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

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