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