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