Initial commit.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
Anup Patel 2018-12-11 19:24:06 +05:30 committed by Anup Patel
commit 9e8ff05cb6
67 changed files with 6084 additions and 0 deletions

37
LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}

View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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

View 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

View 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;
}

View 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
View 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;
}

View 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
View 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
View 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
View 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
};

View 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

View 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

View 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
};