Initial commit.
authorAnup Patel <anup.patel@wdc.com>
Tue, 11 Dec 2018 13:54:06 +0000 (19:24 +0530)
committerAnup Patel <anup@brainfault.org>
Tue, 11 Dec 2018 13:54:06 +0000 (19:24 +0530)
Signed-off-by: Anup Patel <anup.patel@wdc.com>
67 files changed:
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
blob/fw_common.S [new file with mode: 0644]
blob/fw_common.ldS [new file with mode: 0644]
blob/fw_jump.S [new file with mode: 0644]
blob/fw_jump.elf.ldS [new file with mode: 0644]
blob/fw_payload.S [new file with mode: 0644]
blob/fw_payload.elf.ldS [new file with mode: 0644]
blob/objects.mk [new file with mode: 0644]
include/sbi/riscv_asm.h [new file with mode: 0644]
include/sbi/riscv_atomic.h [new file with mode: 0644]
include/sbi/riscv_barrier.h [new file with mode: 0644]
include/sbi/riscv_encoding.h [new file with mode: 0644]
include/sbi/riscv_io.h [new file with mode: 0644]
include/sbi/riscv_locks.h [new file with mode: 0644]
include/sbi/sbi_bits.h [new file with mode: 0644]
include/sbi/sbi_console.h [new file with mode: 0644]
include/sbi/sbi_const.h [new file with mode: 0644]
include/sbi/sbi_ecall.h [new file with mode: 0644]
include/sbi/sbi_emulate_csr.h [new file with mode: 0644]
include/sbi/sbi_error.h [new file with mode: 0644]
include/sbi/sbi_hart.h [new file with mode: 0644]
include/sbi/sbi_illegal_insn.h [new file with mode: 0644]
include/sbi/sbi_init.h [new file with mode: 0644]
include/sbi/sbi_ipi.h [new file with mode: 0644]
include/sbi/sbi_platform.h [new file with mode: 0644]
include/sbi/sbi_scratch.h [new file with mode: 0644]
include/sbi/sbi_system.h [new file with mode: 0644]
include/sbi/sbi_timer.h [new file with mode: 0644]
include/sbi/sbi_trap.h [new file with mode: 0644]
include/sbi/sbi_types.h [new file with mode: 0644]
include/sbi/sbi_unpriv.h [new file with mode: 0644]
lib/objects.mk [new file with mode: 0644]
lib/riscv_asm.c [new file with mode: 0644]
lib/riscv_atomic.c [new file with mode: 0644]
lib/riscv_locks.c [new file with mode: 0644]
lib/sbi_console.c [new file with mode: 0644]
lib/sbi_ecall.c [new file with mode: 0644]
lib/sbi_emulate_csr.c [new file with mode: 0644]
lib/sbi_hart.c [new file with mode: 0644]
lib/sbi_illegal_insn.c [new file with mode: 0644]
lib/sbi_init.c [new file with mode: 0644]
lib/sbi_ipi.c [new file with mode: 0644]
lib/sbi_system.c [new file with mode: 0644]
lib/sbi_timer.c [new file with mode: 0644]
lib/sbi_trap.c [new file with mode: 0644]
plat/common/fdt.c [new file with mode: 0644]
plat/common/include/plat/fdt.h [new file with mode: 0644]
plat/common/include/plat/irqchip/plic.h [new file with mode: 0644]
plat/common/include/plat/serial/sifive-uart.h [new file with mode: 0644]
plat/common/include/plat/serial/uart8250.h [new file with mode: 0644]
plat/common/include/plat/sys/clint.h [new file with mode: 0644]
plat/common/irqchip/objects.mk [new file with mode: 0644]
plat/common/irqchip/plic.c [new file with mode: 0644]
plat/common/objects.mk [new file with mode: 0644]
plat/common/serial/objects.mk [new file with mode: 0644]
plat/common/serial/sifive-uart.c [new file with mode: 0644]
plat/common/serial/uart8250.c [new file with mode: 0644]
plat/common/sys/clint.c [new file with mode: 0644]
plat/common/sys/objects.mk [new file with mode: 0644]
plat/qemu/virt/config.mk [new file with mode: 0644]
plat/qemu/virt/objects.mk [new file with mode: 0644]
plat/qemu/virt/platform.c [new file with mode: 0644]
plat/sifive/hifive_u540/config.mk [new file with mode: 0644]
plat/sifive/hifive_u540/objects.mk [new file with mode: 0644]
plat/sifive/hifive_u540/platform.c [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..1cdc70e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,37 @@
+Copyright (c) 2018 Western Digital Corporation or its affiliates.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies,
+either expressed or implied, of the <project name> project.
+
+--------------
+
+Note:
+Individual files contain the following tag instead of the full license text.
+
+::
+
+    SPDX-License-Identifier:    BSD-2-Clause
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ff41674
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,296 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Current Version
+MAJOR = 0
+MINOR = 1
+
+# Select Make Options:
+# o  Do not use make's built-in rules and variables
+# o  Do not print "Entering directory ...";
+MAKEFLAGS += -rR --no-print-directory
+
+# Find out source, build, and install directories
+src_dir=$(CURDIR)
+ifdef O
+ build_dir=$(shell readlink -f $(O))
+else
+ build_dir=$(CURDIR)/build
+endif
+ifeq ($(build_dir),$(CURDIR))
+$(error Build directory is same as source directory.)
+endif
+ifdef I
+ install_dir=$(shell readlink -f $(I))
+else
+ install_dir=$(CURDIR)/install
+endif
+ifeq ($(install_dir),$(CURDIR))
+$(error Install directory is same as source directory.)
+endif
+ifeq ($(install_dir),$(build_dir))
+$(error Install directory is same as build directory.)
+endif
+
+# Check if verbosity is ON for build process
+VERBOSE_DEFAULT    := 0
+CMD_PREFIX_DEFAULT := @
+ifdef VERBOSE
+       ifeq ("$(origin VERBOSE)", "command line")
+               VB := $(VERBOSE)
+       else
+               VB := $(VERBOSE_DEFAULT)
+       endif
+else
+       VB := $(VERBOSE_DEFAULT)
+endif
+ifeq ($(VB), 1)
+       override V :=
+else
+       override V := $(CMD_PREFIX_DEFAULT)
+endif
+
+# Setup path of directories
+export plat_subdir=plat/$(PLAT)
+export plat_dir=$(CURDIR)/$(plat_subdir)
+export plat_common_dir=$(CURDIR)/plat/common
+export include_dir=$(CURDIR)/include
+export lib_dir=$(CURDIR)/lib
+export blob_dir=$(CURDIR)/blob
+
+# Setup list of objects.mk files
+ifdef PLAT
+plat-object-mks=$(shell if [ -d $(plat_dir) ]; then find $(plat_dir) -iname "objects.mk" | sort -r; fi)
+plat-common-object-mks=$(shell if [ -d $(plat_common_dir) ]; then find $(plat_common_dir) -iname "objects.mk" | sort -r; fi)
+endif
+lib-object-mks=$(shell if [ -d $(lib_dir) ]; then find $(lib_dir) -iname "objects.mk" | sort -r; fi)
+blob-object-mks=$(shell if [ -d $(blob_dir) ]; then find $(blob_dir) -iname "objects.mk" | sort -r; fi)
+
+# Include platform specifig config.mk
+ifdef PLAT
+include $(plat_dir)/config.mk
+endif
+
+# Include all object.mk files
+ifdef PLAT
+include $(plat-object-mks)
+include $(plat-common-object-mks)
+endif
+include $(lib-object-mks)
+include $(blob-object-mks)
+
+# Setup list of objects
+lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj))
+ifdef PLAT
+plat-objs-path-y=$(foreach obj,$(plat-objs-y),$(build_dir)/$(plat_subdir)/$(obj))
+plat-common-objs-path-y=$(foreach obj,$(plat-common-objs-y),$(build_dir)/plat/common/$(obj))
+blob-bins-path-y=$(foreach bin,$(blob-bins-y),$(build_dir)/$(plat_subdir)/blob/$(bin))
+endif
+blob-elfs-path-y=$(blob-bins-path-y:.bin=.elf)
+blob-objs-path-y=$(blob-bins-path-y:.bin=.o)
+
+# Setup list of deps files for objects
+deps-y=$(plat-objs-path-y:.o=.dep)
+deps-y+=$(plat-common-objs-path-y:.o=.dep)
+deps-y+=$(lib-objs-path-y:.o=.dep)
+deps-y+=$(blob-objs-path-y:.o=.dep)
+
+# Setup compilation environment
+cpp=$(CROSS_COMPILE)cpp
+cppflags+=-DOPENSBI_MAJOR=$(MAJOR)
+cppflags+=-DOPENSBI_MINOR=$(MINOR)
+cppflags+=-I$(plat_dir)/include
+cppflags+=-I$(plat_common_dir)/include
+cppflags+=-I$(include_dir)
+cppflags+=$(plat-cppflags-y)
+cppflags+=$(blob-cppflags-y)
+cc=$(CROSS_COMPILE)gcc
+cflags=-g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
+cflags+=-fno-omit-frame-pointer -fno-optimize-sibling-calls
+cflags+=-mno-save-restore -mstrict-align
+cflags+=$(cppflags)
+cflags+=$(plat-cflags-y)
+cflags+=$(blob-cflags-y)
+cflags+=$(EXTRA_CFLAGS)
+as=$(CROSS_COMPILE)gcc
+asflags=-g -Wall -nostdlib -D__ASSEMBLY__
+asflags+=-fno-omit-frame-pointer -fno-optimize-sibling-calls
+asflags+=-mno-save-restore -mstrict-align
+asflags+=$(cppflags)
+asflags+=$(plat-asflags-y)
+asflags+=$(blob-asflags-y)
+asflags+=$(EXTRA_ASFLAGS)
+ar=$(CROSS_COMPILE)ar
+arflags=rcs
+ld=$(CROSS_COMPILE)gcc
+ldflags=-g -Wall -nostdlib -Wl,--build-id=none
+ldflags+=$(plat-ldflags-y)
+ldflags+=$(blob-ldflags-y)
+merge=$(CROSS_COMPILE)ld
+mergeflags=-r
+objcopy=$(CROSS_COMPILE)objcopy
+
+# Setup functions for compilation
+define dynamic_flags
+-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
+endef
+merge_objs = $(V)mkdir -p `dirname $(1)`; \
+            echo " MERGE     $(subst $(build_dir)/,,$(1))"; \
+            $(merge) $(mergeflags) $(2) -o $(1)
+merge_deps = $(V)mkdir -p `dirname $(1)`; \
+            echo " MERGE-DEP $(subst $(build_dir)/,,$(1))"; \
+            cat $(2) > $(1)
+copy_file =  $(V)mkdir -p `dirname $(1)`; \
+            echo " COPY      $(subst $(build_dir)/,,$(1))"; \
+            cp -f $(2) $(1)
+inst_file =  $(V)mkdir -p `dirname $(1)`; \
+            echo " INSTALL   $(subst $(install_dir)/,,$(1))"; \
+            cp -f $(2) $(1)
+inst_file_list = $(V)if [ ! -z "$(3)" ]; then \
+            mkdir -p $(1); \
+            for f in $(3) ; do \
+            echo " INSTALL   "$(2)"/"`basename $$f`; \
+            cp -f $$f $(1); \
+            done \
+            fi
+inst_header_dir =  $(V)mkdir -p $(1); \
+            echo " INSTALL   $(subst $(install_dir)/,,$(1))"; \
+            cp -rf $(2) $(1)
+compile_cpp = $(V)mkdir -p `dirname $(1)`; \
+            echo " CPP       $(subst $(build_dir)/,,$(1))"; \
+            $(cpp) $(cppflags) $(2) | grep -v "\#" > $(1)
+compile_cc_dep = $(V)mkdir -p `dirname $(1)`; \
+            echo " CC-DEP    $(subst $(build_dir)/,,$(1))"; \
+            echo -n `dirname $(1)`/ > $(1) && \
+            $(cc) $(cflags) $(call dynamic_flags,$(1),$(2))   \
+              -MM $(2) >> $(1) || rm -f $(1)
+compile_cc = $(V)mkdir -p `dirname $(1)`; \
+            echo " CC        $(subst $(build_dir)/,,$(1))"; \
+            $(cc) $(cflags) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_as_dep = $(V)mkdir -p `dirname $(1)`; \
+            echo " AS-DEP    $(subst $(build_dir)/,,$(1))"; \
+            echo -n `dirname $(1)`/ > $(1) && \
+            $(as) $(asflags) $(call dynamic_flags,$(1),$(2))  \
+              -MM $(2) >> $(1) || rm -f $(1)
+compile_as = $(V)mkdir -p `dirname $(1)`; \
+            echo " AS        $(subst $(build_dir)/,,$(1))"; \
+            $(as) $(asflags) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
+compile_ld = $(V)mkdir -p `dirname $(1)`; \
+            echo " LD        $(subst $(build_dir)/,,$(1))"; \
+            $(ld) $(3) $(ldflags) -Wl,-T$(2) -o $(1)
+compile_ar = $(V)mkdir -p `dirname $(1)`; \
+            echo " AR        $(subst $(build_dir)/,,$(1))"; \
+            $(ar) $(arflags) $(1) $(2)
+compile_objcopy = $(V)mkdir -p `dirname $(1)`; \
+            echo " OBJCOPY   $(subst $(build_dir)/,,$(1))"; \
+            $(objcopy) -S -O binary $(2) $(1)
+
+targets-y  = $(build_dir)/lib/libsbi.a
+ifdef PLAT
+targets-y += $(build_dir)/$(plat_subdir)/lib/libplatsbi.a
+endif
+targets-y += $(blob-bins-path-y)
+
+# Default rule "make" should always be first rule
+.PHONY: all
+all: $(targets-y)
+
+# Preserve all intermediate files
+.SECONDARY:
+
+$(build_dir)/%.bin: $(build_dir)/%.elf
+       $(call compile_objcopy,$@,$<)
+
+$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(plat_subdir)/lib/libplatsbi.a
+       $(call compile_ld,$@,$@.ld,$< $(build_dir)/$(plat_subdir)/lib/libplatsbi.a)
+
+$(build_dir)/$(plat_subdir)/%.ld: $(src_dir)/%.ldS
+       $(call compile_cpp,$@,$<)
+
+$(build_dir)/lib/libsbi.a: $(lib-objs-path-y)
+       $(call compile_ar,$@,$^)
+
+$(build_dir)/$(plat_subdir)/lib/libplatsbi.a: $(lib-objs-path-y) $(plat-common-objs-path-y) $(plat-objs-path-y)
+       $(call compile_ar,$@,$^)
+
+$(build_dir)/%.dep: $(src_dir)/%.c
+       $(call compile_cc_dep,$@,$<)
+
+$(build_dir)/%.o: $(src_dir)/%.c
+       $(call compile_cc,$@,$<)
+
+$(build_dir)/%.dep: $(src_dir)/%.S
+       $(call compile_as_dep,$@,$<)
+
+$(build_dir)/%.o: $(src_dir)/%.S
+       $(call compile_as,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.dep: $(src_dir)/%.c
+       $(call compile_cc_dep,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.o: $(src_dir)/%.c
+       $(call compile_cc,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.dep: $(src_dir)/%.S
+       $(call compile_as_dep,$@,$<)
+
+$(build_dir)/$(plat_subdir)/%.o: $(src_dir)/%.S
+       $(call compile_as,$@,$<)
+
+# Dependency files should only be included after default Makefile rule
+# They should not be included for any "xxxconfig" or "xxxclean" rule
+all-deps-1 = $(if $(findstring config,$(MAKECMDGOALS)),,$(deps-y))
+all-deps-2 = $(if $(findstring clean,$(MAKECMDGOALS)),,$(all-deps-1))
+-include $(all-deps-2)
+
+install_targets-y  = install_libsbi
+ifdef PLAT
+install_targets-y += install_libplatsbi
+install_targets-y += install_blobs
+endif
+
+# Rule for "make install"
+.PHONY: install
+install: $(install_targets-y)
+
+.PHONY: install_libsbi
+install_libsbi: $(build_dir)/lib/libsbi.a
+       $(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
+       $(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
+
+.PHONY: install_libplatsbi
+install_libplatsbi: $(build_dir)/$(plat_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
+       $(call inst_header_dir,$(install_dir)/$(plat_subdir)/include,$(include_dir)/sbi)
+       $(call inst_file,$(install_dir)/$(plat_subdir)/lib/libplatsbi.a,$(build_dir)/$(plat_subdir)/lib/libplatsbi.a)
+
+.PHONY: install_blobs
+install_blobs: $(build_dir)/$(plat_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(blob-bins-path-y)
+       $(call inst_file_list,$(install_dir)/$(plat_subdir)/blob,$(plat_subdir)/blob,$(blob-elfs-path-y))
+       $(call inst_file_list,$(install_dir)/$(plat_subdir)/blob,$(plat_subdir)/blob,$(blob-bins-path-y))
+
+# Rule for "make clean"
+.PHONY: clean
+clean:
+ifeq ($(build_dir),$(CURDIR)/build)
+       $(V)mkdir -p $(build_dir)
+       $(if $(V), @echo " CLEAN     $(build_dir)")
+       $(V)find $(build_dir) -maxdepth 1 -type f -exec rm -rf {} +
+endif
+
+# Rule for "make distclean"
+.PHONY: distclean
+distclean:
+ifeq ($(build_dir),$(CURDIR)/build)
+       $(if $(V), @echo " RM        $(build_dir)")
+       $(V)rm -rf $(build_dir)
+endif
+ifeq ($(install_dir),$(CURDIR)/install)
+       $(if $(V), @echo " RM        $(install_dir)")
+       $(V)rm -rf $(install_dir)
+endif
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..3892273
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+RISC-V Open Source Supervisor Binary Interface (OpenSBI)
+========================================================
+
+The RISC-V Supervisor Binary Interface (SBI) is a recommended
+interface between:
+1. platform specific firmware running in M-mode and bootloader
+   running in S-mode
+2. platform specific firmware running in M-mode and general
+   purpose operating system running in S-mode
+3. hypervisor runnng in HS-mode and general purpose operating
+   system running in VS-mode.
+
+The RISC-V SBI spec is maintained as independent project by
+RISC-V Foundation at https://github.com/riscv/riscv-sbi-doc
+
+The RISC-V OpenSBI project aims to provides an open-source and
+extensible implementation of the SBI spec. This project can be
+easily extended by RISC-V platform or RISC-V System-on-Chip vendors.
+
+
+How to Build?
+-------------
+
+Below are the steps to cross-compile and install RISC-V OpenSBI:
+
+1. Setup build environment
+$ CROSS_COMPILE=riscv64-unknown-linux-gnu-
+
+2. Build sources
+$ make PLAT=<platform_name>
+OR
+$ make PLAT=<platform_name> O=<build_directory>
+
+3. Install blobs
+$ make PLAT=<platform_name> install
+OR
+$ make PLAT=<platform_name> I=<install_directory> install
diff --git a/blob/fw_common.S b/blob/fw_common.S
new file mode 100644 (file)
index 0000000..9cc2b09
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .globl _start
+       .globl _start_warm
+_start:
+       /* Jump to warm-boot for mhartid != 0 */
+       csrr    a6, mhartid
+       blt     zero, a6, _wait_for_boot_hart
+
+       /* Zero-out BSS */
+       la      a4, _bss_start
+       la      a5, _bss_end
+_bss_zero:
+       REG_S   zero, (a4)
+       add     a4, a4, __SIZEOF_POINTER__
+       blt     a4, a5, _bss_zero
+
+       /*
+        * Relocate FDT
+        * Note: We will preserve a0 and a1 passed by
+        * previous booting stage.
+        */
+       /* Mask values in a3 and a4 */
+       li      a3, ~0xf
+       li      a4, 0xff
+       /* t1 = destinetion FDT start address */
+       add     s0, a0, zero
+       add     s1, a1, zero
+       call    fw_next_arg1
+       add     t1, a0, zero
+       add     a0, s0, zero
+       add     a1, s1, zero
+       beqz    t1, _fdt_reloc_done
+       and     t1, t1, a3
+       /* t0 = source FDT start address */
+       add     t0, a1, zero
+       and     t0, t0, a3
+       /* t2 = source FDT size in big-endian */
+       lwu     t2, 4(t0)
+       /* t3 = bit[15:8] of FDT size */
+       add     t3, t2, zero
+       srli    t3, t3, 16
+       and     t3, t3, a4
+       slli    t3, t3, 8
+       /* t4 = bit[23:16] of FDT size */
+       add     t4, t2, zero
+       srli    t4, t4, 8
+       and     t4, t4, a4
+       slli    t4, t4, 16
+       /* t5 = bit[31:24] of FDT size */
+       add     t5, t2, zero
+       and     t5, t5, a4
+       slli    t5, t5, 24
+       /* t2 = bit[7:0] of FDT size */
+       srli    t2, t2, 24
+       and     t2, t2, a4
+       /* t2 = FDT size in little-endian */
+       or      t2, t2, t3
+       or      t2, t2, t4
+       or      t2, t2, t5
+       /* t2 = destinetion FDT end address */
+       add     t2, t1, t2
+       /* FDT copy loop */
+       ble     t2, t1, _fdt_reloc_done
+_fdt_reloc_again:
+       REG_L   t3, 0(t0)
+       REG_S   t3, 0(t1)
+       add     t0, t0, __SIZEOF_POINTER__
+       add     t1, t1, __SIZEOF_POINTER__
+       blt     t1, t2, _fdt_reloc_again
+_fdt_reloc_done:
+
+       /* Update boot hart flag */
+       la      a4, _boot_hart_done
+       li      a5, 1
+       REG_S   a5, (a4)
+       j       _wait_for_boot_hart
+
+       .align  3
+_boot_hart_done:
+       RISCV_PTR       0
+       .align  3
+
+       /* Wait for boot hart */
+_wait_for_boot_hart:
+       la      a4, _boot_hart_done
+       REG_L   a5, (a4)
+       beqz    a5, _wait_for_boot_hart
+
+_start_warm:
+       /* Disable and clear all interrupts */
+       csrw    mie, zero
+       csrw    mip, zero
+
+       /* HART ID should be withing expected limit */
+       csrr    a6, mhartid
+       li      a5, PLAT_HART_COUNT
+       bge     a6, a5, _start_hang
+
+       /* Setup scratch space */
+       li      a5, PLAT_HART_STACK_SIZE
+       la      tp, _stack_end
+       mul     a5, a5, a6
+       sub     tp, tp, a5
+       li      a5, RISCV_SCRATCH_SIZE
+       sub     tp, tp, a5
+       csrw    mscratch, tp
+
+       /* Initialize scratch space */
+       REG_S   zero, RISCV_SCRATCH_TMP0_OFFSET(tp)
+       la      a4, _fw_start
+       la      a5, _fw_end
+       sub     a5, a5, a4
+       REG_S   a4, RISCV_SCRATCH_FW_START_OFFSET(tp)
+       REG_S   a5, RISCV_SCRATCH_FW_SIZE_OFFSET(tp)
+       /* Note: fw_next_arg1() uses a0, a1, and ra */
+       call    fw_next_arg1
+       REG_S   a0, RISCV_SCRATCH_NEXT_ARG1_OFFSET(tp)
+       /* Note: fw_next_addr() uses a0, a1, and ra */
+       call    fw_next_addr
+       REG_S   a0, RISCV_SCRATCH_NEXT_ADDR_OFFSET(tp)
+       li      a4, PRV_S
+       REG_S   a4, RISCV_SCRATCH_NEXT_MODE_OFFSET(tp)
+       la      a4, _start_warm
+       REG_S   a4, RISCV_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
+       la      a4, platform
+       REG_S   a4, RISCV_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
+       la      a4, _hartid_to_scratch
+       REG_S   a4, RISCV_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
+       REG_S   zero, RISCV_SCRATCH_IPI_TYPE_OFFSET(tp)
+
+       /* Setup stack */
+       add     sp, tp, zero
+
+       /* Setup trap handler */
+       la      a4, _trap_handler
+       csrw    mtvec, a4
+
+       /* Initialize SBI runtime */
+       csrr    a0, mscratch
+       call    sbi_init
+
+       /* We don't expect to reach here hence just hang */
+       j       _start_hang
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .globl _hartid_to_scratch
+_hartid_to_scratch:
+       add     sp, sp, -(2 * __SIZEOF_POINTER__)
+       REG_S   a1, (sp)
+       REG_S   a2, (__SIZEOF_POINTER__)(sp)
+       li      a1, PLAT_HART_STACK_SIZE
+       la      a2, _stack_end
+       mul     a1, a1, a0
+       sub     a2, a2, a1
+       li      a1, RISCV_SCRATCH_SIZE
+       sub     a0, a2, a1
+       REG_L   a1, (sp)
+       REG_L   a2, (__SIZEOF_POINTER__)(sp)
+       add     sp, sp, (2 * __SIZEOF_POINTER__)
+       ret
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .globl _start_hang
+_start_hang:
+       wfi
+       j       _start_hang
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .globl _trap_handler
+_trap_handler:
+       /* Swap SP and MSCRATCH */
+       csrrw   sp, mscratch, sp
+
+       /* Setup exception stack */
+       add     sp, sp, -(RISCV_TRAP_REGS_SIZE)
+
+       /* Save RA, T0, T1, and T2 */
+       REG_S   ra, RISCV_TRAP_REGS_OFFSET(ra)(sp)
+       REG_S   t0, RISCV_TRAP_REGS_OFFSET(t0)(sp)
+       REG_S   t1, RISCV_TRAP_REGS_OFFSET(t1)(sp)
+       REG_S   t2, RISCV_TRAP_REGS_OFFSET(t2)(sp)
+
+       /* Save original SP and restore MSCRATCH */
+       add     t0, sp, RISCV_TRAP_REGS_SIZE
+       csrrw   t0, mscratch, t0
+       REG_S   t0, RISCV_TRAP_REGS_OFFSET(sp)(sp)
+
+       /* Save MEPC and MSTATUS CSRs */
+       csrr    t0, mepc
+       csrr    t1, mstatus
+
+       /*
+        * Note: Fast path trap handling can be done here
+        * using SP, RA, T0, T1, and T2 registers where
+        * T0 <- MEPC
+        * T1 <- MSTATUS
+        */
+
+       /* Save MEPC and MSTATUS CSRs */
+       REG_S   t0, RISCV_TRAP_REGS_OFFSET(mepc)(sp)
+       REG_S   t1, RISCV_TRAP_REGS_OFFSET(mstatus)(sp)
+
+       /* Save all general regisers except SP, RA, T0, T1, and T2 */
+       REG_S   zero, RISCV_TRAP_REGS_OFFSET(zero)(sp)
+       REG_S   gp, RISCV_TRAP_REGS_OFFSET(gp)(sp)
+       REG_S   tp, RISCV_TRAP_REGS_OFFSET(tp)(sp)
+       REG_S   s0, RISCV_TRAP_REGS_OFFSET(s0)(sp)
+       REG_S   s1, RISCV_TRAP_REGS_OFFSET(s1)(sp)
+       REG_S   a0, RISCV_TRAP_REGS_OFFSET(a0)(sp)
+       REG_S   a1, RISCV_TRAP_REGS_OFFSET(a1)(sp)
+       REG_S   a2, RISCV_TRAP_REGS_OFFSET(a2)(sp)
+       REG_S   a3, RISCV_TRAP_REGS_OFFSET(a3)(sp)
+       REG_S   a4, RISCV_TRAP_REGS_OFFSET(a4)(sp)
+       REG_S   a5, RISCV_TRAP_REGS_OFFSET(a5)(sp)
+       REG_S   a6, RISCV_TRAP_REGS_OFFSET(a6)(sp)
+       REG_S   a7, RISCV_TRAP_REGS_OFFSET(a7)(sp)
+       REG_S   s2, RISCV_TRAP_REGS_OFFSET(s2)(sp)
+       REG_S   s3, RISCV_TRAP_REGS_OFFSET(s3)(sp)
+       REG_S   s4, RISCV_TRAP_REGS_OFFSET(s4)(sp)
+       REG_S   s5, RISCV_TRAP_REGS_OFFSET(s5)(sp)
+       REG_S   s6, RISCV_TRAP_REGS_OFFSET(s6)(sp)
+       REG_S   s7, RISCV_TRAP_REGS_OFFSET(s7)(sp)
+       REG_S   s8, RISCV_TRAP_REGS_OFFSET(s8)(sp)
+       REG_S   s9, RISCV_TRAP_REGS_OFFSET(s9)(sp)
+       REG_S   s10, RISCV_TRAP_REGS_OFFSET(s10)(sp)
+       REG_S   s11, RISCV_TRAP_REGS_OFFSET(s11)(sp)
+       REG_S   t3, RISCV_TRAP_REGS_OFFSET(t3)(sp)
+       REG_S   t4, RISCV_TRAP_REGS_OFFSET(t4)(sp)
+       REG_S   t5, RISCV_TRAP_REGS_OFFSET(t5)(sp)
+       REG_S   t6, RISCV_TRAP_REGS_OFFSET(t6)(sp)
+
+       /* Call C routine */
+       add     a0, sp, zero
+       csrr    a1, mscratch
+       call    sbi_trap_handler
+
+       /* Restore all general regisers except SP, RA, T0, T1, T2, and T3 */
+       REG_L   gp, RISCV_TRAP_REGS_OFFSET(gp)(sp)
+       REG_L   tp, RISCV_TRAP_REGS_OFFSET(tp)(sp)
+       REG_L   s0, RISCV_TRAP_REGS_OFFSET(s0)(sp)
+       REG_L   s1, RISCV_TRAP_REGS_OFFSET(s1)(sp)
+       REG_L   a0, RISCV_TRAP_REGS_OFFSET(a0)(sp)
+       REG_L   a1, RISCV_TRAP_REGS_OFFSET(a1)(sp)
+       REG_L   a2, RISCV_TRAP_REGS_OFFSET(a2)(sp)
+       REG_L   a3, RISCV_TRAP_REGS_OFFSET(a3)(sp)
+       REG_L   a4, RISCV_TRAP_REGS_OFFSET(a4)(sp)
+       REG_L   a5, RISCV_TRAP_REGS_OFFSET(a5)(sp)
+       REG_L   a6, RISCV_TRAP_REGS_OFFSET(a6)(sp)
+       REG_L   a7, RISCV_TRAP_REGS_OFFSET(a7)(sp)
+       REG_L   s2, RISCV_TRAP_REGS_OFFSET(s2)(sp)
+       REG_L   s3, RISCV_TRAP_REGS_OFFSET(s3)(sp)
+       REG_L   s4, RISCV_TRAP_REGS_OFFSET(s4)(sp)
+       REG_L   s5, RISCV_TRAP_REGS_OFFSET(s5)(sp)
+       REG_L   s6, RISCV_TRAP_REGS_OFFSET(s6)(sp)
+       REG_L   s7, RISCV_TRAP_REGS_OFFSET(s7)(sp)
+       REG_L   s8, RISCV_TRAP_REGS_OFFSET(s8)(sp)
+       REG_L   s9, RISCV_TRAP_REGS_OFFSET(s9)(sp)
+       REG_L   s10, RISCV_TRAP_REGS_OFFSET(s10)(sp)
+       REG_L   s11, RISCV_TRAP_REGS_OFFSET(s11)(sp)
+       REG_L   t3, RISCV_TRAP_REGS_OFFSET(t3)(sp)
+       REG_L   t4, RISCV_TRAP_REGS_OFFSET(t4)(sp)
+       REG_L   t5, RISCV_TRAP_REGS_OFFSET(t5)(sp)
+       REG_L   t6, RISCV_TRAP_REGS_OFFSET(t6)(sp)
+
+       /* Load T0 and T1 with MEPC and MSTATUS */
+       REG_L   t0, RISCV_TRAP_REGS_OFFSET(mepc)(sp)
+       REG_L   t1, RISCV_TRAP_REGS_OFFSET(mstatus)(sp)
+
+       /*
+        * Note: Jump here after fast trap handling
+        * using SP, RA, T0, T1, and T2
+        * T0 <- MEPC
+        * T1 <- MSTATUS
+        */
+
+       /* Restore MEPC and MSTATUS CSRs */
+       csrw    mepc, t0
+       csrw    mstatus, t1
+
+       /* Restore RA, T0, T1, and T2 */
+       REG_L   ra, RISCV_TRAP_REGS_OFFSET(ra)(sp)
+       REG_L   t0, RISCV_TRAP_REGS_OFFSET(t0)(sp)
+       REG_L   t1, RISCV_TRAP_REGS_OFFSET(t1)(sp)
+       REG_L   t2, RISCV_TRAP_REGS_OFFSET(t2)(sp)
+
+       /* Restore SP */
+       REG_L   sp, RISCV_TRAP_REGS_OFFSET(sp)(sp)
+
+       mret
diff --git a/blob/fw_common.ldS b/blob/fw_common.ldS
new file mode 100644 (file)
index 0000000..eac7ede
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+       . = PLAT_TEXT_START;
+
+       PROVIDE(_fw_start = .);
+
+       . = ALIGN(0x1000); /* Need this to create proper sections */
+
+       /* Beginning of the code section */
+
+       .text :
+       {
+               PROVIDE(_text_start = .);
+               *(.entry)
+               *(.text)
+               . = ALIGN(8);
+               PROVIDE(_text_end = .);
+       }
+
+       . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+       /* End of the code sections */
+
+       /* Beginning of the read-only data sections */
+
+       . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+       .rodata :
+       {
+               PROVIDE(_rodata_start = .);
+               *(.rodata .rodata.*)
+               . = ALIGN(8);
+               PROVIDE(_rodata_end = .);
+       }
+
+       /* End of the read-only data sections */
+
+       /* Beginning of the read-write data sections */
+
+       . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+       .data :
+       {
+               PROVIDE(_data_start = .);
+
+               *(.data)
+               *(.data.*)
+               *(.readmostly.data)
+               *(*.data)
+               . = ALIGN(8);
+
+               PROVIDE(_data_end = .);
+       }
+
+       . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+       .stack :
+       {
+               PROVIDE(_stack_start = .);
+               *(.stack)
+               *(.stack.*)
+               . = . + (PLAT_HART_STACK_SIZE * PLAT_HART_COUNT);
+               . = ALIGN(8);
+               PROVIDE(_stack_end = .);
+       }
+
+       . = ALIGN(0x1000); /* Ensure next section is page aligned */
+
+       .bss :
+       {
+               PROVIDE(_bss_start = .);
+               *(.bss)
+               *(.bss.*)
+               . = ALIGN(8);
+               PROVIDE(_bss_end = .);
+       }
+
+       /* End of the read-write data sections */
+
+       . = ALIGN(0x1000); /* Need this to create proper sections */
+
+       PROVIDE(_fw_end = .);
diff --git a/blob/fw_jump.S b/blob/fw_jump.S
new file mode 100644 (file)
index 0000000..960e594
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "fw_common.S"
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .global fw_next_arg1
+fw_next_arg1:
+       /* We return FDT destinetion address in 'a0' */
+#ifdef FW_JUMP_FDT_OFFSET
+       /* a0 = destinetion FDT start address */
+       la      a0, _jump_addr
+       REG_L   a0, (a0)
+       li      a1, FW_JUMP_FDT_OFFSET
+       add     a0, a0, a1
+#else
+       add     a0, zero, zero
+#endif
+       ret
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .global fw_next_addr
+fw_next_addr:
+       /* We return next address in 'a0' */
+       la      a0, _jump_addr
+       REG_L   a0, (a0)
+       ret
+
+#ifndef FW_JUMP_ADDR
+#error "Must define FW_JUMP_ADDR"
+#endif
+
+       .align 3
+       .section .entry, "ax", %progbits
+_jump_addr:
+       RISCV_PTR FW_JUMP_ADDR
diff --git a/blob/fw_jump.elf.ldS b/blob/fw_jump.elf.ldS
new file mode 100644 (file)
index 0000000..dfffbf6
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+       #include "fw_common.ldS"
+}
diff --git a/blob/fw_payload.S b/blob/fw_payload.S
new file mode 100644 (file)
index 0000000..abc2495
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "fw_common.S"
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .global fw_next_arg1
+fw_next_arg1:
+       /* We return FDT destinetion address in 'a0' */
+#ifdef FW_PAYLOAD_FDT_OFFSET
+       /* a0 = destinetion FDT start address */
+       la      a0, payload_bin
+       li      a1, FW_PAYLOAD_FDT_OFFSET
+       add     a0, a0, a1
+#else
+       add     a0, zero, zero
+#endif
+       ret
+
+       .align 3
+       .section .entry, "ax", %progbits
+       .global fw_next_addr
+fw_next_addr:
+       /* We return next address in 'a0' */
+       la      a0, payload_bin
+       ret
+
+#define        str(s)          #s
+#define        stringify(s)    str(s)
+
+       .section .payload, "ax", %progbits
+       .globl  payload_bin
+payload_bin:
+#ifndef FW_PAYLOAD_PATH
+       wfi
+       j       payload_bin
+#else
+       .incbin stringify(FW_PAYLOAD_PATH)
+#endif
diff --git a/blob/fw_payload.elf.ldS b/blob/fw_payload.elf.ldS
new file mode 100644 (file)
index 0000000..2196e9c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS
+{
+       #include "fw_common.ldS"
+
+       . = ALIGN(0x200000);
+
+       .payload :
+       {
+               PROVIDE(_payload_start = .);
+               *(.payload)
+               . = ALIGN(8);
+               PROVIDE(_payload_end = .);
+       }
+}
diff --git a/blob/objects.mk b/blob/objects.mk
new file mode 100644 (file)
index 0000000..7376213
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+blob-cppflags-y =
+blob-cflags-y =
+blob-asflags-y =
+blob-ldflags-y =
+
+blob-bins-$(FW_JUMP) += fw_jump.bin
+ifdef FW_JUMP_ADDR
+blob-cppflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
+endif
+ifdef FW_JUMP_FDT_OFFSET
+blob-cppflags-$(FW_JUMP) += -DFW_JUMP_FDT_OFFSET=$(FW_JUMP_FDT_OFFSET)
+endif
+
+blob-bins-$(FW_PAYLOAD) += fw_payload.bin
+ifdef FW_PAYLOAD_PATH
+blob-cppflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=$(FW_PAYLOAD_PATH)
+endif
+ifdef FW_PAYLOAD_FDT_OFFSET
+blob-cppflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_OFFSET=$(FW_PAYLOAD_FDT_OFFSET)
+endif
diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
new file mode 100644 (file)
index 0000000..516bf6f
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ASM_H__
+#define __RISCV_ASM_H__
+
+#ifdef __ASSEMBLY__
+#define __ASM_STR(x)   x
+#else
+#define __ASM_STR(x)   #x
+#endif
+
+#if __riscv_xlen == 64
+#define __REG_SEL(a, b)        __ASM_STR(a)
+#elif __riscv_xlen == 32
+#define __REG_SEL(a, b)        __ASM_STR(b)
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+#define REG_L          __REG_SEL(ld, lw)
+#define REG_S          __REG_SEL(sd, sw)
+#define SZREG          __REG_SEL(8, 4)
+#define LGREG          __REG_SEL(3, 2)
+
+#if __SIZEOF_POINTER__ == 8
+#ifdef __ASSEMBLY__
+#define RISCV_PTR              .dword
+#define RISCV_SZPTR            8
+#define RISCV_LGPTR            3
+#else
+#define RISCV_PTR              ".dword"
+#define RISCV_SZPTR            "8"
+#define RISCV_LGPTR            "3"
+#endif
+#elif __SIZEOF_POINTER__ == 4
+#ifdef __ASSEMBLY__
+#define RISCV_PTR              .word
+#define RISCV_SZPTR            4
+#define RISCV_LGPTR            2
+#else
+#define RISCV_PTR              ".word"
+#define RISCV_SZPTR            "4"
+#define RISCV_LGPTR            "2"
+#endif
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#if (__SIZEOF_INT__ == 4)
+#define RISCV_INT              __ASM_STR(.word)
+#define RISCV_SZINT            __ASM_STR(4)
+#define RISCV_LGINT            __ASM_STR(2)
+#else
+#error "Unexpected __SIZEOF_INT__"
+#endif
+
+#if (__SIZEOF_SHORT__ == 2)
+#define RISCV_SHORT            __ASM_STR(.half)
+#define RISCV_SZSHORT          __ASM_STR(2)
+#define RISCV_LGSHORT          __ASM_STR(1)
+#else
+#error "Unexpected __SIZEOF_SHORT__"
+#endif
+
+#define RISCV_SCRATCH_TMP0_OFFSET              (0 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_START_OFFSET          (1 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_SIZE_OFFSET           (2 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ARG1_OFFSET         (3 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ADDR_OFFSET         (4 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_MODE_OFFSET         (5 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_WARMBOOT_ADDR_OFFSET     (6 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_PLATFORM_ADDR_OFFSET     (7 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_IPI_TYPE_OFFSET          (9 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_SIZE                     256
+
+#define RISCV_TRAP_REGS_zero                   0
+#define RISCV_TRAP_REGS_ra                     1
+#define RISCV_TRAP_REGS_sp                     2
+#define RISCV_TRAP_REGS_gp                     3
+#define RISCV_TRAP_REGS_tp                     4
+#define RISCV_TRAP_REGS_t0                     5
+#define RISCV_TRAP_REGS_t1                     6
+#define RISCV_TRAP_REGS_t2                     7
+#define RISCV_TRAP_REGS_s0                     8
+#define RISCV_TRAP_REGS_s1                     9
+#define RISCV_TRAP_REGS_a0                     10
+#define RISCV_TRAP_REGS_a1                     11
+#define RISCV_TRAP_REGS_a2                     12
+#define RISCV_TRAP_REGS_a3                     13
+#define RISCV_TRAP_REGS_a4                     14
+#define RISCV_TRAP_REGS_a5                     15
+#define RISCV_TRAP_REGS_a6                     16
+#define RISCV_TRAP_REGS_a7                     17
+#define RISCV_TRAP_REGS_s2                     18
+#define RISCV_TRAP_REGS_s3                     19
+#define RISCV_TRAP_REGS_s4                     20
+#define RISCV_TRAP_REGS_s5                     21
+#define RISCV_TRAP_REGS_s6                     22
+#define RISCV_TRAP_REGS_s7                     23
+#define RISCV_TRAP_REGS_s8                     24
+#define RISCV_TRAP_REGS_s9                     25
+#define RISCV_TRAP_REGS_s10                    26
+#define RISCV_TRAP_REGS_s11                    27
+#define RISCV_TRAP_REGS_t3                     28
+#define RISCV_TRAP_REGS_t4                     29
+#define RISCV_TRAP_REGS_t5                     30
+#define RISCV_TRAP_REGS_t6                     31
+#define RISCV_TRAP_REGS_mepc                   32
+#define RISCV_TRAP_REGS_mstatus                        33
+#define RISCV_TRAP_REGS_last                   34
+
+#define RISCV_TRAP_REGS_OFFSET(x)              \
+                               ((RISCV_TRAP_REGS_##x) * __SIZEOF_POINTER__)
+#define RISCV_TRAP_REGS_SIZE                   RISCV_TRAP_REGS_OFFSET(last)
+
+#ifndef __ASSEMBLY__
+
+#define csr_swap(csr, val)                                     \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrrw %0, " #csr ", %1"          \
+                             : "=r" (__v) : "rK" (__v)         \
+                             : "memory");                      \
+       __v;                                                    \
+})
+
+#define csr_read(csr)                                          \
+({                                                             \
+       register unsigned long __v;                             \
+       __asm__ __volatile__ ("csrr %0, " #csr                  \
+                             : "=r" (__v) :                    \
+                             : "memory");                      \
+       __v;                                                    \
+})
+
+#define csr_read_n(csr_num)                                    \
+({                                                             \
+       register unsigned long __v;                             \
+       __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr_num)    \
+                             : "=r" (__v) :                    \
+                             : "memory");                      \
+       __v;                                                    \
+})
+
+#define csr_write(csr, val)                                    \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrw " #csr ", %0"               \
+                             : : "rK" (__v)                    \
+                             : "memory");                      \
+})
+
+#define csr_write_n(csr_num, val)                              \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrw " __ASM_STR(csr_num) ", %0" \
+                             : : "rK" (__v)                    \
+                             : "memory");                      \
+})
+
+#define csr_read_set(csr, val)                                 \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrrs %0, " #csr ", %1"          \
+                             : "=r" (__v) : "rK" (__v)         \
+                             : "memory");                      \
+       __v;                                                    \
+})
+
+#define csr_set(csr, val)                                      \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrs " #csr ", %0"               \
+                             : : "rK" (__v)                    \
+                             : "memory");                      \
+})
+
+#define csr_read_clear(csr, val)                               \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrrc %0, " #csr ", %1"          \
+                             : "=r" (__v) : "rK" (__v)         \
+                             : "memory");                      \
+       __v;                                                    \
+})
+
+#define csr_clear(csr, val)                                    \
+({                                                             \
+       unsigned long __v = (unsigned long)(val);               \
+       __asm__ __volatile__ ("csrc " #csr ", %0"               \
+                             : : "rK" (__v)                    \
+                             : "memory");                      \
+})
+
+unsigned long csr_read_num(int csr_num);
+
+void csr_write_num(int csr_num, unsigned long val);
+
+#define wfi()                                                  \
+do {                                                           \
+       __asm__ __volatile__ ("wfi" ::: "memory");              \
+} while (0)
+
+static inline int misa_extension(char ext)
+{
+       return csr_read(misa) & (1 << (ext - 'A'));
+}
+
+static inline int misa_xlen(void)
+{
+       return ((long)csr_read(misa) < 0) ? 64 : 32;
+}
+
+static inline void misa_string(char *out, unsigned int out_sz)
+{
+       unsigned long i, val = csr_read(misa);
+
+       for (i = 0; i < 26; i++) {
+               if (val & (1 << i)) {
+                       *out = 'A' + i;
+                       out++;
+               }
+       }
+       *out = '\0';
+       out++;
+}
+
+int pmp_set(unsigned int n, unsigned long prot,
+           unsigned long addr, unsigned long log2len);
+
+int pmp_get(unsigned int n, unsigned long *prot_out,
+           unsigned long *addr_out, unsigned long *log2len_out);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/include/sbi/riscv_atomic.h b/include/sbi/riscv_atomic.h
new file mode 100644 (file)
index 0000000..775cd6f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ATOMIC_H__
+#define __RISCV_ATOMIC_H__
+
+typedef struct {
+       volatile long counter;
+} atomic_t;
+
+#define ATOMIC_INIT(_lptr, val)                \
+       (_lptr)->counter = (val)
+
+#define ATOMIC_INITIALIZER(val)                \
+       { .counter = (val), }
+
+long atomic_read(atomic_t *atom);
+
+void atomic_write(atomic_t *atom, long value);
+
+long atomic_add_return(atomic_t *atom, long value);
+
+long atomic_sub_return(atomic_t *atom, long value);
+
+long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
+
+long arch_atomic_xchg(atomic_t *atom, long newval);
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+                                 unsigned int newval);
+
+#endif
diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h
new file mode 100644 (file)
index 0000000..993cbda
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_BARRIER_H__
+#define __RISCV_BARRIER_H__
+
+#define RISCV_ACQUIRE_BARRIER          "\tfence r , rw\n"
+#define RISCV_RELEASE_BARRIER          "\tfence rw,  w\n"
+
+#define RISCV_FENCE(p, s) \
+       __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
+
+/* Read & Write Memory barrier */
+#define mb()                   RISCV_FENCE(iorw,iorw)
+
+/* Read Memory barrier */
+#define rmb()                  RISCV_FENCE(ir,ir)
+
+/* Write Memory barrier */
+#define wmb()                  RISCV_FENCE(ow,ow)
+
+/* SMP Read & Write Memory barrier */
+#define smp_mb()               RISCV_FENCE(rw,rw)
+
+/* SMP Read Memory barrier */
+#define smp_rmb()              RISCV_FENCE(r,r)
+
+/* SMP Write Memory barrier */
+#define smp_wmb()              RISCV_FENCE(w,w)
+
+/* CPU relax for busy loop */
+#define cpu_relax()            asm volatile ("" : : : "memory")
+
+#define __smp_store_release(p, v)                              \
+do {                                                           \
+       RISCV_FENCE(rw,w);                                      \
+       *(p) = (v);                                             \
+} while (0)
+
+#define __smp_load_acquire(p)                                  \
+({                                                             \
+       typeof(*p) ___p1 = *(p);                                \
+       RISCV_FENCE(r,rw);                                      \
+       ___p1;                                                  \
+})
+
+#endif
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
new file mode 100644 (file)
index 0000000..a4407d2
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ENCODING_H__
+#define __RISCV_ENCODING_H__
+
+#include <sbi/sbi_const.h>
+
+/* TODO: Make constants usable in assembly with _AC() macro */
+
+#define MSTATUS_UIE                    0x00000001
+#define MSTATUS_SIE                    0x00000002
+#define MSTATUS_HIE                    0x00000004
+#define MSTATUS_MIE                    0x00000008
+#define MSTATUS_UPIE                   0x00000010
+#define MSTATUS_SPIE                   0x00000020
+#define MSTATUS_HPIE                   0x00000040
+#define MSTATUS_MPIE                   0x00000080
+#define MSTATUS_SPP                    0x00000100
+#define MSTATUS_HPP                    0x00000600
+#define MSTATUS_MPP                    0x00001800
+#define MSTATUS_FS                     0x00006000
+#define MSTATUS_XS                     0x00018000
+#define MSTATUS_MPRV                   0x00020000
+#define MSTATUS_SUM                    0x00040000
+#define MSTATUS_MXR                    0x00080000
+#define MSTATUS_TVM                    0x00100000
+#define MSTATUS_TW                     0x00200000
+#define MSTATUS_TSR                    0x00400000
+#define MSTATUS32_SD                   0x80000000
+#define MSTATUS_UXL                    0x0000000300000000
+#define MSTATUS_SXL                    0x0000000C00000000
+#define MSTATUS64_SD                   0x8000000000000000
+
+#define SSTATUS_UIE                    0x00000001
+#define SSTATUS_SIE                    0x00000002
+#define SSTATUS_UPIE                   0x00000010
+#define SSTATUS_SPIE                   0x00000020
+#define SSTATUS_SPP                    0x00000100
+#define SSTATUS_FS                     0x00006000
+#define SSTATUS_XS                     0x00018000
+#define SSTATUS_SUM                    0x00040000
+#define SSTATUS_MXR                    0x00080000
+#define SSTATUS32_SD                   0x80000000
+#define SSTATUS_UXL                    0x0000000300000000
+#define SSTATUS64_SD                   0x8000000000000000
+
+#define DCSR_XDEBUGVER                 (3U<<30)
+#define DCSR_NDRESET                   (1<<29)
+#define DCSR_FULLRESET                 (1<<28)
+#define DCSR_EBREAKM                   (1<<15)
+#define DCSR_EBREAKH                   (1<<14)
+#define DCSR_EBREAKS                   (1<<13)
+#define DCSR_EBREAKU                   (1<<12)
+#define DCSR_STOPCYCLE                 (1<<10)
+#define DCSR_STOPTIME                  (1<<9)
+#define DCSR_CAUSE                     (7<<6)
+#define DCSR_DEBUGINT                  (1<<5)
+#define DCSR_HALT                      (1<<3)
+#define DCSR_STEP                      (1<<2)
+#define DCSR_PRV                       (3<<0)
+
+#define DCSR_CAUSE_NONE                        0
+#define DCSR_CAUSE_SWBP                        1
+#define DCSR_CAUSE_HWBP                        2
+#define DCSR_CAUSE_DEBUGINT            3
+#define DCSR_CAUSE_STEP                        4
+#define DCSR_CAUSE_HALT                        5
+
+#define MCONTROL_TYPE(xlen)            (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen)           (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen)         (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT                        (1<<19)
+#define MCONTROL_TIMING                        (1<<18)
+#define MCONTROL_ACTION                        (0x3f<<12)
+#define MCONTROL_CHAIN                 (1<<11)
+#define MCONTROL_MATCH                 (0xf<<7)
+#define MCONTROL_M                     (1<<6)
+#define MCONTROL_H                     (1<<5)
+#define MCONTROL_S                     (1<<4)
+#define MCONTROL_U                     (1<<3)
+#define MCONTROL_EXECUTE               (1<<2)
+#define MCONTROL_STORE                 (1<<1)
+#define MCONTROL_LOAD                  (1<<0)
+
+#define MCONTROL_TYPE_NONE             0
+#define MCONTROL_TYPE_MATCH            2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION        0
+#define MCONTROL_ACTION_DEBUG_MODE     1
+#define MCONTROL_ACTION_TRACE_START    2
+#define MCONTROL_ACTION_TRACE_STOP     3
+#define MCONTROL_ACTION_TRACE_EMIT     4
+
+#define MCONTROL_MATCH_EQUAL           0
+#define MCONTROL_MATCH_NAPOT           1
+#define MCONTROL_MATCH_GE              2
+#define MCONTROL_MATCH_LT              3
+#define MCONTROL_MATCH_MASK_LOW                4
+#define MCONTROL_MATCH_MASK_HIGH       5
+
+#define IRQ_S_SOFT                     1
+#define IRQ_H_SOFT                     2
+#define IRQ_M_SOFT                     3
+#define IRQ_S_TIMER                    5
+#define IRQ_H_TIMER                    6
+#define IRQ_M_TIMER                    7
+#define IRQ_S_EXT                      9
+#define IRQ_H_EXT                      10
+#define IRQ_M_EXT                      11
+#define IRQ_COP                                12
+#define IRQ_HOST                       13
+
+#define MIP_SSIP                       (1 << IRQ_S_SOFT)
+#define MIP_HSIP                       (1 << IRQ_H_SOFT)
+#define MIP_MSIP                       (1 << IRQ_M_SOFT)
+#define MIP_STIP                       (1 << IRQ_S_TIMER)
+#define MIP_HTIP                       (1 << IRQ_H_TIMER)
+#define MIP_MTIP                       (1 << IRQ_M_TIMER)
+#define MIP_SEIP                       (1 << IRQ_S_EXT)
+#define MIP_HEIP                       (1 << IRQ_H_EXT)
+#define MIP_MEIP                       (1 << IRQ_M_EXT)
+
+#define SIP_SSIP                       MIP_SSIP
+#define SIP_STIP                       MIP_STIP
+
+#define PRV_U                          0
+#define PRV_S                          1
+#define PRV_H                          2
+#define PRV_M                          3
+
+#define SATP32_MODE                    0x80000000
+#define SATP32_ASID                    0x7FC00000
+#define SATP32_PPN                     0x003FFFFF
+#define SATP64_MODE                    0xF000000000000000
+#define SATP64_ASID                    0x0FFFF00000000000
+#define SATP64_PPN                     0x00000FFFFFFFFFFF
+
+#define SATP_MODE_OFF                  0
+#define SATP_MODE_SV32                 1
+#define SATP_MODE_SV39                 8
+#define SATP_MODE_SV48                 9
+#define SATP_MODE_SV57                 10
+#define SATP_MODE_SV64                 11
+
+#define PMP_R                          0x01
+#define PMP_W                          0x02
+#define PMP_X                          0x04
+#define PMP_A                          0x18
+#define PMP_A_TOR                      0x08
+#define PMP_A_NA4                      0x10
+#define PMP_A_NAPOT                    0x18
+#define PMP_L                          0x80
+
+#define PMP_SHIFT                      2
+#define PMP_COUNT                      16
+
+/* page table entry (PTE) fields */
+#define PTE_V                          0x001 /* Valid */
+#define PTE_R                          0x002 /* Read */
+#define PTE_W                          0x004 /* Write */
+#define PTE_X                          0x008 /* Execute */
+#define PTE_U                          0x010 /* User */
+#define PTE_G                          0x020 /* Global */
+#define PTE_A                          0x040 /* Accessed */
+#define PTE_D                          0x080 /* Dirty */
+#define PTE_SOFT                       0x300 /* Reserved for Software */
+
+#define PTE_PPN_SHIFT                  10
+
+#define PTE_TABLE(PTE)                 \
+       (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#if __riscv_xlen == 64
+#define MSTATUS_SD                     MSTATUS64_SD
+#define SSTATUS_SD                     SSTATUS64_SD
+#define RISCV_PGLEVEL_BITS             9
+#define SATP_MODE                      SATP64_MODE
+#else
+#define MSTATUS_SD                     MSTATUS32_SD
+#define SSTATUS_SD                     SSTATUS32_SD
+#define RISCV_PGLEVEL_BITS             10
+#define SATP_MODE                      SATP32_MODE
+#endif
+#define RISCV_PGSHIFT                  12
+#define RISCV_PGSIZE                   (1 << RISCV_PGSHIFT)
+
+#define CSR_FFLAGS                     0x1
+#define CSR_FRM                                0x2
+#define CSR_FCSR                       0x3
+#define CSR_CYCLE                      0xc00
+#define CSR_TIME                       0xc01
+#define CSR_INSTRET                    0xc02
+#define CSR_HPMCOUNTER3                        0xc03
+#define CSR_HPMCOUNTER4                        0xc04
+#define CSR_HPMCOUNTER5                        0xc05
+#define CSR_HPMCOUNTER6                        0xc06
+#define CSR_HPMCOUNTER7                        0xc07
+#define CSR_HPMCOUNTER8                        0xc08
+#define CSR_HPMCOUNTER9                        0xc09
+#define CSR_HPMCOUNTER10               0xc0a
+#define CSR_HPMCOUNTER11               0xc0b
+#define CSR_HPMCOUNTER12               0xc0c
+#define CSR_HPMCOUNTER13               0xc0d
+#define CSR_HPMCOUNTER14               0xc0e
+#define CSR_HPMCOUNTER15               0xc0f
+#define CSR_HPMCOUNTER16               0xc10
+#define CSR_HPMCOUNTER17               0xc11
+#define CSR_HPMCOUNTER18               0xc12
+#define CSR_HPMCOUNTER19               0xc13
+#define CSR_HPMCOUNTER20               0xc14
+#define CSR_HPMCOUNTER21               0xc15
+#define CSR_HPMCOUNTER22               0xc16
+#define CSR_HPMCOUNTER23               0xc17
+#define CSR_HPMCOUNTER24               0xc18
+#define CSR_HPMCOUNTER25               0xc19
+#define CSR_HPMCOUNTER26               0xc1a
+#define CSR_HPMCOUNTER27               0xc1b
+#define CSR_HPMCOUNTER28               0xc1c
+#define CSR_HPMCOUNTER29               0xc1d
+#define CSR_HPMCOUNTER30               0xc1e
+#define CSR_HPMCOUNTER31               0xc1f
+#define CSR_SSTATUS                    0x100
+#define CSR_SIE                                0x104
+#define CSR_STVEC                      0x105
+#define CSR_SCOUNTEREN                 0x106
+#define CSR_SSCRATCH                   0x140
+#define CSR_SEPC                       0x141
+#define CSR_SCAUSE                     0x142
+#define CSR_STVAL                      0x143
+#define CSR_SIP                                0x144
+#define CSR_SATP                       0x180
+#define CSR_MSTATUS                    0x300
+#define CSR_MISA                       0x301
+#define CSR_MEDELEG                    0x302
+#define CSR_MIDELEG                    0x303
+#define CSR_MIE                                0x304
+#define CSR_MTVEC                      0x305
+#define CSR_MCOUNTEREN                 0x306
+#define CSR_MSCRATCH                   0x340
+#define CSR_MEPC                       0x341
+#define CSR_MCAUSE                     0x342
+#define CSR_MTVAL                      0x343
+#define CSR_MIP                                0x344
+#define CSR_PMPCFG0                    0x3a0
+#define CSR_PMPCFG1                    0x3a1
+#define CSR_PMPCFG2                    0x3a2
+#define CSR_PMPCFG3                    0x3a3
+#define CSR_PMPADDR0                   0x3b0
+#define CSR_PMPADDR1                   0x3b1
+#define CSR_PMPADDR2                   0x3b2
+#define CSR_PMPADDR3                   0x3b3
+#define CSR_PMPADDR4                   0x3b4
+#define CSR_PMPADDR5                   0x3b5
+#define CSR_PMPADDR6                   0x3b6
+#define CSR_PMPADDR7                   0x3b7
+#define CSR_PMPADDR8                   0x3b8
+#define CSR_PMPADDR9                   0x3b9
+#define CSR_PMPADDR10                  0x3ba
+#define CSR_PMPADDR11                  0x3bb
+#define CSR_PMPADDR12                  0x3bc
+#define CSR_PMPADDR13                  0x3bd
+#define CSR_PMPADDR14                  0x3be
+#define CSR_PMPADDR15                  0x3bf
+#define CSR_TSELECT                    0x7a0
+#define CSR_TDATA1                     0x7a1
+#define CSR_TDATA2                     0x7a2
+#define CSR_TDATA3                     0x7a3
+#define CSR_DCSR                       0x7b0
+#define CSR_DPC                                0x7b1
+#define CSR_DSCRATCH                   0x7b2
+#define CSR_MCYCLE                     0xb00
+#define CSR_MINSTRET                   0xb02
+#define CSR_MHPMCOUNTER3               0xb03
+#define CSR_MHPMCOUNTER4               0xb04
+#define CSR_MHPMCOUNTER5               0xb05
+#define CSR_MHPMCOUNTER6               0xb06
+#define CSR_MHPMCOUNTER7               0xb07
+#define CSR_MHPMCOUNTER8               0xb08
+#define CSR_MHPMCOUNTER9               0xb09
+#define CSR_MHPMCOUNTER10              0xb0a
+#define CSR_MHPMCOUNTER11              0xb0b
+#define CSR_MHPMCOUNTER12              0xb0c
+#define CSR_MHPMCOUNTER13              0xb0d
+#define CSR_MHPMCOUNTER14              0xb0e
+#define CSR_MHPMCOUNTER15              0xb0f
+#define CSR_MHPMCOUNTER16              0xb10
+#define CSR_MHPMCOUNTER17              0xb11
+#define CSR_MHPMCOUNTER18              0xb12
+#define CSR_MHPMCOUNTER19              0xb13
+#define CSR_MHPMCOUNTER20              0xb14
+#define CSR_MHPMCOUNTER21              0xb15
+#define CSR_MHPMCOUNTER22              0xb16
+#define CSR_MHPMCOUNTER23              0xb17
+#define CSR_MHPMCOUNTER24              0xb18
+#define CSR_MHPMCOUNTER25              0xb19
+#define CSR_MHPMCOUNTER26              0xb1a
+#define CSR_MHPMCOUNTER27              0xb1b
+#define CSR_MHPMCOUNTER28              0xb1c
+#define CSR_MHPMCOUNTER29              0xb1d
+#define CSR_MHPMCOUNTER30              0xb1e
+#define CSR_MHPMCOUNTER31              0xb1f
+#define CSR_MHPMEVENT3                 0x323
+#define CSR_MHPMEVENT4                 0x324
+#define CSR_MHPMEVENT5                 0x325
+#define CSR_MHPMEVENT6                 0x326
+#define CSR_MHPMEVENT7                 0x327
+#define CSR_MHPMEVENT8                 0x328
+#define CSR_MHPMEVENT9                 0x329
+#define CSR_MHPMEVENT10                        0x32a
+#define CSR_MHPMEVENT11                        0x32b
+#define CSR_MHPMEVENT12                        0x32c
+#define CSR_MHPMEVENT13                        0x32d
+#define CSR_MHPMEVENT14                        0x32e
+#define CSR_MHPMEVENT15                        0x32f
+#define CSR_MHPMEVENT16                        0x330
+#define CSR_MHPMEVENT17                        0x331
+#define CSR_MHPMEVENT18                        0x332
+#define CSR_MHPMEVENT19                        0x333
+#define CSR_MHPMEVENT20                        0x334
+#define CSR_MHPMEVENT21                        0x335
+#define CSR_MHPMEVENT22                        0x336
+#define CSR_MHPMEVENT23                        0x337
+#define CSR_MHPMEVENT24                        0x338
+#define CSR_MHPMEVENT25                        0x339
+#define CSR_MHPMEVENT26                        0x33a
+#define CSR_MHPMEVENT27                        0x33b
+#define CSR_MHPMEVENT28                        0x33c
+#define CSR_MHPMEVENT29                        0x33d
+#define CSR_MHPMEVENT30                        0x33e
+#define CSR_MHPMEVENT31                        0x33f
+#define CSR_MVENDORID                  0xf11
+#define CSR_MARCHID                    0xf12
+#define CSR_MIMPID                     0xf13
+#define CSR_MHARTID                    0xf14
+#define CSR_CYCLEH                     0xc80
+#define CSR_TIMEH                      0xc81
+#define CSR_INSTRETH                   0xc82
+#define CSR_HPMCOUNTER3H               0xc83
+#define CSR_HPMCOUNTER4H               0xc84
+#define CSR_HPMCOUNTER5H               0xc85
+#define CSR_HPMCOUNTER6H               0xc86
+#define CSR_HPMCOUNTER7H               0xc87
+#define CSR_HPMCOUNTER8H               0xc88
+#define CSR_HPMCOUNTER9H               0xc89
+#define CSR_HPMCOUNTER10H              0xc8a
+#define CSR_HPMCOUNTER11H              0xc8b
+#define CSR_HPMCOUNTER12H              0xc8c
+#define CSR_HPMCOUNTER13H              0xc8d
+#define CSR_HPMCOUNTER14H              0xc8e
+#define CSR_HPMCOUNTER15H              0xc8f
+#define CSR_HPMCOUNTER16H              0xc90
+#define CSR_HPMCOUNTER17H              0xc91
+#define CSR_HPMCOUNTER18H              0xc92
+#define CSR_HPMCOUNTER19H              0xc93
+#define CSR_HPMCOUNTER20H              0xc94
+#define CSR_HPMCOUNTER21H              0xc95
+#define CSR_HPMCOUNTER22H              0xc96
+#define CSR_HPMCOUNTER23H              0xc97
+#define CSR_HPMCOUNTER24H              0xc98
+#define CSR_HPMCOUNTER25H              0xc99
+#define CSR_HPMCOUNTER26H              0xc9a
+#define CSR_HPMCOUNTER27H              0xc9b
+#define CSR_HPMCOUNTER28H              0xc9c
+#define CSR_HPMCOUNTER29H              0xc9d
+#define CSR_HPMCOUNTER30H              0xc9e
+#define CSR_HPMCOUNTER31H              0xc9f
+#define CSR_MCYCLEH                    0xb80
+#define CSR_MINSTRETH                  0xb82
+#define CSR_MHPMCOUNTER3H              0xb83
+#define CSR_MHPMCOUNTER4H              0xb84
+#define CSR_MHPMCOUNTER5H              0xb85
+#define CSR_MHPMCOUNTER6H              0xb86
+#define CSR_MHPMCOUNTER7H              0xb87
+#define CSR_MHPMCOUNTER8H              0xb88
+#define CSR_MHPMCOUNTER9H              0xb89
+#define CSR_MHPMCOUNTER10H             0xb8a
+#define CSR_MHPMCOUNTER11H             0xb8b
+#define CSR_MHPMCOUNTER12H             0xb8c
+#define CSR_MHPMCOUNTER13H             0xb8d
+#define CSR_MHPMCOUNTER14H             0xb8e
+#define CSR_MHPMCOUNTER15H             0xb8f
+#define CSR_MHPMCOUNTER16H             0xb90
+#define CSR_MHPMCOUNTER17H             0xb91
+#define CSR_MHPMCOUNTER18H             0xb92
+#define CSR_MHPMCOUNTER19H             0xb93
+#define CSR_MHPMCOUNTER20H             0xb94
+#define CSR_MHPMCOUNTER21H             0xb95
+#define CSR_MHPMCOUNTER22H             0xb96
+#define CSR_MHPMCOUNTER23H             0xb97
+#define CSR_MHPMCOUNTER24H             0xb98
+#define CSR_MHPMCOUNTER25H             0xb99
+#define CSR_MHPMCOUNTER26H             0xb9a
+#define CSR_MHPMCOUNTER27H             0xb9b
+#define CSR_MHPMCOUNTER28H             0xb9c
+#define CSR_MHPMCOUNTER29H             0xb9d
+#define CSR_MHPMCOUNTER30H             0xb9e
+#define CSR_MHPMCOUNTER31H             0xb9f
+
+#define CAUSE_MISALIGNED_FETCH         0x0
+#define CAUSE_FETCH_ACCESS             0x1
+#define CAUSE_ILLEGAL_INSTRUCTION      0x2
+#define CAUSE_BREAKPOINT               0x3
+#define CAUSE_MISALIGNED_LOAD          0x4
+#define CAUSE_LOAD_ACCESS              0x5
+#define CAUSE_MISALIGNED_STORE         0x6
+#define CAUSE_STORE_ACCESS             0x7
+#define CAUSE_USER_ECALL               0x8
+#define CAUSE_SUPERVISOR_ECALL         0x9
+#define CAUSE_HYPERVISOR_ECALL         0xa
+#define CAUSE_MACHINE_ECALL            0xb
+#define CAUSE_FETCH_PAGE_FAULT         0xc
+#define CAUSE_LOAD_PAGE_FAULT          0xd
+#define CAUSE_STORE_PAGE_FAULT         0xf
+
+#endif
diff --git a/include/sbi/riscv_io.h b/include/sbi/riscv_io.h
new file mode 100644 (file)
index 0000000..08f1a2f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_IO_H__
+#define __RISCV_IO_H__
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_types.h>
+
+static inline void __raw_writeb(u8 val, volatile void *addr)
+{
+       asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writew(u16 val, volatile void *addr)
+{
+       asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writel(u32 val, volatile void *addr)
+{
+       asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+#if __riscv_xlen != 32
+static inline void __raw_writeq(u64 val, volatile void *addr)
+{
+       asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+#endif
+
+static inline u8 __raw_readb(const volatile void *addr)
+{
+       u8 val;
+
+       asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr));
+       return val;
+}
+
+static inline u16 __raw_readw(const volatile void *addr)
+{
+       u16 val;
+
+       asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr));
+       return val;
+}
+
+static inline u32 __raw_readl(const volatile void *addr)
+{
+       u32 val;
+
+       asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr));
+       return val;
+}
+
+#if __riscv_xlen != 32
+static inline u64 __raw_readq(const volatile void *addr)
+{
+       u64 val;
+
+       asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr));
+       return val;
+}
+#endif
+
+/* FIXME: These are now the same as asm-generic */
+#define __io_rbr()             do {} while (0)
+#define __io_rar()             do {} while (0)
+#define __io_rbw()             do {} while (0)
+#define __io_raw()             do {} while (0)
+
+#define readb_relaxed(c)       ({ u8  __v; __io_rbr(); __v = __raw_readb(c); __io_rar(); __v; })
+#define readw_relaxed(c)       ({ u16 __v; __io_rbr(); __v = __raw_readw(c); __io_rar(); __v; })
+#define readl_relaxed(c)       ({ u32 __v; __io_rbr(); __v = __raw_readl(c); __io_rar(); __v; })
+
+#define writeb_relaxed(v,c)    ({ __io_rbw(); __raw_writeb((v),(c)); __io_raw(); })
+#define writew_relaxed(v,c)    ({ __io_rbw(); __raw_writew((v),(c)); __io_raw(); })
+#define writel_relaxed(v,c)    ({ __io_rbw(); __raw_writel((v),(c)); __io_raw(); })
+
+#if __riscv_xlen != 32
+#define readq_relaxed(c)       ({ u64 __v; __io_rbr(); __v = __raw_readq(c); __io_rar(); __v; })
+#define writeq_relaxed(v,c)    ({ __io_rbw(); __raw_writeq((v),(c)); __io_raw(); })
+#endif
+
+#define __io_br()      do {} while (0)
+#define __io_ar()      __asm__ __volatile__ ("fence i,r" : : : "memory");
+#define __io_bw()      __asm__ __volatile__ ("fence w,o" : : : "memory");
+#define __io_aw()      do {} while (0)
+
+#define readb(c)       ({ u8  __v; __io_br(); __v = __raw_readb(c); __io_ar(); __v; })
+#define readw(c)       ({ u16 __v; __io_br(); __v = __raw_readw(c); __io_ar(); __v; })
+#define readl(c)       ({ u32 __v; __io_br(); __v = __raw_readl(c); __io_ar(); __v; })
+
+#define writeb(v,c)    ({ __io_bw(); __raw_writeb((v),(c)); __io_aw(); })
+#define writew(v,c)    ({ __io_bw(); __raw_writew((v),(c)); __io_aw(); })
+#define writel(v,c)    ({ __io_bw(); __raw_writel((v),(c)); __io_aw(); })
+
+#if __riscv_xlen != 32
+#define readq(c)       ({ u64 __v; __io_br(); __v = __raw_readq(c); __io_ar(); __v; })
+#define writeq(v,c)    ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
+#endif
+
+#endif
diff --git a/include/sbi/riscv_locks.h b/include/sbi/riscv_locks.h
new file mode 100644 (file)
index 0000000..4a683d9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_LOCKS_H__
+#define __RISCV_LOCKS_H__
+
+typedef struct {
+       volatile long lock;
+} spinlock_t;
+
+#define __RISCV_SPIN_UNLOCKED                  0
+
+#define SPIN_LOCK_INIT(_lptr)                  \
+       (_lptr)->lock = __RISCV_SPIN_UNLOCKED
+
+#define SPIN_LOCK_INITIALIZER                  \
+       { .lock = __RISCV_SPIN_UNLOCKED, }
+
+int spin_lock_check(spinlock_t *lock);
+
+int spin_trylock(spinlock_t *lock);
+
+void spin_lock(spinlock_t *lock);
+
+void spin_unlock(spinlock_t *lock);
+
+#endif
diff --git a/include/sbi/sbi_bits.h b/include/sbi/sbi_bits.h
new file mode 100644 (file)
index 0000000..118fab2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_BITS_H__
+#define __SBI_BITS_H__
+
+#define likely(x) __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+
+#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
+#define ROUNDDOWN(a, b) ((a)/(b)*(b))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
+
+#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
+#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#if __riscv_xlen == 64
+#define SLL32    sllw
+#define STORE    sd
+#define LOAD     ld
+#define LWU      lwu
+#define LOG_REGBYTES 3
+#else
+#define SLL32    sll
+#define STORE    sw
+#define LOAD     lw
+#define LWU      lw
+#define LOG_REGBYTES 2
+#endif
+#define REGBYTES (1 << LOG_REGBYTES)
+
+#endif
diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h
new file mode 100644 (file)
index 0000000..df258ba
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_CONSOLE_H__
+#define __SBI_CONSOLE_H__
+
+#include <sbi/sbi_types.h>
+
+#define __printf(a, b)         __attribute__((format(printf, a, b)))
+
+bool sbi_isprintable(char ch);
+
+char sbi_getc(void);
+
+void sbi_putc(char ch);
+
+void sbi_puts(const char *str);
+
+void sbi_gets(char *s, int maxwidth, char endchar);
+
+int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
+
+int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz,
+                               const char *format, ...);
+
+int __printf(1, 2) sbi_printf(const char *format, ...);
+
+struct sbi_scratch;
+int sbi_console_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_const.h b/include/sbi/sbi_const.h
new file mode 100644 (file)
index 0000000..3071094
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_CONST_H__
+#define __SBI_CONST_H__
+
+/* Some constant macros are used in both assembler and
+ * C code.  Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally.  We
+ * use the following macros to deal with this.
+ *
+ * Similarly, _AT() will cast an expression with a type in C, but
+ * leave it unchanged in asm.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y)       X
+#define _AT(T,X)       X
+#else
+#define __AC(X,Y)      (X##Y)
+#define _AC(X,Y)       __AC(X,Y)
+#define _AT(T,X)       ((T)(X))
+#endif
+
+#define _UL(x)         (_AC(x, UL))
+#define _ULL(x)                (_AC(x, ULL))
+
+#define _BITUL(x)      (_UL(1) << (x))
+#define _BITULL(x)     (_ULL(1) << (x))
+
+#define UL(x)          (_UL(x))
+#define ULL(x)         (_ULL(x))
+
+#define        __STR(s)        #s
+#define        STRINGIFY(s)    __STR(s)
+
+#endif
diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
new file mode 100644 (file)
index 0000000..4f39329
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ECALL_H__
+#define __SBI_ECALL_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+u16 sbi_ecall_version_major(void);
+
+u16 sbi_ecall_version_minor(void);
+
+int sbi_ecall_handler(u32 hartid, ulong mcause,
+                     struct sbi_trap_regs *regs,
+                     struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_emulate_csr.h b/include/sbi/sbi_emulate_csr.h
new file mode 100644 (file)
index 0000000..c6fe419
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_EMULATE_CSR_H__
+#define __SBI_EMULATE_CSR_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_emulate_csr_read(int csr_num,
+                        u32 hartid, ulong mstatus,
+                        struct sbi_scratch *scratch,
+                        ulong *csr_val);
+
+int sbi_emulate_csr_write(int csr_num,
+                         u32 hartid, ulong mstatus,
+                         struct sbi_scratch *scratch,
+                         ulong csr_val);
+
+#endif
diff --git a/include/sbi/sbi_error.h b/include/sbi/sbi_error.h
new file mode 100644 (file)
index 0000000..955674e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ERROR_H__
+#define __SBI_ERROR_H__
+
+#define SBI_OK         0
+#define SBI_EUNKNOWN   -1
+#define SBI_EFAIL      -2
+#define SBI_EINVAL     -3
+#define SBI_ENOENT     -4
+#define SBI_ENOTSUPP   -5
+#define SBI_ENODEV     -6
+#define SBI_ENOSYS     -7
+#define SBI_ETIMEDOUT  -8
+#define SBI_EIO                -9
+#define SBI_EILL       -10
+
+#endif
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
new file mode 100644 (file)
index 0000000..38032ed
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_HART_H__
+#define __SBI_HART_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_pmp_dump(void);
+
+void __attribute__((noreturn)) sbi_hart_hang(void);
+
+void __attribute__((noreturn)) sbi_hart_boot_next(unsigned long arg0,
+                                                 unsigned long arg1,
+                                                 unsigned long next_addr,
+                                                 unsigned long next_mode);
+
+void sbi_hart_mark_available(u32 hartid);
+
+ulong sbi_hart_available_mask(void);
+
+void sbi_hart_unmark_available(u32 hartid);
+
+struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
+                                          u32 hartid);
+
+void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_illegal_insn.h b/include/sbi/sbi_illegal_insn.h
new file mode 100644 (file)
index 0000000..1b8837f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ILLEGAl_INSN_H__
+#define __SBI_ILLEGAl_INSN_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
+                            struct sbi_trap_regs *regs,
+                            struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_init.h b/include/sbi/sbi_init.h
new file mode 100644 (file)
index 0000000..b3aafdc
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_INIT_H__
+#define __SBI_INIT_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+void __attribute__((noreturn)) sbi_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
new file mode 100644 (file)
index 0000000..4058194
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_IPI_H__
+#define __SBI_IPI_H__
+
+#include <sbi/sbi_types.h>
+
+#define SBI_IPI_EVENT_SOFT                     0x1
+#define SBI_IPI_EVENT_FENCE_I                  0x2
+#define SBI_IPI_EVENT_SFENCE_VMA               0x4
+#define SBI_IPI_EVENT_HALT                     0x8
+
+struct sbi_scratch;
+
+int sbi_ipi_send_many(struct sbi_scratch *scratch,
+                     u32 hartid, ulong *pmask, u32 event);
+
+void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
new file mode 100644 (file)
index 0000000..57b8e6b
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_PLATFORM_H__
+#define __SBI_PLATFORM_H__
+
+#include <sbi/sbi_scratch.h>
+
+enum sbi_platform_features {
+       SBI_PLATFORM_HAS_MMIO_TIMER_VALUE = (1 << 0),
+       SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
+};
+
+struct sbi_platform {
+       char name[64];
+       u64 features;
+       u32 hart_count;
+       u32 hart_stack_size;
+       int (*cold_early_init)(void);
+       int (*cold_final_init)(void);
+       int (*warm_early_init)(u32 target_hart);
+       int (*warm_final_init)(u32 target_hart);
+       u32 (*pmp_region_count)(u32 target_hart);
+       int (*pmp_region_info)(u32 target_hart, u32 index,
+                              ulong *prot, ulong *addr, ulong *log2size);
+       void (*console_putc)(char ch);
+       char (*console_getc)(void);
+       int (*console_init)(void);
+       int (*cold_irqchip_init)(void);
+       int (*warm_irqchip_init)(u32 target_hart);
+       void (*ipi_inject)(u32 target_hart, u32 source_hart);
+       void (*ipi_sync)(u32 target_hart, u32 source_hart);
+       void (*ipi_clear)(u32 target_hart);
+       int (*cold_ipi_init)(void);
+       int (*warm_ipi_init)(u32 target_hart);
+       u64 (*timer_value)(void);
+       void (*timer_event_stop)(u32 target_hart);
+       void (*timer_event_start)(u32 target_hart, u64 next_event);
+       int (*cold_timer_init)(void);
+       int (*warm_timer_init)(u32 target_hart);
+       int (*system_reboot)(u32 type);
+       int (*system_shutdown)(u32 type);
+} __attribute__((packed));
+
+#define sbi_platform_ptr(__s)                  \
+((struct sbi_platform *)((__s)->platform_addr))
+
+#define sbi_platform_thishart_ptr()                    \
+((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr))
+
+#define sbi_platform_has_mmio_timer_value(__p) \
+((__p)->features & SBI_PLATFORM_HAS_MMIO_TIMER_VALUE)
+
+#define sbi_platform_has_hart_hotplug(__p)     \
+((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
+
+static inline const char *sbi_platform_name(struct sbi_platform *plat)
+{
+       if (plat)
+               return plat->name;
+       return NULL;
+}
+
+static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
+{
+       if (plat)
+               return plat->hart_count;
+       return 0;
+}
+
+static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
+{
+       if (plat)
+               return plat->hart_stack_size;
+       return 0;
+}
+
+static inline int sbi_platform_cold_early_init(struct sbi_platform *plat)
+{
+       if (plat && plat->cold_early_init)
+               return plat->cold_early_init();
+       return 0;
+}
+
+static inline int sbi_platform_cold_final_init(struct sbi_platform *plat)
+{
+       if (plat && plat->cold_final_init)
+               return plat->cold_final_init();
+       return 0;
+}
+
+static inline int sbi_platform_warm_early_init(struct sbi_platform *plat,
+                                              u32 target_hart)
+{
+       if (plat && plat->warm_early_init)
+               return plat->warm_early_init(target_hart);
+       return 0;
+}
+
+static inline int sbi_platform_warm_final_init(struct sbi_platform *plat,
+                                              u32 target_hart)
+{
+       if (plat && plat->warm_final_init)
+               return plat->warm_final_init(target_hart);
+       return 0;
+}
+
+static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
+                                               u32 target_hart)
+{
+       if (plat && plat->pmp_region_count)
+               return plat->pmp_region_count(target_hart);
+       return 0;
+}
+
+static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
+                                              u32 target_hart, u32 index,
+                                              ulong *prot, ulong *addr,
+                                              ulong *log2size)
+{
+       if (plat && plat->pmp_region_info)
+               return plat->pmp_region_info(target_hart, index,
+                                             prot, addr, log2size);
+       return 0;
+}
+
+static inline void sbi_platform_console_putc(struct sbi_platform *plat,
+                                            char ch)
+{
+       if (plat && plat->console_putc)
+               plat->console_putc(ch);
+}
+
+static inline char sbi_platform_console_getc(struct sbi_platform *plat)
+{
+       if (plat && plat->console_getc)
+               return plat->console_getc();
+       return 0;
+}
+
+static inline int sbi_platform_console_init(struct sbi_platform *plat)
+{
+       if (plat && plat->console_init)
+               return plat->console_init();
+       return 0;
+}
+
+static inline int sbi_platform_warm_irqchip_init(struct sbi_platform *plat,
+                                                u32 target_hart)
+{
+       if (plat && plat->warm_irqchip_init)
+               return plat->warm_irqchip_init(target_hart);
+       return 0;
+}
+
+static inline int sbi_platform_cold_irqchip_init(struct sbi_platform *plat)
+{
+       if (plat && plat->cold_irqchip_init)
+               return plat->cold_irqchip_init();
+       return 0;
+}
+
+static inline void sbi_platform_ipi_inject(struct sbi_platform *plat,
+                                          u32 target_hart, u32 source_hart)
+{
+       if (plat && plat->ipi_inject)
+               plat->ipi_inject(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
+                                        u32 target_hart, u32 source_hart)
+{
+       if (plat && plat->ipi_sync)
+               plat->ipi_sync(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
+                                         u32 target_hart)
+{
+       if (plat && plat->ipi_clear)
+               plat->ipi_clear(target_hart);
+}
+
+static inline int sbi_platform_warm_ipi_init(struct sbi_platform *plat,
+                                            u32 target_hart)
+{
+       if (plat && plat->warm_ipi_init)
+               return plat->warm_ipi_init(target_hart);
+       return 0;
+}
+
+static inline int sbi_platform_cold_ipi_init(struct sbi_platform *plat)
+{
+       if (plat && plat->cold_ipi_init)
+               return plat->cold_ipi_init();
+       return 0;
+}
+
+static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
+{
+       if (plat && plat->timer_value)
+               return plat->timer_value();
+       return 0;
+}
+
+static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat,
+                                                u32 target_hart)
+{
+       if (plat && plat->timer_event_stop)
+               plat->timer_event_stop(target_hart);
+}
+
+static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
+                                                 u32 target_hart,
+                                                 u64 next_event)
+{
+       if (plat && plat->timer_event_start)
+               plat->timer_event_start(target_hart, next_event);
+}
+
+static inline int sbi_platform_warm_timer_init(struct sbi_platform *plat,
+                                              u32 target_hart)
+{
+       if (plat && plat->warm_timer_init)
+               return plat->warm_timer_init(target_hart);
+       return 0;
+}
+
+static inline int sbi_platform_cold_timer_init(struct sbi_platform *plat)
+{
+       if (plat && plat->cold_timer_init)
+               return plat->cold_timer_init();
+       return 0;
+}
+
+static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
+                                            u32 type)
+{
+       if (plat && plat->system_reboot)
+               return plat->system_reboot(type);
+       return 0;
+}
+
+static inline int sbi_platform_system_shutdown(struct sbi_platform *plat,
+                                              u32 type)
+{
+       if (plat && plat->system_shutdown)
+               return plat->system_shutdown(type);
+       return 0;
+}
+
+#endif
diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
new file mode 100644 (file)
index 0000000..d5c6f35
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SCRATCH_H__
+#define __SBI_SCRATCH_H__
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch {
+       unsigned long tmp0;
+       unsigned long fw_start;
+       unsigned long fw_size;
+       unsigned long next_arg1;
+       unsigned long next_addr;
+       unsigned long next_mode;
+       unsigned long warmboot_addr;
+       unsigned long platform_addr;
+       unsigned long hartid_to_scratch;
+       unsigned long ipi_type;
+} __attribute__((packed));
+
+#define sbi_scratch_thishart_ptr()     \
+((struct sbi_scratch *)csr_read(mscratch))
+
+#define sbi_scratch_thishart_arg1_ptr()        \
+((void *)(sbi_scratch_thishart_ptr()->next_arg1))
+
+#endif
diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h
new file mode 100644 (file)
index 0000000..ac1fb36
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SYSTEM_H__
+#define __SBI_SYSTEM_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_system_warm_early_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_warm_final_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_cold_early_init(struct sbi_scratch *scratch);
+
+int sbi_system_cold_final_init(struct sbi_scratch *scratch);
+
+void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
+                                                u32 type);
+
+void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
+                                                  u32 type);
+
+#endif
diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
new file mode 100644 (file)
index 0000000..914e9c0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TIMER_H__
+#define __SBI_TIMER_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+u64 sbi_timer_value(struct sbi_scratch *scratch);
+
+void sbi_timer_event_stop(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_timer_event_start(struct sbi_scratch *scratch, u32 hartid,
+                          u64 next_event);
+
+void sbi_timer_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_trap.h b/include/sbi/sbi_trap.h
new file mode 100644 (file)
index 0000000..a6b22e4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TRAP_H__
+#define __SBI_TRAP_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs {
+       unsigned long zero;
+       unsigned long ra;
+       unsigned long sp;
+       unsigned long gp;
+       unsigned long tp;
+       unsigned long t0;
+       unsigned long t1;
+       unsigned long t2;
+       unsigned long s0;
+       unsigned long s1;
+       unsigned long a0;
+       unsigned long a1;
+       unsigned long a2;
+       unsigned long a3;
+       unsigned long a4;
+       unsigned long a5;
+       unsigned long a6;
+       unsigned long a7;
+       unsigned long s2;
+       unsigned long s3;
+       unsigned long s4;
+       unsigned long s5;
+       unsigned long s6;
+       unsigned long s7;
+       unsigned long s8;
+       unsigned long s9;
+       unsigned long s10;
+       unsigned long s11;
+       unsigned long t3;
+       unsigned long t4;
+       unsigned long t5;
+       unsigned long t6;
+       unsigned long mepc;
+       unsigned long mstatus;
+} __attribute__((packed));
+
+struct sbi_scratch;
+
+void sbi_trap_handler(struct sbi_trap_regs *regs,
+                     struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h
new file mode 100644 (file)
index 0000000..ddcdea2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TYPES_H__
+#define __SBI_TYPES_H__
+
+typedef char                   s8;
+typedef unsigned char          u8;
+typedef char                   int8_t;
+typedef unsigned char          uint8_t;
+
+typedef short                  s16;
+typedef unsigned short         u16;
+typedef short                  int16_t;
+typedef unsigned short         uint16_t;
+
+typedef int                    s32;
+typedef unsigned int           u32;
+typedef int                    int32_t;
+typedef unsigned int           uint32_t;
+
+#if __riscv_xlen == 64
+typedef long                   s64;
+typedef unsigned long          u64;
+typedef long                   int64_t;
+typedef unsigned long          uint64_t;
+#elif __riscv_xlen == 32
+typedef long long              s64;
+typedef unsigned long long     u64;
+typedef long long              int64_t;
+typedef unsigned long long     uint64_t;
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+typedef int                    bool;
+typedef unsigned long          ulong;
+typedef unsigned long          uintptr_t;
+typedef unsigned long          size_t;
+typedef long                   ssize_t;
+typedef unsigned long          virtual_addr_t;
+typedef unsigned long          virtual_size_t;
+typedef unsigned long          physical_addr_t;
+typedef unsigned long          physical_size_t;
+
+#define TRUE                   1
+#define FALSE                  0
+
+#define NULL                   ((void *)0)
+
+#endif
diff --git a/include/sbi/sbi_unpriv.h b/include/sbi/sbi_unpriv.h
new file mode 100644 (file)
index 0000000..2b925c5
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_UNPRIV_H__
+#define __SBI_UNPRIV_H__
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_types.h>
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn)                 \
+static inline type load_##type(const type *addr, ulong mepc)           \
+{                                                                      \
+       register ulong __mepc asm ("a2") = mepc;                        \
+       register ulong __mstatus asm ("a3");                            \
+       type val;                                                       \
+       asm ("csrrs %0, mstatus, %3\n"                                  \
+               #insn " %1, %2\n"                                       \
+               "csrw mstatus, %0"                                      \
+       : "+&r" (__mstatus), "=&r" (val)                                \
+       : "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc));               \
+       return val;                                                     \
+}
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn)                        \
+static inline void store_##type(type *addr, type val, ulong mepc)      \
+{                                                                      \
+       register ulong __mepc asm ("a2") = mepc;                        \
+       register ulong __mstatus asm ("a3");                            \
+       asm volatile ("csrrs %0, mstatus, %3\n"                         \
+               #insn " %1, %2\n"                                       \
+               "csrw mstatus, %0"                                      \
+       : "+&r" (__mstatus)                                             \
+       : "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc));    \
+}
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
+#if __riscv_xlen == 64
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
+#else
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
+
+static inline u64 load_u64(const u64 *addr, ulong mepc)
+{
+       return load_u32((u32 *)addr, mepc)
+               + ((u64)load_u32((u32 *)addr + 1, mepc) << 32);
+}
+
+static inline void store_u64(u64 *addr, u64 val, ulong mepc)
+{
+       store_u32((u32 *)addr, val, mepc);
+       store_u32((u32 *)addr + 1, val >> 32, mepc);
+}
+#endif
+
+static inline ulong get_insn(ulong mepc, ulong *mstatus)
+{
+       register ulong __mepc asm ("a2") = mepc;
+       register ulong __mstatus asm ("a3");
+       ulong val;
+#ifndef __riscv_compressed
+       asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+               STR(LWU) " %[insn], (%[addr])\n"
+               "csrw mstatus, %[mstatus]"
+               : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
+               : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
+#else
+       ulong rvc_mask = 3, tmp;
+       asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+               "and %[tmp], %[addr], 2\n"
+               "bnez %[tmp], 1f\n"
+               STR(LWU) " %[insn], (%[addr])\n"
+               "and %[tmp], %[insn], %[rvc_mask]\n"
+               "beq %[tmp], %[rvc_mask], 2f\n"
+               "sll %[insn], %[insn], %[xlen_minus_16]\n"
+               "srl %[insn], %[insn], %[xlen_minus_16]\n"
+               "j 2f\n"
+               "1:\n"
+               "lhu %[insn], (%[addr])\n"
+               "and %[tmp], %[insn], %[rvc_mask]\n"
+               "bne %[tmp], %[rvc_mask], 2f\n"
+               "lhu %[tmp], 2(%[addr])\n"
+               "sll %[tmp], %[tmp], 16\n"
+               "add %[insn], %[insn], %[tmp]\n"
+               "2: csrw mstatus, %[mstatus]"
+       : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
+       : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
+       [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
+#endif
+       *mstatus = __mstatus;
+       return val;
+}
+
+#endif
diff --git a/lib/objects.mk b/lib/objects.mk
new file mode 100644 (file)
index 0000000..ed14677
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+lib-objs-y += riscv_asm.o
+lib-objs-y += riscv_atomic.o
+lib-objs-y += riscv_locks.o
+
+lib-objs-y += sbi_console.o
+lib-objs-y += sbi_ecall.o
+lib-objs-y += sbi_emulate_csr.o
+lib-objs-y += sbi_hart.o
+lib-objs-y += sbi_illegal_insn.o
+lib-objs-y += sbi_init.o
+lib-objs-y += sbi_ipi.o
+lib-objs-y += sbi_system.o
+lib-objs-y += sbi_timer.o
+lib-objs-y += sbi_trap.o
diff --git a/lib/riscv_asm.c b/lib/riscv_asm.c
new file mode 100644 (file)
index 0000000..0fbdb31
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_error.h>
+
+unsigned long csr_read_num(int csr_num)
+{
+       unsigned long ret = 0;
+
+       switch (csr_num) {
+       case CSR_PMPCFG0:
+               ret = csr_read_n(CSR_PMPCFG0);
+               break;
+       case CSR_PMPCFG1:
+               ret = csr_read_n(CSR_PMPCFG1);
+               break;
+       case CSR_PMPCFG2:
+               ret = csr_read_n(CSR_PMPCFG2);
+               break;
+       case CSR_PMPCFG3:
+               ret = csr_read_n(CSR_PMPCFG3);
+               break;
+       case CSR_PMPADDR0:
+               ret = csr_read_n(CSR_PMPADDR0);
+               break;
+       case CSR_PMPADDR1:
+               ret = csr_read_n(CSR_PMPADDR1);
+               break;
+       case CSR_PMPADDR2:
+               ret = csr_read_n(CSR_PMPADDR2);
+               break;
+       case CSR_PMPADDR3:
+               ret = csr_read_n(CSR_PMPADDR3);
+               break;
+       case CSR_PMPADDR4:
+               ret = csr_read_n(CSR_PMPADDR4);
+               break;
+       case CSR_PMPADDR5:
+               ret = csr_read_n(CSR_PMPADDR5);
+               break;
+       case CSR_PMPADDR6:
+               ret = csr_read_n(CSR_PMPADDR6);
+               break;
+       case CSR_PMPADDR7:
+               ret = csr_read_n(CSR_PMPADDR7);
+               break;
+       case CSR_PMPADDR8:
+               ret = csr_read_n(CSR_PMPADDR8);
+               break;
+       case CSR_PMPADDR9:
+               ret = csr_read_n(CSR_PMPADDR9);
+               break;
+       case CSR_PMPADDR10:
+               ret = csr_read_n(CSR_PMPADDR10);
+               break;
+       case CSR_PMPADDR11:
+               ret = csr_read_n(CSR_PMPADDR11);
+               break;
+       case CSR_PMPADDR12:
+               ret = csr_read_n(CSR_PMPADDR12);
+               break;
+       case CSR_PMPADDR13:
+               ret = csr_read_n(CSR_PMPADDR13);
+               break;
+       case CSR_PMPADDR14:
+               ret = csr_read_n(CSR_PMPADDR14);
+               break;
+       case CSR_PMPADDR15:
+               ret = csr_read_n(CSR_PMPADDR15);
+               break;
+       default:
+               break;
+       };
+
+       return ret;
+}
+
+void csr_write_num(int csr_num, unsigned long val)
+{
+       switch (csr_num) {
+       case CSR_PMPCFG0:
+               csr_write_n(CSR_PMPCFG0, val);
+               break;
+       case CSR_PMPCFG1:
+               csr_write_n(CSR_PMPCFG1, val);
+               break;
+       case CSR_PMPCFG2:
+               csr_write_n(CSR_PMPCFG2, val);
+               break;
+       case CSR_PMPCFG3:
+               csr_write_n(CSR_PMPCFG3, val);
+               break;
+       case CSR_PMPADDR0:
+               csr_write_n(CSR_PMPADDR0, val);
+               break;
+       case CSR_PMPADDR1:
+               csr_write_n(CSR_PMPADDR1, val);
+               break;
+       case CSR_PMPADDR2:
+               csr_write_n(CSR_PMPADDR2, val);
+               break;
+       case CSR_PMPADDR3:
+               csr_write_n(CSR_PMPADDR3, val);
+               break;
+       case CSR_PMPADDR4:
+               csr_write_n(CSR_PMPADDR4, val);
+               break;
+       case CSR_PMPADDR5:
+               csr_write_n(CSR_PMPADDR5, val);
+               break;
+       case CSR_PMPADDR6:
+               csr_write_n(CSR_PMPADDR6, val);
+               break;
+       case CSR_PMPADDR7:
+               csr_write_n(CSR_PMPADDR7, val);
+               break;
+       case CSR_PMPADDR8:
+               csr_write_n(CSR_PMPADDR8, val);
+               break;
+       case CSR_PMPADDR9:
+               csr_write_n(CSR_PMPADDR9, val);
+               break;
+       case CSR_PMPADDR10:
+               csr_write_n(CSR_PMPADDR10, val);
+               break;
+       case CSR_PMPADDR11:
+               csr_write_n(CSR_PMPADDR11, val);
+               break;
+       case CSR_PMPADDR12:
+               csr_write_n(CSR_PMPADDR12, val);
+               break;
+       case CSR_PMPADDR13:
+               csr_write_n(CSR_PMPADDR13, val);
+               break;
+       case CSR_PMPADDR14:
+               csr_write_n(CSR_PMPADDR14, val);
+               break;
+       case CSR_PMPADDR15:
+               csr_write_n(CSR_PMPADDR15, val);
+               break;
+       default:
+               break;
+       };
+}
+
+static unsigned long ctz(unsigned long x)
+{
+       unsigned long ret = 0;
+
+       while (!(x & 1UL)) {
+               ret++;
+               x = x >> 1;
+       }
+
+       return ret;
+}
+
+int pmp_set(unsigned int n, unsigned long prot,
+           unsigned long addr, unsigned long log2len)
+{
+       int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+       unsigned long cfgmask, pmpcfg;
+       unsigned long addrmask, pmpaddr;
+
+       /* check parameters */
+       if (n >= PMP_COUNT ||
+           log2len > __riscv_xlen ||
+           log2len < PMP_SHIFT)
+               return SBI_EINVAL;
+
+       /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+       pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+       pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+       pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+       pmpcfg_shift = (n & 7) << 3;
+#else
+       pmpcfg_csr = -1;
+       pmpcfg_shift = -1;
+#endif
+       pmpaddr_csr = CSR_PMPADDR0 + n;
+       if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+               return SBI_ENOTSUPP;
+
+       /* encode PMP config */
+       prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
+       cfgmask = ~(0xff << pmpcfg_shift);
+       pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
+       pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
+
+       /* encode PMP address */
+       if (log2len == PMP_SHIFT) {
+               pmpaddr = (addr >> PMP_SHIFT);
+       } else {
+               if (log2len == __riscv_xlen) {
+                       pmpaddr = -1UL;
+               } else {
+                       addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
+                       pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask);
+                       pmpaddr |= (addrmask >> 1);
+               }
+       }
+
+       /* write csrs */
+       csr_write_num(pmpaddr_csr, pmpaddr);
+       csr_write_num(pmpcfg_csr, pmpcfg);
+
+       return 0;
+}
+
+int pmp_get(unsigned int n, unsigned long *prot_out,
+           unsigned long *addr_out, unsigned long *log2len_out)
+{
+       int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
+       unsigned long cfgmask, pmpcfg, prot;
+       unsigned long t1, addr, log2len;
+
+       /* check parameters */
+       if (n >= PMP_COUNT || !prot_out ||
+           !addr_out || !log2len_out)
+               return SBI_EINVAL;
+       *prot_out = *addr_out = *log2len_out = 0;
+
+       /* calculate PMP register and offset */
+#if __riscv_xlen == 32
+       pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
+       pmpcfg_shift = (n & 3) << 3;
+#elif __riscv_xlen == 64
+       pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
+       pmpcfg_shift = (n & 7) << 3;
+#else
+       pmpcfg_csr = -1;
+       pmpcfg_shift = -1;
+#endif
+       pmpaddr_csr = CSR_PMPADDR0 + n;
+       if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
+               return SBI_ENOTSUPP;
+
+       /* decode PMP config */
+       cfgmask = (0xff << pmpcfg_shift);
+       pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
+       prot = pmpcfg >> pmpcfg_shift;
+
+       /* decode PMP address */
+       if ((prot & PMP_A) == PMP_A_NAPOT) {
+               addr = csr_read_num(pmpaddr_csr);
+               if (addr == -1UL) {
+                       addr = 0;
+                       log2len = __riscv_xlen;
+               } else {
+                       t1 = ctz(~addr);
+                       addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
+                       log2len = (t1 + PMP_SHIFT + 1);
+               }
+       } else {
+               addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
+               log2len = PMP_SHIFT;
+       }
+
+       /* return details */
+       *prot_out = prot;
+       *addr_out = addr;
+       *log2len_out = log2len;
+
+       return 0;
+}
diff --git a/lib/riscv_atomic.c b/lib/riscv_atomic.c
new file mode 100644 (file)
index 0000000..3a599f5
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_types.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/riscv_barrier.h>
+
+long atomic_read(atomic_t *atom)
+{
+       long ret = atom->counter;
+       rmb();
+       return ret;
+}
+
+void atomic_write(atomic_t *atom, long value)
+{
+       atom->counter = value;
+       wmb();
+}
+
+long atomic_add_return(atomic_t *atom, long value)
+{
+       long ret;
+
+       __asm__ __volatile__ (
+               "       amoadd.w.aqrl  %1, %2, %0"
+               : "+A" (atom->counter), "=r" (ret)
+               : "r" (value)
+               : "memory");
+
+       return ret + value;
+}
+
+long atomic_sub_return(atomic_t *atom, long value)
+{
+       long ret;
+
+       __asm__ __volatile__ (
+               "       amoadd.w.aqrl  %1, %2, %0"
+               : "+A" (atom->counter), "=r" (ret)
+               : "r" (-value)
+               : "memory");
+
+       return ret - value;
+}
+
+#define __xchg(ptr, new, size)                                         \
+({                                                                     \
+       __typeof__(ptr) __ptr = (ptr);                                  \
+       __typeof__(*(ptr)) __new = (new);                               \
+       __typeof__(*(ptr)) __ret;                                       \
+       register unsigned int __rc;                                     \
+       switch (size) {                                                 \
+       case 4:                                                         \
+               __asm__ __volatile__ (                                  \
+                       "0:     lr.w %0, %2\n"                          \
+                       "       sc.w.rl %1, %z3, %2\n"                  \
+                       "       bnez %1, 0b\n"                          \
+                       "       fence rw, rw\n"                         \
+                       : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
+                       : "rJ" (__new)                                  \
+                       : "memory");                                    \
+               break;                                                  \
+       case 8:                                                         \
+               __asm__ __volatile__ (                                  \
+                       "0:     lr.d %0, %2\n"                          \
+                       "       sc.d.rl %1, %z3, %2\n"                  \
+                       "       bnez %1, 0b\n"                          \
+                       "       fence rw, rw\n"                         \
+                       : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
+                       : "rJ" (__new)                                  \
+                       : "memory");                                    \
+               break;                                                  \
+       default:                                                        \
+               break;                                                  \
+       }                                                               \
+       __ret;                                                          \
+})
+
+#define xchg(ptr, n)                                                   \
+({                                                                     \
+       __typeof__(*(ptr)) _n_ = (n);                                   \
+       (__typeof__(*(ptr))) __xchg((ptr), _n_, sizeof(*(ptr)));        \
+})
+
+#define __cmpxchg(ptr, old, new, size)                                 \
+({                                                                     \
+       __typeof__(ptr) __ptr = (ptr);                                  \
+       __typeof__(*(ptr)) __old = (old);                               \
+       __typeof__(*(ptr)) __new = (new);                               \
+       __typeof__(*(ptr)) __ret;                                       \
+       register unsigned int __rc;                                     \
+       switch (size) {                                                 \
+       case 4:                                                         \
+               __asm__ __volatile__ (                                  \
+                       "0:     lr.w %0, %2\n"                          \
+                       "       bne  %0, %z3, 1f\n"                     \
+                       "       sc.w.rl %1, %z4, %2\n"                  \
+                       "       bnez %1, 0b\n"                          \
+                       "       fence rw, rw\n"                         \
+                       "1:\n"                                          \
+                       : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
+                       : "rJ" (__old), "rJ" (__new)                    \
+                       : "memory");                                    \
+               break;                                                  \
+       case 8:                                                         \
+               __asm__ __volatile__ (                                  \
+                       "0:     lr.d %0, %2\n"                          \
+                       "       bne %0, %z3, 1f\n"                      \
+                       "       sc.d.rl %1, %z4, %2\n"                  \
+                       "       bnez %1, 0b\n"                          \
+                       "       fence rw, rw\n"                         \
+                       "1:\n"                                          \
+                       : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
+                       : "rJ" (__old), "rJ" (__new)                    \
+                       : "memory");                                    \
+               break;                                                  \
+       default:                                                        \
+               break;                                                  \
+       }                                                               \
+       __ret;                                                          \
+})
+
+#define cmpxchg(ptr, o, n)                                             \
+({                                                                     \
+       __typeof__(*(ptr)) _o_ = (o);                                   \
+       __typeof__(*(ptr)) _n_ = (n);                                   \
+       (__typeof__(*(ptr))) __cmpxchg((ptr),                           \
+                                      _o_, _n_, sizeof(*(ptr)));       \
+})
+
+long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval)
+{
+       return cmpxchg(&atom->counter, oldval, newval);
+}
+
+long arch_atomic_xchg(atomic_t *atom, long newval)
+{
+       return xchg(&atom->counter, newval);
+}
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+                                 unsigned int newval)
+{
+       return xchg(ptr, newval);
+}
diff --git a/lib/riscv_locks.c b/lib/riscv_locks.c
new file mode 100644 (file)
index 0000000..0f94986
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_locks.h>
+
+int spin_lock_check(spinlock_t *lock)
+{
+       return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+       int tmp = 1, busy;
+
+       __asm__ __volatile__ (
+               "       amoswap.w %0, %2, %1\n"
+               RISCV_ACQUIRE_BARRIER
+               : "=r" (busy), "+A" (lock->lock)
+               : "r" (tmp)
+               : "memory");
+
+       return !busy;
+}
+
+void spin_lock(spinlock_t *lock)
+{
+       while (1) {
+               if (spin_lock_check(lock))
+                       continue;
+
+               if (spin_trylock(lock))
+                       break;
+       }
+}
+
+void spin_unlock(spinlock_t *lock)
+{
+       __smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
+}
diff --git a/lib/sbi_console.c b/lib/sbi_console.c
new file mode 100644 (file)
index 0000000..24b9d3c
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_console.h>
+
+static struct sbi_platform *console_plat = NULL;
+
+bool sbi_isprintable(char c)
+{
+       if (((31 < c) && (c < 127)) ||
+          (c == '\f') ||
+          (c == '\r') ||
+          (c == '\n') ||
+          (c == '\t')) {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+char sbi_getc(void)
+{
+       return sbi_platform_console_getc(console_plat);
+}
+
+void sbi_putc(char ch)
+{
+       sbi_platform_console_putc(console_plat, ch);
+}
+
+void sbi_puts(const char *str)
+{
+       while (*str) {
+               sbi_putc(*str);
+               str++;
+       }
+}
+
+void sbi_gets(char *s, int maxwidth, char endchar)
+{
+       char *retval;
+       char ch;
+       retval = s;
+       ch = sbi_getc();
+       while (ch != endchar && maxwidth > 0) {
+               *retval = ch;
+               retval++;
+               maxwidth--;
+               if (maxwidth == 0)
+                       break;
+               ch = sbi_getc();
+       }
+       *retval = '\0';
+       return;
+}
+
+#define PAD_RIGHT      1
+#define PAD_ZERO       2
+#define PAD_ALTERNATE  4
+#define PRINT_BUF_LEN  64
+
+#define va_start(v,l)          __builtin_va_start((v),l)
+#define va_end                 __builtin_va_end
+#define va_arg                 __builtin_va_arg
+typedef __builtin_va_list      va_list;
+
+static void printc(char **out, u32 *out_len, char ch)
+{
+       if (out) {
+               if (*out) {
+                       if (out_len && (0 < *out_len)) {
+                               **out = ch;
+                               ++(*out);
+                               (*out_len)--;
+                       } else {
+                               **out = ch;
+                               ++(*out);
+                       }
+               }
+       } else {
+               sbi_putc(ch);
+       }
+}
+
+static int prints(char **out, u32 *out_len, const char *string, int width, int flags)
+{
+       int pc = 0;
+       char padchar = ' ';
+
+       if (width > 0) {
+               int len = 0;
+               const char *ptr;
+               for (ptr = string; *ptr; ++ptr)
+                       ++len;
+               if (len >= width)
+                       width = 0;
+               else
+                       width -= len;
+               if (flags & PAD_ZERO)
+                       padchar = '0';
+       }
+       if (!(flags & PAD_RIGHT)) {
+               for (; width > 0; --width) {
+                       printc(out, out_len, padchar);
+                       ++pc;
+               }
+       }
+       for (; *string; ++string) {
+               printc(out, out_len, *string);
+               ++pc;
+       }
+       for (; width > 0; --width) {
+               printc(out, out_len, padchar);
+               ++pc;
+       }
+
+       return pc;
+}
+
+static int printi(char **out, u32 *out_len, long long i, int b, int sg,
+                 int width, int flags, int letbase)
+{
+       char print_buf[PRINT_BUF_LEN];
+       char *s;
+       int neg = 0, pc = 0;
+       u64 t;
+       unsigned long long u = i;
+
+       if (sg && b == 10 && i < 0) {
+               neg = 1;
+               u = -i;
+       }
+
+       s = print_buf + PRINT_BUF_LEN - 1;
+       *s = '\0';
+
+       if (!u) {
+               *--s = '0';
+       } else {
+               while (u) {
+                       t = u % b;
+                       u = u / b;
+                       if (t >= 10)
+                               t += letbase - '0' - 10;
+                       *--s = t + '0';
+               }
+       }
+
+       if (flags & PAD_ALTERNATE) {
+               if ((b == 16) && (letbase == 'A')) {
+                       *--s = 'X';
+               } else if ((b == 16) && (letbase == 'a')) {
+                       *--s = 'x';
+               }
+               *--s = '0';
+       }
+
+       if (neg) {
+               if (width && (flags & PAD_ZERO)) {
+                       printc(out, out_len, '-');
+                       ++pc;
+                       --width;
+               } else {
+                       *--s = '-';
+               }
+       }
+
+       return pc + prints(out, out_len, s, width, flags);
+}
+
+static int print(char **out, u32 *out_len, const char *format, va_list args)
+{
+       int width, flags, acnt = 0;
+       int pc = 0;
+       char scr[2];
+       unsigned long long tmp;
+
+       for (; *format != 0; ++format) {
+               if (*format == '%') {
+                       ++format;
+                       width = flags = 0;
+                       if (*format == '\0')
+                               break;
+                       if (*format == '%')
+                               goto out;
+                       /* Get flags */
+                       if (*format == '-') {
+                               ++format;
+                               flags = PAD_RIGHT;
+                       }
+                       if (*format == '#') {
+                               ++format;
+                               flags |= PAD_ALTERNATE;
+                       }
+                       while (*format == '0') {
+                               ++format;
+                               flags |= PAD_ZERO;
+                       }
+                       /* Get width */
+                       for (; *format >= '0' && *format <= '9'; ++format) {
+                               width *= 10;
+                               width += *format - '0';
+                       }
+                       if (*format == 's') {
+                               char *s = va_arg(args, char *);
+                               acnt += sizeof(char *);
+                               pc += prints(out, out_len,
+                                            s ? s : "(null)", width, flags);
+                               continue;
+                       }
+                       if ((*format == 'd') || (*format == 'i')) {
+                               pc += printi(out, out_len,
+                                       va_arg(args, int),
+                                       10, 1, width, flags, '0');
+                               acnt += sizeof(int);
+                               continue;
+                       }
+                       if (*format == 'x') {
+                               pc += printi(out, out_len,
+                                       va_arg(args, unsigned int),
+                                       16, 0, width, flags, 'a');
+                               acnt += sizeof(unsigned int);
+                               continue;
+                       }
+                       if (*format == 'X') {
+                               pc += printi(out, out_len,
+                                       va_arg(args, unsigned int),
+                                       16, 0, width, flags, 'A');
+                               acnt += sizeof(unsigned int);
+                               continue;
+                       }
+                       if (*format == 'u') {
+                               pc += printi(out, out_len,
+                                       va_arg(args, unsigned int),
+                                       10, 0, width, flags, 'a');
+                               acnt += sizeof(unsigned int);
+                               continue;
+                       }
+                       if (*format == 'p') {
+                               pc += printi(out, out_len,
+                                       va_arg(args, unsigned long),
+                                       16, 0, width, flags, 'a');
+                               acnt += sizeof(unsigned long);
+                               continue;
+                       }
+                       if (*format == 'P') {
+                               pc += printi(out, out_len,
+                                       va_arg(args, unsigned long),
+                                       16, 0, width, flags, 'A');
+                               acnt += sizeof(unsigned long);
+                               continue;
+                       }
+                       if (*format == 'l' && *(format + 1) == 'l') {
+                               while (acnt & (sizeof(unsigned long long)-1)) {
+                                       va_arg(args, int);
+                                       acnt += sizeof(int);
+                               }
+                               if (sizeof(unsigned long long) ==
+                                               sizeof(unsigned long)) {
+                                       tmp = va_arg(args, unsigned long long);
+                                       acnt += sizeof(unsigned long long);
+                               } else {
+                                       ((unsigned long *)&tmp)[0] =
+                                               va_arg(args, unsigned long);
+                                       ((unsigned long *)&tmp)[1] =
+                                               va_arg(args, unsigned long);
+                                       acnt += 2*sizeof(unsigned long);
+                               }
+                               if (*(format + 2) == 'u') {
+                                       format += 2;
+                                       pc += printi(out, out_len, tmp,
+                                               10, 0, width, flags, 'a');
+                               } else if (*(format + 2) == 'x') {
+                                       format += 2;
+                                       pc += printi(out, out_len, tmp,
+                                               16, 0, width, flags, 'a');
+                               } else if (*(format + 2) == 'X') {
+                                       format += 2;
+                                       pc += printi(out, out_len, tmp,
+                                               16, 0, width, flags, 'A');
+                               } else {
+                                       format += 1;
+                                       pc += printi(out, out_len, tmp,
+                                               10, 1, width, flags, '0');
+                               }
+                               continue;
+                       } else if (*format == 'l') {
+                               if (*(format + 1) == 'x') {
+                                       format += 1;
+                                       pc += printi(out, out_len,
+                                               va_arg(args, unsigned long),
+                                               16, 0, width, flags, 'a');
+                                       acnt += sizeof(unsigned long);
+                               } else if (*(format + 1) == 'X') {
+                                       format += 1;
+                                       pc += printi(out, out_len,
+                                               va_arg(args, unsigned long),
+                                               16, 0, width, flags, 'A');
+                                       acnt += sizeof(unsigned long);
+                               } else {
+                                       pc += printi(out, out_len,
+                                               va_arg(args, long),
+                                               10, 1, width, flags, '0');
+                                       acnt += sizeof(long);
+                               }
+                       }
+                       if (*format == 'c') {
+                               /* char are converted to int then pushed on the stack */
+                               scr[0] = va_arg(args, int);
+                               scr[1] = '\0';
+                               pc += prints(out, out_len, scr, width, flags);
+                               acnt += sizeof(int);
+                               continue;
+                       }
+               } else {
+out:
+                       printc(out, out_len, *format);
+                       ++pc;
+               }
+       }
+       if (out)
+               **out = '\0';
+       return pc;
+}
+
+int sbi_sprintf(char *out, const char *format, ...)
+{
+       va_list args;
+       int retval;
+       va_start(args, format);
+       retval = print(&out, NULL, format, args);
+       va_end(args);
+       return retval;
+}
+
+int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
+{
+       va_list args;
+       int retval;
+       va_start(args, format);
+       retval = print(&out, &out_sz, format, args);
+       va_end(args);
+       return retval;
+}
+
+int sbi_printf(const char *format, ...)
+{
+       va_list args;
+       int retval;
+       va_start(args, format);
+       retval = print(NULL, NULL, format, args);
+       va_end(args);
+       return retval;
+}
+
+int sbi_console_init(struct sbi_scratch *scratch)
+{
+       console_plat = sbi_platform_ptr(scratch);
+
+       return sbi_platform_console_init(console_plat);
+}
diff --git a/lib/sbi_ecall.c b/lib/sbi_ecall.c
new file mode 100644 (file)
index 0000000..928a8b7
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_trap.h>
+
+#define SBI_ECALL_VERSION_MAJOR                        0
+#define SBI_ECALL_VERSION_MINOR                        1
+
+#define SBI_ECALL_SET_TIMER                    0
+#define SBI_ECALL_CONSOLE_PUTCHAR              1
+#define SBI_ECALL_CONSOLE_GETCHAR              2
+#define SBI_ECALL_CLEAR_IPI                    3
+#define SBI_ECALL_SEND_IPI                     4
+#define SBI_ECALL_REMOTE_FENCE_I               5
+#define SBI_ECALL_REMOTE_SFENCE_VMA            6
+#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID       7
+#define SBI_ECALL_SHUTDOWN                     8
+
+u16 sbi_ecall_version_major(void)
+{
+       return SBI_ECALL_VERSION_MAJOR;
+}
+
+u16 sbi_ecall_version_minor(void)
+{
+       return SBI_ECALL_VERSION_MINOR;
+}
+
+int sbi_ecall_handler(u32 hartid, ulong mcause,
+                     struct sbi_trap_regs *regs,
+                     struct sbi_scratch *scratch)
+{
+       int ret = SBI_ENOTSUPP;
+
+       switch (regs->a7) {
+       case SBI_ECALL_SET_TIMER:
+#if __riscv_xlen == 32
+               sbi_timer_event_start(scratch, hartid,
+                       (((u64)regs->a1 << 32) || (u64)regs->a0));
+#else
+               sbi_timer_event_start(scratch, hartid, (u64)regs->a0);
+#endif
+               ret = 0;
+               break;
+       case SBI_ECALL_CONSOLE_PUTCHAR:
+               sbi_putc(regs->a0);
+               ret = 0;
+               break;
+       case SBI_ECALL_CONSOLE_GETCHAR:
+               regs->a0 = sbi_getc();
+               ret = 0;
+               break;
+       case SBI_ECALL_CLEAR_IPI:
+               sbi_ipi_clear_smode(scratch, hartid);
+               ret = 0;
+               break;
+       case SBI_ECALL_SEND_IPI:
+               ret = sbi_ipi_send_many(scratch, hartid,
+                                       (ulong *)regs->a0,
+                                       SBI_IPI_EVENT_SOFT);
+               break;
+       case SBI_ECALL_REMOTE_FENCE_I:
+               ret = sbi_ipi_send_many(scratch, hartid,
+                                       (ulong *)regs->a0,
+                                       SBI_IPI_EVENT_FENCE_I);
+               break;
+       case SBI_ECALL_REMOTE_SFENCE_VMA:
+       case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
+               ret = sbi_ipi_send_many(scratch, hartid,
+                                       (ulong *)regs->a0,
+                                       SBI_IPI_EVENT_SFENCE_VMA);
+               break;
+       case SBI_ECALL_SHUTDOWN:
+               sbi_system_shutdown(scratch, 0);
+               ret = 0;
+               break;
+       default:
+               break;
+       };
+
+       if (!ret) {
+               regs->mepc += 4;
+       }
+
+       return ret;
+}
diff --git a/lib/sbi_emulate_csr.c b/lib/sbi_emulate_csr.c
new file mode 100644 (file)
index 0000000..cc74f96
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_emulate_csr.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_timer.h>
+
+int sbi_emulate_csr_read(int csr_num,
+                        u32 hartid, ulong mstatus,
+                        struct sbi_scratch *scratch,
+                        ulong *csr_val)
+{
+       ulong cen = -1UL;
+
+       if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
+               cen = csr_read(scounteren);
+
+       switch (csr_num) {
+       case CSR_MISA:
+               *csr_val = csr_read(misa);
+               break;
+       case CSR_MVENDORID:
+               *csr_val = csr_read(mvendorid);
+               break;
+       case CSR_MARCHID:
+               *csr_val = csr_read(marchid);
+               break;
+       case CSR_MIMPID:
+               *csr_val = csr_read(mimpid);
+               break;
+       case CSR_MHARTID:
+               *csr_val = csr_read(mhartid);
+               break;
+       case CSR_CYCLE:
+               if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = csr_read(mcycle);
+               break;
+       case CSR_TIME:
+               if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = sbi_timer_value(scratch);
+               break;
+       case CSR_INSTRET:
+               if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = csr_read(minstret);
+               break;
+       case CSR_MHPMCOUNTER3:
+               if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
+                       return -1;
+               *csr_val = csr_read(mhpmcounter3);
+               break;
+       case CSR_MHPMCOUNTER4:
+               if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
+                       return -1;
+               *csr_val = csr_read(mhpmcounter4);
+               break;
+#if __riscv_xlen == 32
+       case CSR_CYCLEH:
+               if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = csr_read(mcycleh);
+               break;
+       case CSR_TIMEH:
+               if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = sbi_timer_value(scratch);
+               *csr_val = *csr_val >> 32;
+               break;
+       case CSR_INSTRETH:
+               if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
+                       return -1;
+               *csr_val = csr_read(minstreth);
+               break;
+       case CSR_MHPMCOUNTER3H:
+               if (!((cen >> (3 + CSR_MHPMCOUNTER3 - CSR_MHPMCOUNTER3)) & 1))
+                       return -1;
+               *csr_val = csr_read(mhpmcounter3h);
+               break;
+       case CSR_MHPMCOUNTER4H:
+               if (!((cen >> (3 + CSR_MHPMCOUNTER4 - CSR_MHPMCOUNTER3)) & 1))
+                       return -1;
+               *csr_val = csr_read(mhpmcounter4h);
+               break;
+#endif
+       case CSR_MHPMEVENT3:
+               *csr_val = csr_read(mhpmevent3);
+               break;
+       case CSR_MHPMEVENT4:
+               *csr_val = csr_read(mhpmevent4);
+               break;
+       default:
+               sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
+                          __func__, hartid, csr_num);
+               return SBI_ENOTSUPP;
+       };
+
+       return 0;
+}
+
+int sbi_emulate_csr_write(int csr_num,
+                         u32 hartid, ulong mstatus,
+                         struct sbi_scratch *scratch,
+                         ulong csr_val)
+{
+       switch (csr_num) {
+       case CSR_CYCLE:
+               csr_write(mcycle, csr_val);
+               break;
+       case CSR_INSTRET:
+               csr_write(minstret, csr_val);
+               break;
+       case CSR_MHPMCOUNTER3:
+               csr_write(mhpmcounter3, csr_val);
+               break;
+       case CSR_MHPMCOUNTER4:
+               csr_write(mhpmcounter4, csr_val);
+               break;
+#if __riscv_xlen == 32
+       case CSR_CYCLEH:
+               csr_write(mcycleh, csr_val);
+               break;
+       case CSR_INSTRETH:
+               csr_write(minstreth, csr_val);
+               break;
+       case CSR_MHPMCOUNTER3H:
+               csr_write(mhpmcounter3h, csr_val);
+               break;
+       case CSR_MHPMCOUNTER4H:
+               csr_write(mhpmcounter4h, csr_val);
+               break;
+#endif
+       case CSR_MHPMEVENT3:
+               csr_write(mhpmevent3, csr_val);
+               break;
+       case CSR_MHPMEVENT4:
+               csr_write(mhpmevent4, csr_val);
+               break;
+       default:
+               sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n",
+                          __func__, hartid, csr_num);
+               return SBI_ENOTSUPP;
+       };
+
+       return 0;
+}
diff --git a/lib/sbi_hart.c b/lib/sbi_hart.c
new file mode 100644 (file)
index 0000000..db833c7
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_locks.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+
+static int mstatus_init(u32 hartid)
+{
+       /* Enable FPU */
+       if (misa_extension('D') || misa_extension('F'))
+               csr_write(mstatus, MSTATUS_FS);
+
+       /* Enable user/supervisor use of perf counters */
+       if (misa_extension('S'))
+               csr_write(scounteren, -1);
+       csr_write(mcounteren, -1);
+
+       /* Disable all interrupts */
+       csr_write(mie, 0);
+
+       /* Disable S-mode paging */
+       if (misa_extension('S'))
+               csr_write(sptbr, 0);
+
+       return 0;
+}
+
+#ifdef __riscv_flen
+static void init_fp_reg(int i)
+{
+       /* TODO: */
+}
+#endif
+
+static int fp_init(u32 hartid)
+{
+#ifdef __riscv_flen
+       int i;
+#else
+       unsigned long fd_mask;
+#endif
+
+       if (!misa_extension('D') && !misa_extension('F'))
+               return 0;
+
+       if (!(csr_read(mstatus) & MSTATUS_FS))
+               return SBI_EINVAL;
+
+#ifdef __riscv_flen
+       for (i = 0; i < 32; i++)
+               init_fp_reg(i);
+       csr_write(fcsr, 0);
+#else
+       fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
+       csr_clear(misa, fd_mask);
+       if (csr_read(misa) & fd_mask)
+               return SBI_ENOTSUPP;
+#endif
+
+       return 0;
+}
+
+static int delegate_traps(u32 hartid)
+{
+       /* send S-mode interrupts and most exceptions straight to S-mode */
+       unsigned long interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
+       unsigned long exceptions = (1U << CAUSE_MISALIGNED_FETCH) |
+                                  (1U << CAUSE_FETCH_PAGE_FAULT) |
+                                  (1U << CAUSE_BREAKPOINT) |
+                                  (1U << CAUSE_LOAD_PAGE_FAULT) |
+                                  (1U << CAUSE_STORE_PAGE_FAULT) |
+                                  (1U << CAUSE_USER_ECALL);
+
+       if (!misa_extension('S'))
+               return 0;
+
+       csr_write(mideleg, interrupts);
+       csr_write(medeleg, exceptions);
+
+       if (csr_read(mideleg) != interrupts)
+               return SBI_EFAIL;
+       if (csr_read(medeleg) != exceptions)
+               return SBI_EFAIL;
+
+       return 0;
+}
+
+unsigned long log2roundup(unsigned long x)
+{
+       unsigned long ret = 0;
+
+       while (ret < __riscv_xlen) {
+               if (x <= (1UL << ret))
+                       break;
+               ret++;
+       }
+
+       return ret;
+}
+
+void sbi_hart_pmp_dump(void)
+{
+       unsigned int i;
+       unsigned long prot, addr, size, l2l;
+
+       for (i = 0; i < PMP_COUNT; i++) {
+               pmp_get(i, &prot, &addr, &l2l);
+               if (!(prot & PMP_A))
+                       continue;
+               if (l2l < __riscv_xlen)
+                       size = (1UL << l2l);
+               else
+                       size = 0;
+#if __riscv_xlen == 32
+               sbi_printf("PMP%d: 0x%08lx-0x%08lx (A",
+#else
+               sbi_printf("PMP%d: 0x%016lx-0x%016lx (A",
+#endif
+                          i, addr, addr + size - 1);
+               if (prot & PMP_L)
+                       sbi_printf(",L");
+               if (prot & PMP_R)
+                       sbi_printf(",R");
+               if (prot & PMP_W)
+                       sbi_printf(",W");
+               if (prot & PMP_X)
+                       sbi_printf(",X");
+               sbi_printf(")\n");
+       }
+}
+
+static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       u32 i, count;
+       unsigned long fw_start, fw_size_log2;
+       ulong prot, addr, log2size;
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       fw_size_log2 = log2roundup(scratch->fw_size);
+       fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
+
+       pmp_set(0, 0, fw_start, fw_size_log2);
+
+       count = sbi_platform_pmp_region_count(plat, hartid);
+       if ((PMP_COUNT - 1) < count)
+               count = (PMP_COUNT - 1);
+
+       for (i = 0; i < count; i++) {
+               if (sbi_platform_pmp_region_info(plat, hartid, i,
+                                                &prot, &addr, &log2size))
+                       continue;
+               pmp_set(i + 1, prot, addr, log2size);
+       }
+
+       return 0;
+}
+
+int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       int rc;
+
+       rc = mstatus_init(hartid);
+       if (rc)
+               return rc;
+
+       rc = fp_init(hartid);
+       if (rc)
+               return rc;
+
+       rc = delegate_traps(hartid);
+       if (rc)
+               return rc;
+
+       return pmp_init(scratch, hartid);
+}
+
+void __attribute__((noreturn)) sbi_hart_hang(void)
+{
+       while (1)
+               wfi();
+       __builtin_unreachable();
+}
+
+void __attribute__((noreturn)) sbi_hart_boot_next(unsigned long arg0,
+                                            unsigned long arg1,
+                                            unsigned long next_addr,
+                                            unsigned long next_mode)
+{
+       unsigned long val;
+
+       if (next_mode != PRV_S && next_mode != PRV_M && next_mode != PRV_U)
+               sbi_hart_hang();
+
+       val = csr_read(mstatus);
+       val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
+       val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
+       csr_write(mstatus, val);
+       csr_write(mepc, next_addr);
+
+       if (next_mode == PRV_S) {
+               csr_write(stvec, next_addr);
+               csr_write(sscratch, 0);
+               csr_write(sie, 0);
+               csr_write(satp, 0);
+       } else if (next_mode == PRV_U) {
+               csr_write(utvec, next_addr);
+               csr_write(uscratch, 0);
+               csr_write(uie, 0);
+       }
+
+       register unsigned long a0 asm ("a0") = arg0;
+       register unsigned long a1 asm ("a1") = arg1;
+       __asm__ __volatile__ ("mret" : : "r" (a0), "r" (a1));
+       __builtin_unreachable();
+}
+
+static spinlock_t avail_hart_mask_lock = SPIN_LOCK_INITIALIZER;
+static volatile unsigned long avail_hart_mask = 0;
+
+void sbi_hart_mark_available(u32 hartid)
+{
+       spin_lock(&avail_hart_mask_lock);
+       avail_hart_mask |= (1UL << hartid);
+       spin_unlock(&avail_hart_mask_lock);
+}
+
+void sbi_hart_unmark_available(u32 hartid)
+{
+       spin_lock(&avail_hart_mask_lock);
+       avail_hart_mask &= ~(1UL << hartid);
+       spin_unlock(&avail_hart_mask_lock);
+}
+
+ulong sbi_hart_available_mask(void)
+{
+       ulong ret;
+
+       spin_lock(&avail_hart_mask_lock);
+       ret = avail_hart_mask;
+       spin_unlock(&avail_hart_mask_lock);
+
+       return ret;
+}
+
+typedef struct sbi_scratch *(*h2s)(ulong hartid);
+
+struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
+                                          u32 hartid)
+{
+       return ((h2s)scratch->hartid_to_scratch)(hartid);
+}
+
+#define NO_HOTPLUG_BITMAP_SIZE __riscv_xlen
+static spinlock_t coldboot_holding_pen_lock = SPIN_LOCK_INITIALIZER;
+static volatile unsigned long coldboot_holding_pen = 0;
+
+void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
+{
+       unsigned long done;
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       if ((sbi_platform_hart_count(plat) <= hartid) ||
+           (NO_HOTPLUG_BITMAP_SIZE <= hartid))
+               sbi_hart_hang();
+
+       while (1) {
+               spin_lock(&coldboot_holding_pen_lock);
+               done = coldboot_holding_pen;
+               spin_unlock(&coldboot_holding_pen_lock);
+               if (done)
+                       break;
+               cpu_relax();
+       }
+}
+
+void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch)
+{
+       spin_lock(&coldboot_holding_pen_lock);
+       coldboot_holding_pen = 1;
+       spin_unlock(&coldboot_holding_pen_lock);
+}
diff --git a/lib/sbi_illegal_insn.c b/lib/sbi_illegal_insn.c
new file mode 100644 (file)
index 0000000..e8edd0e
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_emulate_csr.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_illegal_insn.h>
+#include <sbi/sbi_trap.h>
+#include <sbi/sbi_unpriv.h>
+
+#define SH_RD                  7
+#define SH_RS1                 15
+#define SH_RS2                 20
+#define SH_RS2C                        2
+
+#define RV_X(x, s, n)          (((x) >> (s)) & ((1 << (n)) - 1))
+#define RVC_LW_IMM(x)          ((RV_X(x, 6, 1) << 2) | \
+                                (RV_X(x, 10, 3) << 3) | \
+                                (RV_X(x, 5, 1) << 6))
+#define RVC_LD_IMM(x)          ((RV_X(x, 10, 3) << 3) | \
+                                (RV_X(x, 5, 2) << 6))
+#define RVC_LWSP_IMM(x)                ((RV_X(x, 4, 3) << 2) | \
+                                (RV_X(x, 12, 1) << 5) | \
+                                (RV_X(x, 2, 2) << 6))
+#define RVC_LDSP_IMM(x)                ((RV_X(x, 5, 2) << 3) | \
+                                (RV_X(x, 12, 1) << 5) | \
+                                (RV_X(x, 2, 3) << 6))
+#define RVC_SWSP_IMM(x)                ((RV_X(x, 9, 4) << 2) | \
+                                (RV_X(x, 7, 2) << 6))
+#define RVC_SDSP_IMM(x)                ((RV_X(x, 10, 3) << 3) | \
+                                (RV_X(x, 7, 3) << 6))
+#define RVC_RS1S(insn)         (8 + RV_X(insn, SH_RD, 3))
+#define RVC_RS2S(insn)         (8 + RV_X(insn, SH_RS2C, 3))
+#define RVC_RS2(insn)          RV_X(insn, SH_RS2C, 5)
+
+#define SHIFT_RIGHT(x, y)      ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
+
+#define REG_MASK               \
+((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES))
+
+#define REG_OFFSET(insn, pos)  \
+(SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK)
+
+#define REG_PTR(insn, pos, regs)\
+(ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))
+
+#define GET_RM(insn)           (((insn) >> 12) & 7)
+
+#define GET_RS1(insn, regs)    (*REG_PTR(insn, SH_RS1, regs))
+#define GET_RS2(insn, regs)    (*REG_PTR(insn, SH_RS2, regs))
+#define GET_RS1S(insn, regs)   (*REG_PTR(RVC_RS1S(insn), 0, regs))
+#define GET_RS2S(insn, regs)   (*REG_PTR(RVC_RS2S(insn), 0, regs))
+#define GET_RS2C(insn, regs)   (*REG_PTR(insn, SH_RS2C, regs))
+#define GET_SP(regs)           (*REG_PTR(2, 0, regs))
+#define SET_RD(insn, regs, val)        (*REG_PTR(insn, SH_RD, regs) = (val))
+#define IMM_I(insn)            ((s32)(insn) >> 20)
+#define IMM_S(insn)            (((s32)(insn) >> 25 << 5) | \
+                                (s32)(((insn) >> 7) & 0x1f))
+#define MASK_FUNCT3            0x7000
+
+typedef int (*illegal_insn_func)(ulong insn,
+                                u32 hartid, ulong mcause,
+                                struct sbi_trap_regs *regs,
+                                struct sbi_scratch *scratch);
+
+static int truly_illegal_insn(ulong insn,
+                             u32 hartid, ulong mcause,
+                             struct sbi_trap_regs *regs,
+                             struct sbi_scratch *scratch)
+{
+       /* For now, always fails */
+       return SBI_ENOTSUPP;
+}
+
+static int system_opcode_insn(ulong insn,
+                             u32 hartid, ulong mcause,
+                             struct sbi_trap_regs *regs,
+                             struct sbi_scratch *scratch)
+{
+       int do_write, rs1_num = (insn >> 15) & 0x1f;
+       ulong rs1_val = GET_RS1(insn, regs);
+       int csr_num = (u32)insn >> 20;
+       ulong csr_val, new_csr_val;
+
+       if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus,
+                                scratch, &csr_val))
+               return truly_illegal_insn(insn, hartid, mcause,
+                                         regs, scratch);
+
+       do_write = rs1_num;
+       switch (GET_RM(insn)) {
+       case 1:
+               new_csr_val = rs1_val;
+               do_write = 1;
+               break;
+       case 2:
+               new_csr_val = csr_val | rs1_val;
+               break;
+       case 3: new_csr_val = csr_val & ~rs1_val;
+               break;
+       case 5:
+               new_csr_val = rs1_num;
+               do_write = 1;
+               break;
+       case 6:
+               new_csr_val = csr_val | rs1_num;
+               break;
+       case 7:
+               new_csr_val = csr_val & ~rs1_num;
+               break;
+       default:
+               return truly_illegal_insn(insn, hartid, mcause,
+                                         regs, scratch);
+       };
+
+       if (do_write &&
+           sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
+                                 scratch, new_csr_val))
+               return truly_illegal_insn(insn, hartid, mcause,
+                                         regs, scratch);
+
+       SET_RD(insn, regs, csr_val);
+
+       regs->mepc += 4;
+
+       return 0;
+}
+
+static illegal_insn_func illegal_insn_table[32] = {
+       truly_illegal_insn, /* 0 */
+       truly_illegal_insn, /* 1 */
+       truly_illegal_insn, /* 2 */
+       truly_illegal_insn, /* 3 */
+       truly_illegal_insn, /* 4 */
+       truly_illegal_insn, /* 5 */
+       truly_illegal_insn, /* 6 */
+       truly_illegal_insn, /* 7 */
+       truly_illegal_insn, /* 8 */
+       truly_illegal_insn, /* 9 */
+       truly_illegal_insn, /* 10 */
+       truly_illegal_insn, /* 11 */
+       truly_illegal_insn, /* 12 */
+       truly_illegal_insn, /* 13 */
+       truly_illegal_insn, /* 14 */
+       truly_illegal_insn, /* 15 */
+       truly_illegal_insn, /* 16 */
+       truly_illegal_insn, /* 17 */
+       truly_illegal_insn, /* 18 */
+       truly_illegal_insn, /* 19 */
+       truly_illegal_insn, /* 20 */
+       truly_illegal_insn, /* 21 */
+       truly_illegal_insn, /* 22 */
+       truly_illegal_insn, /* 23 */
+       truly_illegal_insn, /* 24 */
+       truly_illegal_insn, /* 25 */
+       truly_illegal_insn, /* 26 */
+       truly_illegal_insn, /* 27 */
+       system_opcode_insn, /* 28 */
+       truly_illegal_insn, /* 29 */
+       truly_illegal_insn, /* 30 */
+       truly_illegal_insn  /* 31 */
+};
+
+int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
+                            struct sbi_trap_regs *regs,
+                            struct sbi_scratch *scratch)
+{
+       ulong mstatus;
+       ulong insn = csr_read(mbadaddr);
+
+       if (unlikely((insn & 3) != 3)) {
+               if (insn == 0) {
+                       mstatus = csr_read(mstatus);
+                       insn = get_insn(regs->mepc, &mstatus);
+               }
+               if ((insn & 3) != 3)
+                       return SBI_ENOTSUPP;
+       }
+
+       return illegal_insn_table[(insn & 0x7c) >> 2](insn, hartid, mcause,
+                                                     regs, scratch);
+}
diff --git a/lib/sbi_init.c b/lib/sbi_init.c
new file mode 100644 (file)
index 0000000..52c63fa
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_atomic.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+
+static void __attribute__((noreturn)) init_coldboot(struct sbi_scratch *scratch,
+                                                   u32 hartid)
+{
+       int rc;
+       char str[64];
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       rc = sbi_system_cold_early_init(scratch);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_system_warm_early_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_hart_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_console_init(scratch);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_platform_cold_irqchip_init(plat);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_platform_warm_irqchip_init(plat, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_ipi_cold_init(scratch);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_ipi_warm_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_timer_cold_init(scratch);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_timer_warm_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_system_cold_final_init(scratch);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_system_warm_final_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       misa_string(str, sizeof(str));
+       sbi_printf("OpenSBI v%d.%d (%s %s)\n",
+                  OPENSBI_MAJOR, OPENSBI_MINOR,
+                  __DATE__, __TIME__);
+       sbi_printf("\n");
+       /* Platform details */
+       sbi_printf("Platform Name          : %s\n", sbi_platform_name(plat));
+       sbi_printf("Platform HART Features : RV%d%s\n", misa_xlen(), str);
+       sbi_printf("Platform Max HARTs     : %d\n",
+                  sbi_platform_hart_count(plat));
+       /* Firmware details */
+       sbi_printf("Firmware Base          : 0x%lx\n", scratch->fw_start);
+       sbi_printf("Firmware Size          : %d KB\n",
+                  (u32)(scratch->fw_size / 1024));
+       /* Generic details */
+       sbi_printf("Runtime SBI Version    : %d.%d\n",
+                  sbi_ecall_version_major(), sbi_ecall_version_minor());
+       sbi_printf("\n");
+
+       sbi_hart_pmp_dump();
+
+       sbi_hart_mark_available(hartid);
+
+       if (!sbi_platform_has_hart_hotplug(plat))
+               sbi_hart_wake_coldboot_harts(scratch);
+
+       sbi_hart_boot_next(hartid, scratch->next_arg1,
+                          scratch->next_addr, scratch->next_mode);
+}
+
+static void __attribute__((noreturn)) init_warmboot(struct sbi_scratch *scratch,
+                                                   u32 hartid)
+{
+       int rc;
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       if (!sbi_platform_has_hart_hotplug(plat))
+               sbi_hart_wait_for_coldboot(scratch, hartid);
+
+       rc = sbi_system_warm_early_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_hart_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_platform_warm_irqchip_init(plat, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_ipi_warm_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_timer_warm_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       rc = sbi_system_warm_final_init(scratch, hartid);
+       if (rc)
+               sbi_hart_hang();
+
+       sbi_hart_mark_available(hartid);
+
+       if (sbi_platform_has_hart_hotplug(plat))
+               /* TODO: To be implemented in-future. */
+               sbi_hart_hang();
+       else
+               sbi_hart_boot_next(hartid, scratch->next_arg1,
+                                  scratch->next_addr, scratch->next_mode);
+}
+
+static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
+
+void __attribute__((noreturn)) sbi_init(struct sbi_scratch *scratch)
+{
+       bool coldboot = FALSE;
+       u32 hartid = csr_read(mhartid);
+
+       if (atomic_add_return(&coldboot_lottery, 1) == 1)
+               coldboot = TRUE;
+
+       if (coldboot)
+               init_coldboot(scratch, hartid);
+       else
+               init_warmboot(scratch, hartid);
+}
diff --git a/lib/sbi_ipi.c b/lib/sbi_ipi.c
new file mode 100644 (file)
index 0000000..f3e68de
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_unpriv.h>
+
+int sbi_ipi_send_many(struct sbi_scratch *scratch,
+                     u32 hartid, ulong *pmask, u32 event)
+{
+       ulong i, m;
+       struct sbi_scratch *oth;
+       ulong mask = sbi_hart_available_mask();
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       if (pmask)
+               mask &= load_ulong(pmask, csr_read(mepc));
+
+       /* send IPIs to everyone */
+       for (i = 0, m = mask; m; i++, m >>= 1) {
+               if ((m & 1) && (i != hartid)) {
+                       oth = sbi_hart_id_to_scratch(scratch, i);
+                       oth->ipi_type = event;
+                       mb();
+                       sbi_platform_ipi_inject(plat, i, hartid);
+                       if (event != SBI_IPI_EVENT_SOFT)
+                               sbi_platform_ipi_sync(plat, i, hartid);
+               }
+       }
+
+       return 0;
+}
+
+void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid)
+{
+       csr_clear(mip, MIP_SSIP);
+}
+
+void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid)
+{
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       sbi_platform_ipi_clear(plat, hartid);
+       switch (scratch->ipi_type) {
+       case SBI_IPI_EVENT_SOFT:
+               csr_set(mip, MIP_SSIP);
+               break;
+       case SBI_IPI_EVENT_FENCE_I:
+               __asm__ __volatile("fence.i");
+               break;
+       case SBI_IPI_EVENT_SFENCE_VMA:
+               __asm__ __volatile("sfence.vma");
+               break;
+       case SBI_IPI_EVENT_HALT:
+               sbi_hart_hang();
+               break;
+       };
+       scratch->ipi_type = 0;
+}
+
+int sbi_ipi_warm_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       /* Enable software interrupts */
+       csr_set(mie, MIP_MSIP);
+
+       return sbi_platform_warm_ipi_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_ipi_cold_init(struct sbi_scratch *scratch)
+{
+       return sbi_platform_cold_ipi_init(sbi_platform_ptr(scratch));
+}
diff --git a/lib/sbi_system.c b/lib/sbi_system.c
new file mode 100644 (file)
index 0000000..cd250f5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+
+int sbi_system_warm_early_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       return sbi_platform_warm_early_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_system_warm_final_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       return sbi_platform_warm_final_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_system_cold_early_init(struct sbi_scratch *scratch)
+{
+       return sbi_platform_cold_early_init(sbi_platform_ptr(scratch));
+}
+
+int sbi_system_cold_final_init(struct sbi_scratch *scratch)
+{
+       return sbi_platform_cold_final_init(sbi_platform_ptr(scratch));
+}
+
+void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
+                                                u32 type)
+
+{
+       sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
+       sbi_hart_hang();
+}
+
+void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
+                                                  u32 type)
+{
+       sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
+       sbi_hart_hang();
+}
diff --git a/lib/sbi_timer.c b/lib/sbi_timer.c
new file mode 100644 (file)
index 0000000..355bc64
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_timer.h>
+
+#if __riscv_xlen == 32
+u64 get_ticks(void)
+{
+       u32 lo, hi, tmp;
+       __asm__ __volatile__ (
+               "1:\n"
+               "rdtimeh %0\n"
+               "rdtime %1\n"
+               "rdtimeh %2\n"
+               "bne %0, %2, 1b"
+               : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+       return ((u64)hi << 32) | lo;
+}
+#else
+u64 get_ticks(void)
+{
+       unsigned long n;
+
+       __asm__ __volatile__ (
+               "rdtime %0"
+               : "=r" (n));
+       return n;
+}
+#endif
+
+u64 sbi_timer_value(struct sbi_scratch *scratch)
+{
+       struct sbi_platform *plat = sbi_platform_ptr(scratch);
+
+       if (sbi_platform_has_mmio_timer_value(plat))
+               return sbi_platform_timer_value(plat);
+       else
+               return get_ticks();
+}
+
+void sbi_timer_event_stop(struct sbi_scratch *scratch, u32 hartid)
+{
+       sbi_platform_timer_event_stop(sbi_platform_ptr(scratch), hartid);
+}
+
+void sbi_timer_event_start(struct sbi_scratch *scratch, u32 hartid,
+                          u64 next_event)
+{
+       sbi_platform_timer_event_start(sbi_platform_ptr(scratch),
+                                      hartid, next_event);
+       csr_clear(mip, MIP_STIP);
+       csr_set(mie, MIP_MTIP);
+}
+
+void sbi_timer_process(struct sbi_scratch *scratch, u32 hartid)
+{
+       csr_clear(mie, MIP_MTIP);
+       csr_set(mip, MIP_STIP);
+}
+
+int sbi_timer_warm_init(struct sbi_scratch *scratch, u32 hartid)
+{
+       return sbi_platform_warm_timer_init(sbi_platform_ptr(scratch), hartid);
+}
+
+int sbi_timer_cold_init(struct sbi_scratch *scratch)
+{
+       return sbi_platform_cold_timer_init(sbi_platform_ptr(scratch));
+}
diff --git a/lib/sbi_trap.c b/lib/sbi_trap.c
new file mode 100644 (file)
index 0000000..f9c70a6
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_illegal_insn.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_trap.h>
+
+static void __attribute__((noreturn)) sbi_trap_error(const char *msg,
+                                               int rc, u32 hartid,
+                                               ulong mcause,
+                                               struct sbi_trap_regs *regs)
+{
+       sbi_printf("%s: hart%d: %s (error %d)\n",
+                  __func__, hartid, msg, rc);
+       sbi_printf("%s: hart%d: mcause=0x%lx mepc=0x%lx mstatus=0x%lx\n",
+                  __func__, hartid, mcause, regs->mepc, regs->mstatus);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "ra", regs->ra, "sp", regs->sp);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "gp", regs->gp, "tp", regs->tp);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s0", regs->s0, "s1", regs->s1);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "a0", regs->a0, "a1", regs->a1);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "a2", regs->a2, "a3", regs->a3);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "a4", regs->a4, "a5", regs->a5);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "a6", regs->a6, "a7", regs->a7);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s2", regs->s2, "s3", regs->s3);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s4", regs->s4, "s5", regs->s5);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s6", regs->s6, "s7", regs->s7);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s8", regs->s8, "s9", regs->s9);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "s10", regs->s10, "s11", regs->s11);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "t0", regs->t0, "t1", regs->t1);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "t2", regs->t2, "t3", regs->t3);
+       sbi_printf("%s: hart%d: %s=0x%lx %s=0x%lx\n",
+                  __func__, hartid, "t4", regs->t4, "t5", regs->t5);
+       sbi_printf("%s: hart%d: %s=0x%lx\n",
+                  __func__, hartid, "t6", regs->t6);
+
+       sbi_hart_hang();
+}
+
+void sbi_trap_handler(struct sbi_trap_regs *regs,
+                     struct sbi_scratch *scratch)
+{
+       int rc;
+       const char *msg;
+       u32 hartid = csr_read(mhartid);
+       ulong mcause = csr_read(mcause);
+
+       if (mcause & (1UL << (__riscv_xlen - 1))) {
+               mcause &= ~(1UL << (__riscv_xlen - 1));
+               switch (mcause) {
+               case IRQ_M_TIMER:
+                       sbi_timer_process(scratch, hartid);
+                       break;
+               case IRQ_M_SOFT:
+                       sbi_ipi_process(scratch, hartid);
+                       break;
+               default:
+                       sbi_trap_error("unhandled external interrupt",
+                                       SBI_ENOTSUPP, hartid, mcause, regs);
+                       break;
+               };
+               return;
+       }
+
+       rc = SBI_ENOTSUPP;
+       msg = "trap handler failed";
+       switch (mcause) {
+       case CAUSE_ILLEGAL_INSTRUCTION:
+               rc = sbi_illegal_insn_handler(hartid, mcause, regs, scratch);
+               msg = "illegal instruction handler failed";
+               break;
+       case CAUSE_SUPERVISOR_ECALL:
+       case CAUSE_HYPERVISOR_ECALL:
+               rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
+               msg = "ecall handler failed";
+               break;
+       default:
+               break;
+       };
+
+       if (rc) {
+               sbi_trap_error(msg, rc, hartid, mcause, regs);
+       }
+}
diff --git a/plat/common/fdt.c b/plat/common/fdt.c
new file mode 100644 (file)
index 0000000..4f6017c
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <plat/fdt.h>
+
+#define FDT_MAGIC      0xd00dfeed
+#define FDT_VERSION    17
+
+struct fdt_header {
+       u32 magic;
+       u32 totalsize;
+       u32 off_dt_struct;
+       u32 off_dt_strings;
+       u32 off_mem_rsvmap;
+       u32 version;
+       u32 last_comp_version; /* <= 17 */
+       u32 boot_cpuid_phys;
+       u32 size_dt_strings;
+       u32 size_dt_struct;
+} __attribute__((packed));
+
+#define FDT_BEGIN_NODE 1
+#define FDT_END_NODE   2
+#define FDT_PROP       3
+#define FDT_NOP                4
+#define FDT_END                9
+
+u32 fdt_rev32(u32 v)
+{
+       return ((v & 0x000000FF) << 24) |
+              ((v & 0x0000FF00) << 8) |
+              ((v & 0x00FF0000) >> 8) |
+              ((v & 0xFF000000) >> 24);
+}
+
+ulong fdt_strlen(const char *str)
+{
+       ulong ret = 0;
+
+       while (*str != '\0') {
+               ret++;
+               str++;
+       }
+
+       return ret;
+}
+
+int fdt_strcmp(const char *a, const char *b)
+{
+       /* search first diff or end of string */
+       for (; *a == *b && *a != '\0'; a++, b++);
+       return *a - *b;
+}
+
+int fdt_prop_string_index(const struct fdt_prop *prop,
+                         const char *str)
+{
+       int i;
+       ulong l = 0;
+       const char *p, *end;
+
+       p = prop->value;
+       end = p + prop->len;
+
+       for (i = 0; p < end; i++, p += l) {
+               l = fdt_strlen(p) + 1;
+               if (p + l > end)
+                       return -1;
+               if (fdt_strcmp(str, p) == 0)
+                       return i; /* Found it; return index */
+       }
+
+       return -1;
+}
+
+struct recursive_iter_info {
+       void (*fn)(const struct fdt_node *node,
+                  const struct fdt_prop *prop,
+                  void *priv);
+       void *fn_priv;
+       const char *str;
+};
+
+#define DATA32(ptr)    fdt_rev32(*((u32*)ptr))
+
+static void recursive_iter(char **data, struct recursive_iter_info *info,
+                          const struct fdt_node *parent)
+{
+       struct fdt_node node;
+       struct fdt_prop prop;
+
+       if (DATA32(*data) != FDT_BEGIN_NODE)
+               return;
+
+       node.data = *data;
+
+       (*data) += sizeof(u32);
+
+       node.parent = parent;
+       node.name = *data;
+
+       *data += fdt_strlen(*data) + 1;
+       while ((ulong)(*data) % sizeof(u32) != 0)
+               (*data)++;
+
+       node.depth = (parent) ? (parent->depth + 1) : 1;
+
+       /* Default cell counts, as per the FDT spec */
+       node.address_cells = 2;
+       node.size_cells = 1;
+
+       info->fn(&node, NULL, info->fn_priv);
+
+       while (DATA32(*data) != FDT_END_NODE) {
+               switch (DATA32(*data)) {
+               case FDT_PROP:
+                       prop.node = &node;
+                       *data += sizeof(u32);
+                       prop.len = DATA32(*data);
+                       *data += sizeof(u32);
+                       prop.name = &info->str[DATA32(*data)];
+                       *data += sizeof(u32);
+                       prop.value = *data;
+                       *data += prop.len;
+                       while ((ulong)(*data) % sizeof(u32) != 0)
+                               (*data)++;
+                       info->fn(&node, &prop, info->fn_priv);
+                       break;
+               case FDT_NOP:
+                       *data += sizeof(u32);
+                       break;
+               case FDT_BEGIN_NODE:
+                       recursive_iter(data, info, &node);
+                       break;
+               default:
+                       return;
+               };
+       }
+
+       *data += sizeof(u32);
+}
+
+struct match_iter_info {
+       int (*match)(const struct fdt_node *node,
+                    const struct fdt_prop *prop,
+                    void *priv);
+       void *match_priv;
+       void (*fn)(const struct fdt_node *node,
+                  const struct fdt_prop *prop,
+                  void *priv);
+       void *fn_priv;
+       const char *str;
+};
+
+static void match_iter(const struct fdt_node *node,
+                      const struct fdt_prop *prop,
+                      void *priv)
+{
+       char *data;
+       struct match_iter_info *minfo = priv;
+       struct fdt_prop nprop;
+
+       /* Do nothing if node+prop dont match */
+       if (!minfo->match(node, prop, minfo->match_priv))
+               return;
+
+       /* Call function for node */
+       if (minfo->fn)
+               minfo->fn(node, NULL, minfo->fn_priv);
+
+       /* Convert node to character stream */
+       data = node->data;
+       data += sizeof(u32);
+
+       /* Skip node name */
+       data += fdt_strlen(data) + 1;
+       while ((ulong)(data) % sizeof(u32) != 0)
+               data++;
+
+       /* Find node property and its value */
+       while (DATA32(data) == FDT_PROP) {
+               nprop.node = node;
+               data += sizeof(u32);
+               nprop.len = DATA32(data);
+               data += sizeof(u32);
+               nprop.name = &minfo->str[DATA32(data)];
+               data += sizeof(u32);
+               nprop.value = data;
+               data += nprop.len;
+               while ((ulong)(data) % sizeof(u32) != 0)
+                       (data)++;
+               /* Call function for every property */
+               if (minfo->fn)
+                       minfo->fn(node, &nprop, minfo->fn_priv);
+       }
+}
+
+int fdt_match_node_prop(void *fdt,
+                       int (*match)(const struct fdt_node *node,
+                                    const struct fdt_prop *prop,
+                                    void *priv),
+                       void *match_priv,
+                       void (*fn)(const struct fdt_node *node,
+                                  const struct fdt_prop *prop,
+                                  void *priv),
+                       void *fn_priv)
+{
+       char *data;
+       u32 string_offset, data_offset;
+       struct fdt_header *header;
+       struct match_iter_info minfo;
+       struct recursive_iter_info rinfo;
+
+       if (!fdt || !match)
+               return -1;
+       header = fdt;
+       if (fdt_rev32(header->magic) != FDT_MAGIC ||
+           fdt_rev32(header->last_comp_version) > FDT_VERSION)
+               return -1;
+       string_offset = fdt_rev32(header->off_dt_strings);
+       data_offset = fdt_rev32(header->off_dt_struct);
+
+       minfo.match = match;
+       minfo.match_priv = match_priv;
+       minfo.fn = fn;
+       minfo.fn_priv = fn_priv;
+       minfo.str = (const char *)(fdt + string_offset);
+
+       rinfo.fn = match_iter;
+       rinfo.fn_priv = &minfo;
+       rinfo.str = minfo.str;
+
+       data = (char *)(fdt + data_offset);
+       recursive_iter(&data, &rinfo, NULL);
+
+       return 0;
+}
+
+struct match_compat_info {
+       const char *compat;
+};
+
+static int match_compat(const struct fdt_node *node,
+                       const struct fdt_prop *prop,
+                       void *priv)
+{
+       struct match_compat_info *cinfo = priv;
+
+       if (!prop)
+               return 0;
+
+       if (fdt_strcmp(prop->name, "compatible"))
+               return 0;
+
+       if (fdt_prop_string_index(prop, cinfo->compat) < 0)
+               return 0;
+
+       return 1;
+}
+
+int fdt_compat_node_prop(void *fdt,
+                        const char *compat,
+                        void (*fn)(const struct fdt_node *node,
+                                   const struct fdt_prop *prop,
+                                   void *priv),
+                        void *fn_priv)
+{
+       struct match_compat_info cinfo = { .compat = compat };
+
+       return fdt_match_node_prop(fdt, match_compat, &cinfo,
+                                      fn, fn_priv);
+}
+
+static int match_walk(const struct fdt_node *node,
+                     const struct fdt_prop *prop,
+                     void *priv)
+{
+       if (!prop)
+               return 1;
+
+       return 0;
+}
+
+int fdt_walk(void *fdt,
+            void (*fn)(const struct fdt_node *node,
+                       const struct fdt_prop *prop,
+                       void *priv),
+            void *fn_priv)
+{
+       return fdt_match_node_prop(fdt, match_walk, NULL,
+                                      fn, fn_priv);
+}
+
+u32 fdt_size(void *fdt)
+{
+       struct fdt_header *header;
+
+       if (!fdt)
+               return 0;
+
+       header = fdt;
+       if (fdt_rev32(header->magic) != FDT_MAGIC ||
+           fdt_rev32(header->last_comp_version) > FDT_VERSION)
+               return 0;
+
+       return fdt_rev32(header->totalsize);
+}
diff --git a/plat/common/include/plat/fdt.h b/plat/common/include/plat/fdt.h
new file mode 100644 (file)
index 0000000..246243f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __FDT_H__
+#define __FDT_H__
+
+#include <sbi/sbi_types.h>
+
+struct fdt_node {
+       char *data;
+       const struct fdt_node *parent;
+       const char *name;
+       int depth;
+       int address_cells;
+       int size_cells;
+};
+
+struct fdt_prop {
+       const struct fdt_node *node;
+       const char *name;
+       void *value;
+       u32 len;
+};
+
+/* Reverse byte-order of 32bit number */
+u32 fdt_rev32(u32 v);
+
+/* Length of a string */
+ulong fdt_strlen(const char *str);
+
+/* Compate two strings */
+int fdt_strcmp(const char *a, const char *b);
+
+/* Find index of matching string from a list of strings */
+int fdt_prop_string_index(const struct fdt_prop *prop,
+                             const char *str);
+
+/* Iterate over each property of matching node */
+int fdt_match_node_prop(void *fdt,
+                       int (*match)(const struct fdt_node *node,
+                                    const struct fdt_prop *prop,
+                                    void *priv),
+                       void *match_priv,
+                       void (*fn)(const struct fdt_node *node,
+                                  const struct fdt_prop *prop,
+                                  void *priv),
+                       void *fn_priv);
+
+/* Iterate over each property of compatible node */
+int fdt_compat_node_prop(void *fdt,
+                        const char *compat,
+                        void (*fn)(const struct fdt_node *node,
+                                   const struct fdt_prop *prop,
+                                   void *priv),
+                        void *fn_priv);
+
+/* Iterate over each node and property */
+int fdt_walk(void *fdt,
+            void (*fn)(const struct fdt_node *node,
+                       const struct fdt_prop *prop,
+                       void *priv),
+            void *fn_priv);
+
+/* Get size of FDT */
+u32 fdt_size(void *fdt);
+
+#endif
diff --git a/plat/common/include/plat/irqchip/plic.h b/plat/common/include/plat/irqchip/plic.h
new file mode 100644 (file)
index 0000000..7c062aa
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __IRQCHIP_PLIC_H__
+#define __IRQCHIP_PLIC_H__
+
+#include <sbi/sbi_types.h>
+
+int plic_fdt_fixup(void *fdt, const char *compat);
+
+int plic_warm_irqchip_init(u32 target_hart);
+
+int plic_cold_irqchip_init(unsigned long base,
+                          u32 num_sources, u32 hart_count);
+
+#endif
diff --git a/plat/common/include/plat/serial/sifive-uart.h b/plat/common/include/plat/serial/sifive-uart.h
new file mode 100644 (file)
index 0000000..b932b16
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_SIFIVE_UART_H__
+#define __SERIAL_SIFIVE_UART_H__
+
+#include <sbi/sbi_types.h>
+
+void sifive_uart_putc(char ch);
+
+char sifive_uart_getc(void);
+
+int sifive_uart_init(unsigned long base,
+                    u32 in_freq, u32 baudrate);
+
+#endif
diff --git a/plat/common/include/plat/serial/uart8250.h b/plat/common/include/plat/serial/uart8250.h
new file mode 100644 (file)
index 0000000..ca19a9f
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_UART8250_H__
+#define __SERIAL_UART8250_H__
+
+#include <sbi/sbi_types.h>
+
+void uart8250_putc(char ch);
+
+char uart8250_getc(void);
+
+int uart8250_init(unsigned long base,
+                 u32 in_freq, u32 baudrate,
+                 u32 reg_shift, u32 reg_width);
+
+#endif
diff --git a/plat/common/include/plat/sys/clint.h b/plat/common/include/plat/sys/clint.h
new file mode 100644 (file)
index 0000000..642d83a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SYS_CLINT_H__
+#define __SYS_CLINT_H__
+
+#include <sbi/sbi_types.h>
+
+void clint_ipi_inject(u32 target_hart, u32 source_hart);
+
+void clint_ipi_sync(u32 target_hart, u32 source_hart);
+
+void clint_ipi_clear(u32 target_hart);
+
+int clint_warm_ipi_init(u32 target_hart);
+
+int clint_cold_ipi_init(unsigned long base, u32 hart_count);
+
+u64 clint_timer_value(void);
+
+void clint_timer_event_stop(u32 target_hart);
+
+void clint_timer_event_start(u32 target_hart, u64 next_event);
+
+int clint_warm_timer_init(u32 target_hart);
+
+int clint_cold_timer_init(unsigned long base, u32 hart_count);
+
+#endif
diff --git a/plat/common/irqchip/objects.mk b/plat/common/irqchip/objects.mk
new file mode 100644 (file)
index 0000000..3950734
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_IRQCHIP_PLIC) += irqchip/plic.o
diff --git a/plat/common/irqchip/plic.c b/plat/common/irqchip/plic.c
new file mode 100644 (file)
index 0000000..404d1b7
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/fdt.h>
+#include <plat/irqchip/plic.h>
+
+#define PLIC_PRIORITY_BASE             0x0
+#define PLIC_PENDING_BASE              0x1000
+#define PLIC_ENABLE_BASE               0x2000
+#define PLIC_ENABLE_STRIDE             0x80
+#define PLIC_CONTEXT_BASE              0x200000
+#define PLIC_CONTEXT_STRIDE            0x1000
+
+static u32 plic_hart_count;
+static u32 plic_num_sources;
+static volatile void *plic_base;
+
+static void plic_set_priority(u32 source, u32 val)
+{
+       writel(val, plic_base);
+}
+
+static void plic_set_m_thresh(u32 hartid, u32 val)
+{
+       volatile void *plic_m_thresh = plic_base +
+                               PLIC_CONTEXT_BASE +
+                               PLIC_CONTEXT_STRIDE * (2 * hartid);
+       writel(val, plic_m_thresh);
+}
+
+static void plic_set_s_thresh(u32 hartid, u32 val)
+{
+       volatile void *plic_s_thresh = plic_base +
+                               PLIC_CONTEXT_BASE +
+                               PLIC_CONTEXT_STRIDE * (2 * hartid + 1);
+       writel(val, plic_s_thresh);
+}
+
+static void plic_set_s_ie(u32 hartid, u32 word_index, u32 val)
+{
+       volatile void *plic_s_ie = plic_base +
+                               PLIC_ENABLE_BASE +
+                               PLIC_ENABLE_STRIDE * (2 * hartid + 1);
+       writel(val, plic_s_ie + word_index * 4);
+}
+
+static void plic_fdt_fixup_prop(const struct fdt_node *node,
+                               const struct fdt_prop *prop,
+                               void *priv)
+{
+       u32 *cells;
+       u32 i, cells_count;
+
+       if (!prop)
+               return;
+       if (fdt_strcmp(prop->name, "interrupts-extended"))
+               return;
+
+       cells = prop->value;
+       cells_count = prop->len / sizeof(u32);
+
+       if (!cells_count)
+               return;
+
+       for (i = 0; i < cells_count; i++) {
+               if (i % 4 == 1)
+                       cells[i] = fdt_rev32(0xffffffff);
+       }
+}
+
+int plic_fdt_fixup(void *fdt, const char *compat)
+{
+       fdt_compat_node_prop(fdt, compat, plic_fdt_fixup_prop, NULL);
+       return 0;
+}
+
+int plic_warm_irqchip_init(u32 target_hart)
+{
+       size_t i, ie_words = plic_num_sources / 32 + 1;
+
+       if (plic_hart_count <= target_hart)
+               return -1;
+
+       /* By default, enable all IRQs for S-mode of target HART */
+       for (i = 0; i < ie_words; i++)
+               plic_set_s_ie(target_hart, i, -1);
+
+       /* By default, enable M-mode threshold */
+       plic_set_m_thresh(target_hart, 1);
+
+       /* By default, disable S-mode threshold */
+       plic_set_s_thresh(target_hart, 0);
+
+       return 0;
+}
+
+int plic_cold_irqchip_init(unsigned long base,
+                          u32 num_sources, u32 hart_count)
+{
+       int i;
+
+       plic_hart_count = hart_count;
+       plic_num_sources = num_sources;
+       plic_base = (void *)base;
+
+       /* Configure default priorities of all IRQs */
+       for (i = 0; i < plic_num_sources; i++)
+               plic_set_priority(i, 1);
+
+       return 0;
+}
diff --git a/plat/common/objects.mk b/plat/common/objects.mk
new file mode 100644 (file)
index 0000000..18fcd0c
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-y += fdt.o
diff --git a/plat/common/serial/objects.mk b/plat/common/serial/objects.mk
new file mode 100644 (file)
index 0000000..61d5d37
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_SERIAL_UART8250) += serial/uart8250.o
+plat-common-objs-$(PLAT_SERIAL_SIFIVE_UART) += serial/sifive-uart.o
diff --git a/plat/common/serial/sifive-uart.c b/plat/common/serial/sifive-uart.c
new file mode 100644 (file)
index 0000000..50c7cad
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/serial/sifive-uart.h>
+
+#define UART_REG_TXFIFO                0
+#define UART_REG_RXFIFO                1
+#define UART_REG_TXCTRL                2
+#define UART_REG_RXCTRL                3
+#define UART_REG_IE            4
+#define UART_REG_IP            5
+#define UART_REG_DIV           6
+
+#define UART_TXFIFO_FULL       0x80000000
+#define UART_RXFIFO_EMPTY      0x80000000
+#define UART_RXFIFO_DATA       0x000000ff
+#define UART_TXCTRL_TXEN       0x1
+#define UART_RXCTRL_RXEN       0x1
+
+static volatile void *uart_base;
+static u32 uart_in_freq;
+static u32 uart_baudrate;
+
+static u32 get_reg(u32 num)
+{
+       return readl(uart_base + (num * 0x4));
+}
+
+static void set_reg(u32 num, u32 val)
+{
+       writel(val, uart_base + (num * 0x4));
+}
+
+void sifive_uart_putc(char ch)
+{
+       while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL);
+
+       set_reg(UART_REG_TXFIFO, ch);
+}
+
+char sifive_uart_getc(void)
+{
+       u32 ret = get_reg(UART_REG_RXFIFO);
+       if (!(ret & UART_RXFIFO_EMPTY))
+               return ret & UART_RXFIFO_DATA;
+       return 0;
+}
+
+int sifive_uart_init(unsigned long base,
+                    u32 in_freq, u32 baudrate)
+{
+       uart_base = (volatile void *)base;
+       uart_in_freq = in_freq;
+       uart_baudrate = baudrate;
+
+       /* Configure baudrate */
+       set_reg(UART_REG_DIV, (in_freq / baudrate) - 1);
+       /* Disable interrupts */
+       set_reg(UART_REG_IE, 0);
+       /* Enable TX */
+       set_reg(UART_REG_TXCTRL, UART_TXCTRL_TXEN);
+       /* Enable Rx */
+       set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
+
+       return 0;
+}
diff --git a/plat/common/serial/uart8250.c b/plat/common/serial/uart8250.c
new file mode 100644 (file)
index 0000000..7a99045
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <plat/serial/uart8250.h>
+
+#define UART_RBR_OFFSET                0       /* In:  Recieve Buffer Register */
+#define UART_THR_OFFSET                0       /* Out: Transmitter Holding Register */
+#define UART_DLL_OFFSET                0       /* Out: Divisor Latch Low */
+#define UART_IER_OFFSET                1       /* I/O: Interrupt Enable Register */
+#define UART_DLM_OFFSET                1       /* Out: Divisor Latch High */
+#define UART_FCR_OFFSET                2       /* Out: FIFO Control Register */
+#define UART_IIR_OFFSET                2       /* I/O: Interrupt Identification Register */
+#define UART_LCR_OFFSET                3       /* Out: Line Control Register */
+#define UART_MCR_OFFSET                4       /* Out: Modem Control Register */
+#define UART_LSR_OFFSET                5       /* In:  Line Status Register */
+#define UART_MSR_OFFSET                6       /* In:  Modem Status Register */
+#define UART_SCR_OFFSET                7       /* I/O: Scratch Register */
+#define UART_MDR1_OFFSET       8       /* I/O:  Mode Register */
+
+#define UART_LSR_FIFOE         0x80    /* Fifo error */
+#define UART_LSR_TEMT          0x40    /* Transmitter empty */
+#define UART_LSR_THRE          0x20    /* Transmit-hold-register empty */
+#define UART_LSR_BI            0x10    /* Break interrupt indicator */
+#define UART_LSR_FE            0x08    /* Frame error indicator */
+#define UART_LSR_PE            0x04    /* Parity error indicator */
+#define UART_LSR_OE            0x02    /* Overrun error indicator */
+#define UART_LSR_DR            0x01    /* Receiver data ready */
+#define UART_LSR_BRK_ERROR_BITS        0x1E    /* BI, FE, PE, OE bits */
+
+static volatile void *uart8250_base;
+static u32 uart8250_in_freq;
+static u32 uart8250_baudrate;
+static u32 uart8250_reg_width;
+static u32 uart8250_reg_shift;
+
+static u32 get_reg(u32 num)
+{
+       u32 offset = num << uart8250_reg_shift;
+
+       if (uart8250_reg_width == 1)
+               return readb(uart8250_base + offset);
+       else if (uart8250_reg_width == 2)
+               return readw(uart8250_base + offset);
+       else
+               return readl(uart8250_base + offset);
+}
+
+static void set_reg(u32 num, u32 val)
+{
+       u32 offset = num << uart8250_reg_shift;
+
+       if (uart8250_reg_width == 1)
+               writeb(val, uart8250_base + offset);
+       else if (uart8250_reg_width == 2)
+               writew(val, uart8250_base + offset);
+       else
+               writel(val, uart8250_base + offset);
+}
+
+void uart8250_putc(char ch)
+{
+       while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0);
+
+       set_reg(UART_THR_OFFSET, ch);
+}
+
+char uart8250_getc(void)
+{
+       if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
+               return get_reg(UART_RBR_OFFSET);
+       return 0;
+}
+
+int uart8250_init(unsigned long base,
+                 u32 in_freq, u32 baudrate,
+                 u32 reg_shift, u32 reg_width)
+{
+       u16 bdiv;
+
+       uart8250_base = (volatile void *)base;
+       uart8250_reg_shift = reg_shift;
+       uart8250_reg_width = reg_width;
+       uart8250_in_freq = in_freq;
+       uart8250_baudrate = baudrate;
+
+       bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
+
+       /* Disable all interrupts */
+       set_reg(UART_IER_OFFSET, 0x00);
+       /* Enable DLAB */
+       set_reg(UART_LCR_OFFSET, 0x80);
+       /* Set divisor low byte */
+       set_reg(UART_DLL_OFFSET, bdiv & 0xff);
+       /* Set divisor high byte */
+       set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
+       /* 8 bits, no parity, one stop bit */
+       set_reg(UART_LCR_OFFSET, 0x03);
+       /* Enable FIFO */
+       set_reg(UART_FCR_OFFSET, 0x01);
+       /* No modem control DTR RTS */
+       set_reg(UART_MCR_OFFSET, 0x00);
+       /* Clear line status */
+       get_reg(UART_LSR_OFFSET);
+       /* Read receive buffer */
+       get_reg(UART_RBR_OFFSET);
+       /* Set scratchpad */
+       set_reg(UART_SCR_OFFSET, 0x00);
+
+       return 0;
+}
diff --git a/plat/common/sys/clint.c b/plat/common/sys/clint.c
new file mode 100644 (file)
index 0000000..b6c6e9b
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/riscv_atomic.h>
+#include <plat/sys/clint.h>
+
+static u32 clint_ipi_hart_count;
+static volatile void *clint_ipi_base;
+static volatile u32 *clint_ipi;
+
+void clint_ipi_inject(u32 target_hart, u32 source_hart)
+{
+       if ((clint_ipi_hart_count <= target_hart) ||
+           (clint_ipi_hart_count <= source_hart))
+               return;
+
+       /* Set CLINT IPI */
+       __io_bw();
+       atomic_raw_xchg_uint(&clint_ipi[target_hart], 1);
+}
+
+void clint_ipi_sync(u32 target_hart, u32 source_hart)
+{
+       u32 target_ipi, incoming_ipi;
+
+       if ((clint_ipi_hart_count <= target_hart) ||
+           (clint_ipi_hart_count <= source_hart))
+               return;
+
+       /* Wait until target HART has handled IPI */
+       incoming_ipi = 0;
+       while (1) {
+               target_ipi = readl(&clint_ipi[target_hart]);
+               if (!target_ipi)
+                       break;
+
+               __io_bw();
+               incoming_ipi |=
+                       atomic_raw_xchg_uint(&clint_ipi[source_hart], 0);
+       }
+
+       if (incoming_ipi) {
+               __io_bw();
+               atomic_raw_xchg_uint(&clint_ipi[source_hart], incoming_ipi);
+       }
+}
+
+void clint_ipi_clear(u32 target_hart)
+{
+       if (clint_ipi_hart_count <= target_hart)
+               return;
+
+       /* Clear CLINT IPI */
+       __io_bw();
+       atomic_raw_xchg_uint(&clint_ipi[target_hart], 0);
+}
+
+int clint_warm_ipi_init(u32 target_hart)
+{
+       if (clint_ipi_hart_count <= target_hart ||
+           !clint_ipi_base)
+               return -1;
+
+       /* Clear CLINT IPI */
+       clint_ipi_clear(target_hart);
+
+       return 0;
+}
+
+int clint_cold_ipi_init(unsigned long base, u32 hart_count)
+{
+       /* Figure-out CLINT IPI register address */
+       clint_ipi_hart_count = hart_count;
+       clint_ipi_base = (void *)base;
+       clint_ipi = (u32 *)clint_ipi_base;
+
+       return 0;
+}
+
+static u32 clint_time_hart_count;
+static volatile void *clint_time_base;
+static volatile u64 *clint_time_val;
+static volatile u64 *clint_time_cmp;
+
+u64 clint_timer_value(void)
+{
+       return readq_relaxed(clint_time_val);
+}
+
+void clint_timer_event_stop(u32 target_hart)
+{
+       if (clint_time_hart_count <= target_hart)
+               return;
+
+       /* Clear CLINT Time Compare */
+       writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
+}
+
+void clint_timer_event_start(u32 target_hart, u64 next_event)
+{
+       if (clint_time_hart_count <= target_hart)
+               return;
+
+       /* Program CLINT Time Compare */
+       writeq_relaxed(next_event, &clint_time_cmp[target_hart]);
+}
+
+int clint_warm_timer_init(u32 target_hart)
+{
+       if (clint_time_hart_count <= target_hart ||
+           !clint_time_base)
+               return -1;
+
+       /* Clear CLINT Time Compare */
+       writeq_relaxed(-1ULL, &clint_time_cmp[target_hart]);
+
+       return 0;
+}
+
+int clint_cold_timer_init(unsigned long base, u32 hart_count)
+{
+       /* Figure-out CLINT Time register address */
+       clint_time_hart_count = hart_count;
+       clint_time_base = (void *)base;
+       clint_time_val = (u64 *)(clint_time_base + 0xbff8);
+       clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
+
+       return 0;
+}
diff --git a/plat/common/sys/objects.mk b/plat/common/sys/objects.mk
new file mode 100644 (file)
index 0000000..451adbb
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-common-objs-$(PLAT_SYS_CLINT) += sys/clint.o
diff --git a/plat/qemu/virt/config.mk b/plat/qemu/virt/config.mk
new file mode 100644 (file)
index 0000000..3e33157
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Essential defines required by SBI platform
+plat-cppflags-y = -DPLAT_NAME="QEMU Virt Machine"
+plat-cppflags-y+= -DPLAT_HART_COUNT=8
+plat-cppflags-y+= -DPLAT_HART_STACK_SIZE=8192
+plat-cppflags-y+= -DPLAT_TEXT_START=0x80000000
+
+# Compiler flags
+plat-cflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-asflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-ldflags-y =
+
+# Common drivers to enable
+PLAT_IRQCHIP_PLIC=y
+PLAT_SERIAL_UART8250=y
+PLAT_SYS_CLINT=y
+
+# Blobs to build
+FW_JUMP=y
+FW_JUMP_ADDR=0x80200000
+FW_JUMP_FDT_OFFSET=0x2000000
+FW_PAYLOAD=y
+FW_PAYLOAD_FDT_OFFSET=0x2000000
diff --git a/plat/qemu/virt/objects.mk b/plat/qemu/virt/objects.mk
new file mode 100644 (file)
index 0000000..03ee2fe
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-objs-y += platform.o
diff --git a/plat/qemu/virt/platform.c b/plat/qemu/virt/platform.c
new file mode 100644 (file)
index 0000000..e59cdfd
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_const.h>
+#include <sbi/sbi_platform.h>
+#include <plat/irqchip/plic.h>
+#include <plat/serial/uart8250.h>
+#include <plat/sys/clint.h>
+
+#define VIRT_TEST_ADDR                 0x100000
+
+#define VIRT_CLINT_ADDR                        0x2000000
+
+#define VIRT_PLIC_ADDR                 0xc000000
+#define VIRT_PLIC_NUM_SOURCES          127
+#define VIRT_PLIC_NUM_PRIORITIES       7
+
+#define VIRT_UART16550_ADDR            0x10000000
+
+static int virt_cold_final_init(void)
+{
+       return plic_fdt_fixup(sbi_scratch_thishart_arg1_ptr(), "riscv,plic0");
+}
+
+static u32 virt_pmp_region_count(u32 target_hart)
+{
+       return 1;
+}
+
+static int virt_pmp_region_info(u32 target_hart, u32 index,
+                               ulong *prot, ulong *addr, ulong *log2size)
+{
+       int ret = 0;
+
+       switch (index) {
+       case 0:
+               *prot = PMP_R | PMP_W | PMP_X;
+               *addr = 0;
+               *log2size = __riscv_xlen;
+               break;
+       default:
+               ret = -1;
+               break;
+       };
+
+       return ret;
+}
+
+static int virt_console_init(void)
+{
+       return uart8250_init(VIRT_UART16550_ADDR,
+                            1843200, 115200, 0, 1);
+}
+
+static int virt_cold_irqchip_init(void)
+{
+       return plic_cold_irqchip_init(VIRT_PLIC_ADDR,
+                                     VIRT_PLIC_NUM_SOURCES,
+                                     PLAT_HART_COUNT);
+}
+
+static int virt_cold_ipi_init(void)
+{
+       return clint_cold_ipi_init(VIRT_CLINT_ADDR,
+                                  PLAT_HART_COUNT);
+}
+
+static int virt_cold_timer_init(void)
+{
+       return clint_cold_timer_init(VIRT_CLINT_ADDR,
+                                    PLAT_HART_COUNT);
+}
+
+static int virt_system_down(u32 type)
+{
+       /* For now nothing to do. */
+       return 0;
+}
+
+struct sbi_platform platform = {
+       .name = STRINGIFY(PLAT_NAME),
+       .features = SBI_PLATFORM_HAS_MMIO_TIMER_VALUE,
+       .hart_count = PLAT_HART_COUNT,
+       .hart_stack_size = PLAT_HART_STACK_SIZE,
+       .pmp_region_count = virt_pmp_region_count,
+       .pmp_region_info = virt_pmp_region_info,
+       .cold_final_init = virt_cold_final_init,
+       .console_putc = uart8250_putc,
+       .console_getc = uart8250_getc,
+       .console_init = virt_console_init,
+       .cold_irqchip_init = virt_cold_irqchip_init,
+       .warm_irqchip_init = plic_warm_irqchip_init,
+       .ipi_inject = clint_ipi_inject,
+       .ipi_sync = clint_ipi_sync,
+       .ipi_clear = clint_ipi_clear,
+       .warm_ipi_init = clint_warm_ipi_init,
+       .cold_ipi_init = virt_cold_ipi_init,
+       .timer_value = clint_timer_value,
+       .timer_event_stop = clint_timer_event_stop,
+       .timer_event_start = clint_timer_event_start,
+       .warm_timer_init = clint_warm_timer_init,
+       .cold_timer_init = virt_cold_timer_init,
+       .system_reboot = virt_system_down,
+       .system_shutdown = virt_system_down
+};
diff --git a/plat/sifive/hifive_u540/config.mk b/plat/sifive/hifive_u540/config.mk
new file mode 100644 (file)
index 0000000..fe5e040
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Essential defines required by SBI platform
+plat-cppflags-y = -DPLAT_NAME="SiFive HiFive U540"
+plat-cppflags-y+= -DPLAT_HART_COUNT=1
+plat-cppflags-y+= -DPLAT_HART_STACK_SIZE=8192
+plat-cppflags-y+= -DPLAT_TEXT_START=0x80000000
+
+# Compiler flags
+plat-cflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-asflags-y =-mabi=lp64 -march=rv64imafdc -mcmodel=medany
+plat-ldflags-y =
+
+# Common drivers to enable
+PLAT_IRQCHIP_PLIC=y
+PLAT_SERIAL_SIFIVE_UART=y
+PLAT_SYS_CLINT=y
+
+# Blobs to build
+FW_JUMP=y
+FW_JUMP_ADDR=0x80200000
+FW_JUMP_FDT_OFFSET=0x2000000
+FW_PAYLOAD=y
+FW_PAYLOAD_FDT_OFFSET=0x2000000
diff --git a/plat/sifive/hifive_u540/objects.mk b/plat/sifive/hifive_u540/objects.mk
new file mode 100644 (file)
index 0000000..03ee2fe
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018 Western Digital Corporation or its affiliates.
+#
+# Authors:
+#   Anup Patel <anup.patel@wdc.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+plat-objs-y += platform.o
diff --git a/plat/sifive/hifive_u540/platform.c b/plat/sifive/hifive_u540/platform.c
new file mode 100644 (file)
index 0000000..a4a401e
--- /dev/null
@@ -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
+};