Compare commits

..

No commits in common. "master" and "v0.2" have entirely different histories.
master ... v0.2

496 changed files with 9739 additions and 60084 deletions

View File

@ -1,16 +0,0 @@
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
BreakStringLiterals: false
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
IndentWidth: 8
ReflowComments: false
SortIncludes: false
SpacesInContainerLiterals: false
TabWidth: 8
UseTab: Always

View File

@ -1,21 +0,0 @@
# SPDX-License-Identifier: BSD-2-Clause
# See here for more information about the format and editor support:
# https://editorconfig.org/
root = true
[{*.{c,dts,h,lds,ldS,mk,s,S},Kconfig,Makefile,Makefile.*}]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = tab
indent_size = 8
[*.py]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4

View File

@ -1,26 +0,0 @@
name: 'Repo Lockdown'
on:
pull_request_target:
types: opened
permissions:
pull-requests: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/repo-lockdown@v4
with:
pr-comment: |
We have mailing list based patch review so it would be great if you can send these patchs to OpenSBI mailing list.
You need to join OpenSBI mailing list using following link
http://lists.infradead.org/mailman/listinfo/opensbi
Make sure you use "git send-email" to send the patches.
Thanks for your contribution to OpenSBI project.
lock-pr: true
close-pr: true

14
.gitignore vendored
View File

@ -1,12 +1,3 @@
# ignore anything begin with dot
.*
# exceptions we need even begin with dot
!.clang-format
!.gitignore
!.github
!.editorconfig
# Object files # Object files
*.o *.o
*.a *.a
@ -15,8 +6,3 @@
#Build & install directories #Build & install directories
build/ build/
install/ install/
# Development friendly files
tags
cscope*
*~

View File

@ -1,27 +0,0 @@
List of OpenSBI Contributors (Alphabetically sorted)
====================================================
* **[Western Digital Corporation](https://www.wdc.com/)**
* Project initiator and maintainer
* Copyright (c) 2019 Western Digital Corporation or its affiliates
* Alistair Francis <alistair@alistair23.me>
* Andreas Schwab <schwab@suse.de>
* Anup Patel <anup.patel@wdc.com>
* Atish Patra <atish.patra@wdc.com>
* Bin Meng <bmeng.cn@gmail.com>
* Damien Le Moal <damien.lemoal@wdc.com>
* Karsten Merker <merker@debian.org>
* Nick Kossifidis <mickflemm@gmail.com>
* Shawn Chang <citypw@gmail.com>
* Xiang Wang <wxjstz@126.com>

View File

@ -1,8 +1,7 @@
The 2-Clause BSD License The 2-Clause BSD License
SPDX short identifier: BSD-2-Clause SPDX short identifier: BSD-2-Clause
Copyright (c) 2019 Western Digital Corporation or its affiliates and other Copyright (c) 2019 Western Digital Corporation or its affiliates.
contributors.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
@ -23,3 +22,4 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

25
Kconfig
View File

@ -1,25 +0,0 @@
# SPDX-License-Identifier: BSD-2-Clause
mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration"
config OPENSBI_SRC_DIR
string
option env="OPENSBI_SRC_DIR"
config OPENSBI_PLATFORM
string
option env="OPENSBI_PLATFORM"
config OPENSBI_PLATFORM_SRC_DIR
string
option env="OPENSBI_PLATFORM_SRC_DIR"
menu "Platform Options"
source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig"
endmenu
source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig"
source "$(OPENSBI_SRC_DIR)/firmware/Kconfig"

577
Makefile
View File

@ -12,48 +12,26 @@
# o Do not print "Entering directory ..."; # o Do not print "Entering directory ...";
MAKEFLAGS += -r --no-print-directory MAKEFLAGS += -r --no-print-directory
# Readlink -f requires GNU readlink
ifeq ($(shell uname -s),Darwin)
READLINK ?= greadlink
else
READLINK ?= readlink
endif
# Find out source, build, and install directories # Find out source, build, and install directories
src_dir=$(CURDIR) src_dir=$(CURDIR)
ifdef O ifdef O
build_dir=$(shell $(READLINK) -f $(O)) build_dir=$(shell readlink -f $(O))
else else
build_dir=$(CURDIR)/build build_dir=$(CURDIR)/build
endif endif
ifeq ($(build_dir),$(CURDIR)) ifeq ($(build_dir),$(CURDIR))
$(error Build directory is same as source directory.) $(error Build directory is same as source directory.)
endif endif
install_root_dir_default=$(CURDIR)/install
ifdef I ifdef I
install_root_dir=$(shell $(READLINK) -f $(I)) install_dir=$(shell readlink -f $(I))
else else
install_root_dir=$(install_root_dir_default)/usr install_dir=$(CURDIR)/install
endif endif
ifeq ($(install_root_dir),$(CURDIR)) ifeq ($(install_dir),$(CURDIR))
$(error Install root directory is same as source directory.) $(error Install directory is same as source directory.)
endif endif
ifeq ($(install_root_dir),$(build_dir)) ifeq ($(install_dir),$(build_dir))
$(error Install root directory is same as build directory.) $(error Install directory is same as build directory.)
endif
ifdef PLATFORM_DIR
platform_dir_path=$(shell $(READLINK) -f $(PLATFORM_DIR))
ifdef PLATFORM
platform_parent_dir=$(platform_dir_path)
else
PLATFORM=$(shell basename $(platform_dir_path))
platform_parent_dir=$(shell realpath ${platform_dir_path}/..)
endif
else
platform_parent_dir=$(src_dir)/platform
endif
ifndef PLATFORM_DEFCONFIG
PLATFORM_DEFCONFIG=defconfig
endif endif
# Check if verbosity is ON for build process # Check if verbosity is ON for build process
@ -65,100 +43,76 @@ else
endif endif
# Setup path of directories # Setup path of directories
export platform_subdir=$(PLATFORM) export platform_subdir=platform/$(PLATFORM)
export platform_src_dir=$(platform_parent_dir)/$(platform_subdir) export platform_dir=$(CURDIR)/$(platform_subdir)
export platform_build_dir=$(build_dir)/platform/$(platform_subdir) export platform_common_dir=$(CURDIR)/platform/common
export include_dir=$(CURDIR)/include export include_dir=$(CURDIR)/include
export libsbi_dir=$(CURDIR)/lib/sbi export lib_dir=$(CURDIR)/lib
export libsbiutils_dir=$(CURDIR)/lib/utils
export firmware_dir=$(CURDIR)/firmware export firmware_dir=$(CURDIR)/firmware
# Setup variables for kconfig
ifdef PLATFORM
export PYTHONDONTWRITEBYTECODE=1
export KCONFIG_DIR=$(platform_build_dir)/kconfig
export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list
export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h
export KCONFIG_AUTOCONFIG=$(KCONFIG_DIR)/auto.conf
export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd
export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config
# Additional exports for include paths in Kconfig files
export OPENSBI_SRC_DIR=$(src_dir)
export OPENSBI_PLATFORM=$(PLATFORM)
export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)
endif
# Find library version # Find library version
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MAJOR=`grep MAJOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'` OPENSBI_VERSION_MINOR=`grep MINOR $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_GIT=
# Detect 'git' presence before issuing 'git' commands
GIT_AVAIL := $(shell command -v git 2> /dev/null)
ifneq ($(GIT_AVAIL),)
GIT_DIR := $(shell git rev-parse --git-dir 2> /dev/null)
ifneq ($(GIT_DIR),)
OPENSBI_VERSION_GIT := $(shell if [ -d $(GIT_DIR) ]; then git describe 2> /dev/null; fi)
endif
endif
# Setup compilation commands # Setup compilation commands
ifneq ($(LLVM),)
ifneq ($(filter %/,$(LLVM)),)
LLVM_PREFIX := $(LLVM)
else ifneq ($(filter -%,$(LLVM)),)
LLVM_SUFFIX := $(LLVM)
endif
CC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
AR = $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
LD = $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
OBJCOPY = $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
else
ifdef CROSS_COMPILE ifdef CROSS_COMPILE
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)cpp
AR = $(CROSS_COMPILE)ar AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
else else
CC ?= gcc CC ?= gcc
CPP ?= cpp
AR ?= ar AR ?= ar
LD ?= ld LD ?= ld
OBJCOPY ?= objcopy OBJCOPY ?= objcopy
endif endif
endif
CPP = $(CC) -E
AS = $(CC) AS = $(CC)
DTC = dtc DTC = dtc
ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),) # Guess the compillers xlen
CC_IS_CLANG = y OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
else
CC_IS_CLANG = n # Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_dir) ]; then find $(platform_dir) -iname "objects.mk" | sort -r; fi)
platform-common-object-mks=$(shell if [ -d $(platform_common_dir) ]; then find $(platform_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)
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
# Include platform specifig config.mk
ifdef PLATFORM
include $(platform_dir)/config.mk
endif endif
ifneq ($(shell $(LD) --version 2>&1 | head -n 1 | grep LLD),) # Include all object.mk files
LD_IS_LLD = y ifdef PLATFORM
else include $(platform-object-mks)
LD_IS_LLD = n include $(platform-common-object-mks)
endif endif
include $(lib-object-mks)
include $(firmware-object-mks)
ifeq ($(CC_IS_CLANG),y) # Setup list of objects
ifneq ($(CROSS_COMPILE),) lib-objs-path-y=$(foreach obj,$(lib-objs-y),$(build_dir)/lib/$(obj))
CLANG_TARGET = --target=$(notdir $(CROSS_COMPILE:%-=%)) ifdef PLATFORM
endif platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(build_dir)/$(platform_subdir)/$(obj))
platform-dtb-path-y=$(foreach obj,$(platform-dtb-y),$(build_dir)/$(platform_subdir)/$(obj))
platform-common-objs-path-y=$(foreach obj,$(platform-common-objs-y),$(build_dir)/platform/common/$(obj))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(build_dir)/$(platform_subdir)/firmware/$(bin))
endif endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Guess the compiler's XLEN # Setup list of deps files for objects
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP}) deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(platform-common-objs-path-y:.o=.dep)
deps-y+=$(lib-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
# Guess the compiler's ABI and ISA # Setup platform XLEN, ABI, ISA and Code Model
ifneq ($(CC_IS_CLANG),y)
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
endif
# Setup platform XLEN
ifndef PLATFORM_RISCV_XLEN ifndef PLATFORM_RISCV_XLEN
ifeq ($(OPENSBI_CC_XLEN), 32) ifeq ($(OPENSBI_CC_XLEN), 32)
PLATFORM_RISCV_XLEN = 32 PLATFORM_RISCV_XLEN = 32
@ -166,288 +120,61 @@ ifndef PLATFORM_RISCV_XLEN
PLATFORM_RISCV_XLEN = 64 PLATFORM_RISCV_XLEN = 64
endif endif
endif endif
ifeq ($(CC_IS_CLANG),y)
ifeq ($(CROSS_COMPILE),)
CLANG_TARGET = --target=riscv$(PLATFORM_RISCV_XLEN)-unknown-elf
endif
endif
ifeq ($(LD_IS_LLD),y)
RELAX_FLAG = -mno-relax
USE_LD_FLAG = -fuse-ld=lld
else
USE_LD_FLAG = -fuse-ld=bfd
endif
REPRODUCIBLE ?= n
ifeq ($(REPRODUCIBLE),y)
REPRODUCIBLE_FLAGS += -ffile-prefix-map=$(src_dir)=
endif
# Check whether the linker supports creating PIEs
OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
# Check whether the linker supports --exclude-libs
OPENSBI_LD_EXCLUDE_LIBS := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) "-Wl,--exclude-libs,ALL" -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
# Check whether the compiler supports -m(no-)save-restore
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep -e "-save-restore" >/dev/null && echo n || echo y)
# Check whether the compiler supports -m(no-)strict-align
CC_SUPPORT_STRICT_ALIGN := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mstrict-align -x c /dev/null -o /dev/null 2>&1 | grep -e "-mstrict-align" -e "-mno-unaligned-access" >/dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep -e "zicsr" -e "zifencei" > /dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Vector extension
CC_SUPPORT_VECTOR := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)gv -dM -E -x c /dev/null 2>&1 | grep -q riscv.*vector && echo y || echo n)
ifneq ($(OPENSBI_LD_PIE),y)
$(error Your linker does not support creating PIEs, opensbi requires this.)
endif
# Build Info:
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
BUILD_INFO ?= n
ifeq ($(BUILD_INFO),y)
OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z
ifndef OPENSBI_BUILD_TIME_STAMP
ifdef SOURCE_DATE_EPOCH
OPENSBI_BUILD_TIME_STAMP := $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u -r "$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u "$(OPENSBI_BUILD_DATE_FMT)")
else
OPENSBI_BUILD_TIME_STAMP := $(shell date "$(OPENSBI_BUILD_DATE_FMT)")
endif
endif
OPENSBI_BUILD_COMPILER_VERSION := $(shell $(CC) -v 2>&1 | grep ' version ' | \
sed 's/[[:space:]]*$$//')
endif
# Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
endif
libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -iname "objects.mk" | sort -r; fi)
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
# The "make all" rule should always be first rule
.PHONY: all
all:
# Include platform specific .config
ifdef PLATFORM
.PHONY: menuconfig
menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig
.PHONY: savedefconfig
savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig
$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
$(KCONFIG_AUTOCONFIG): $(KCONFIG_CONFIG)
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
$(KCONFIG_AUTOHEADER): $(KCONFIG_AUTOCONFIG);
$(KCONFIG_AUTOLIST): $(KCONFIG_AUTOCONFIG);
$(KCONFIG_AUTOCMD): $(KCONFIG_AUTOLIST)
$(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD)
$(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD)
include $(KCONFIG_AUTOCONFIG)
include $(KCONFIG_AUTOCMD)
endif
# Include all objects.mk files
ifdef PLATFORM
include $(platform-object-mks)
endif
include $(libsbi-object-mks)
include $(libsbiutils-object-mks)
include $(firmware-object-mks)
# Setup list of objects
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
ifdef PLATFORM
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj))
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
endif
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
firmware-objs-path-y=$(firmware-bins-path-y:.bin=.o)
# Setup list of deps files for objects
deps-y=$(platform-objs-path-y:.o=.dep)
deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
deps-y+=$(firmware-elfs-path-y:=.dep)
# Setup platform ABI, ISA and Code Model
ifndef PLATFORM_RISCV_ABI ifndef PLATFORM_RISCV_ABI
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1) ifeq ($(PLATFORM_RISCV_XLEN), 32)
ifeq ($(PLATFORM_RISCV_XLEN), 32) PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
PLATFORM_RISCV_ABI = ilp$(PLATFORM_RISCV_XLEN)
else
PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
endif
else else
PLATFORM_RISCV_ABI = $(OPENSBI_CC_ABI) PLATFORM_RISCV_ABI = lp$(PLATFORM_RISCV_XLEN)
endif endif
endif endif
ifndef PLATFORM_RISCV_ISA ifndef PLATFORM_RISCV_ISA
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1) PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
PLATFORM_RISCV_ISA := rv$(PLATFORM_RISCV_XLEN)imafdc
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
PLATFORM_RISCV_ISA := $(PLATFORM_RISCV_ISA)_zicsr_zifencei
endif
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
endif endif
ifndef PLATFORM_RISCV_CODE_MODEL ifndef PLATFORM_RISCV_CODE_MODEL
PLATFORM_RISCV_CODE_MODEL = medany PLATFORM_RISCV_CODE_MODEL = medany
endif endif
# Setup install directories
ifdef INSTALL_INCLUDE_PATH
install_include_path=$(INSTALL_INCLUDE_PATH)
else
install_include_path=include
endif
ifdef INSTALL_LIB_PATH
install_lib_path=$(INSTALL_LIB_PATH)
else
ifneq ($(origin INSTALL_LIB_SUBDIR), undefined)
install_lib_subdir=$(INSTALL_LIB_SUBDIR)
else
install_lib_subdir=$(PLATFORM_RISCV_ABI)
endif
install_lib_path=lib$(subst 32,,$(PLATFORM_RISCV_XLEN))/$(install_lib_subdir)
endif
ifdef INSTALL_FIRMWARE_PATH
install_firmware_path=$(INSTALL_FIRMWARE_PATH)
else
install_firmware_path=share/opensbi/$(PLATFORM_RISCV_ABI)
endif
ifdef INSTALL_DOCS_PATH
install_docs_path=$(INSTALL_DOCS_PATH)
else
install_docs_path=share/opensbi/docs
endif
# Setup compilation commands flags # Setup compilation commands flags
ifeq ($(CC_IS_CLANG),y) GENFLAGS = -I$(platform_dir)/include
GENFLAGS += $(CLANG_TARGET) GENFLAGS += -I$(platform_common_dir)/include
GENFLAGS += -Wno-unused-command-line-argument
endif
GENFLAGS += -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir) GENFLAGS += -I$(include_dir)
ifneq ($(OPENSBI_VERSION_GIT),) GENFLAGS += $(platform-common-genflags-y)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
GENFLAGS += -include $(include_dir)/sbi/sbi_visibility.h
ifdef PLATFORM
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y) GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y) GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -ffunction-sections -fdata-sections CFLAGS = -g -Wall -Werror -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += $(REPRODUCIBLE_FLAGS)
# Optionally supported flags
ifeq ($(CC_SUPPORT_VECTOR),y)
CFLAGS += -DOPENSBI_CC_SUPPORT_VECTOR
endif
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
CFLAGS += -mno-save-restore
endif
ifeq ($(CC_SUPPORT_STRICT_ALIGN),y)
CFLAGS += -mstrict-align
endif
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL) CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(RELAX_FLAG)
CFLAGS += $(GENFLAGS) CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y) CFLAGS += $(platform-cflags-y)
CFLAGS += -fPIE -pie
CFLAGS += $(firmware-cflags-y) CFLAGS += $(firmware-cflags-y)
CPPFLAGS += $(GENFLAGS) CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y) CPPFLAGS += $(platform-cppflags-y)
CPPFLAGS += $(firmware-cppflags-y) CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -fPIE ASFLAGS += -mno-save-restore -mstrict-align
ASFLAGS += $(REPRODUCIBLE_FLAGS)
# Optionally supported flags
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
ASFLAGS += -mno-save-restore
endif
ifeq ($(CC_SUPPORT_STRICT_ALIGN),y)
ASFLAGS += -mstrict-align
endif
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL) ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
ASFLAGS += $(RELAX_FLAG)
ifneq ($(CC_IS_CLANG),y)
ifneq ($(RELAX_FLAG),)
ASFLAGS += -Wa,$(RELAX_FLAG)
endif
endif
ASFLAGS += $(GENFLAGS) ASFLAGS += $(GENFLAGS)
ASFLAGS += $(platform-asflags-y) ASFLAGS += $(platform-asflags-y)
ASFLAGS += $(firmware-asflags-y) ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs ARFLAGS = rcs
ELFFLAGS += $(USE_LD_FLAG) ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
ELFFLAGS += -Wl,--gc-sections
ifeq ($(OPENSBI_LD_EXCLUDE_LIBS),y)
ELFFLAGS += -Wl,--exclude-libs,ALL
endif
ELFFLAGS += -Wl,--build-id=none
ELFFLAGS += -Wl,--no-dynamic-linker -Wl,-pie
ELFFLAGS += $(platform-ldflags-y) ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y) ELFFLAGS += $(firmware-ldflags-y)
MERGEFLAGS += -r MERGEFLAGS += -r
ifeq ($(LD_IS_LLD),y)
MERGEFLAGS += -b elf
else
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
endif
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp DTCFLAGS = -O dtb
ifneq ($(DEBUG),)
CFLAGS += -O0
ELFFLAGS += -Wl,--print-gc-sections
else
CFLAGS += -O2
endif
# Setup functions for compilation # Setup functions for compilation
define dynamic_flags define dynamic_flags
@ -461,35 +188,30 @@ merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
cat $(2) > $(1) cat $(2) > $(1)
copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " COPY $(subst $(build_dir)/,,$(1))"; \ echo " COPY $(subst $(build_dir)/,,$(1))"; \
cp -L -f $(2) $(1) cp -f $(2) $(1)
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
cp -L -f $(2) $(1) cp -f $(2) $(1)
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
mkdir -p $(1)/$(3); \ mkdir -p $(1)/$(3); \
for file in $(4) ; do \ for file in $(4) ; do \
rel_file=`echo $$file | sed -e 's@$(2)/$(subst $(install_firmware_path),platform,$(3))@@'`; \ rel_file=`echo $$file | sed -e 's@$(2)/$(3)/@@'`; \
dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \ dest_file=$(1)"/"$(3)"/"`echo $$rel_file`; \
dest_dir=`dirname $$dest_file`; \ dest_dir=`dirname $$dest_file`; \
echo " INSTALL "$(3)"/"`echo $$rel_file`; \ echo " INSTALL "$(3)"/"`echo $$rel_file`; \
mkdir -p $$dest_dir; \ mkdir -p $$dest_dir; \
cp -L -f $$file $$dest_file; \ cp -f $$file $$dest_file; \
done \ done \
fi fi
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \ inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \ echo " INSTALL $(subst $(install_dir)/,,$(1))"; \
cp -L -rf $(2) $(1) cp -rf $(2) $(1)
compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \
printf %s `dirname $(1)`/ > $(1) && \
$(CC) $(CPPFLAGS) -x c -MM $(3) \
-MT `basename $(1:.dep=$(2))` >> $(1) || rm -f $(1)
compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cpp = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP $(subst $(build_dir)/,,$(1))"; \ echo " CPP $(subst $(build_dir)/,,$(1))"; \
$(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1) $(CPP) $(CPPFLAGS) -x c $(2) | grep -v "\#" > $(1)
compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \ echo " CC-DEP $(subst $(build_dir)/,,$(1))"; \
printf %s `dirname $(1)`/ > $(1) && \ echo `dirname $(1)`/ \\ > $(1) && \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@ -497,7 +219,7 @@ compile_cc = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1) $(CC) $(CFLAGS) $(call dynamic_flags,$(1),$(2)) -c $(2) -o $(1)
compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \ echo " AS-DEP $(subst $(build_dir)/,,$(1))"; \
printf %s `dirname $(1)`/ > $(1) && \ echo `dirname $(1)`/ \\ > $(1) && \
$(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \ $(AS) $(ASFLAGS) $(call dynamic_flags,$(1),$(2)) \
-MM $(2) >> $(1) || rm -f $(1) -MM $(2) >> $(1) || rm -f $(1)
compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_as = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
@ -514,131 +236,64 @@ compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(OBJCOPY) -S -O binary $(2) $(1) $(OBJCOPY) -S -O binary $(2) $(1)
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \ compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " DTC $(subst $(build_dir)/,,$(1))"; \ echo " DTC $(subst $(build_dir)/,,$(1))"; \
$(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1) $(DTC) $(DTCFLAGS) -o $(1) $(2)
compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " D2C $(subst $(build_dir)/,,$(1))"; \
$(if $($(2)-varalign-$(3)),$(eval D2C_ALIGN_BYTES := $($(2)-varalign-$(3))),$(eval D2C_ALIGN_BYTES := $(4))) \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
$(eval CARRAY_VAR_LIST := $(carray-$(subst .carray.c,,$(shell basename $(1)))-y)) \
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1) || rm $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
targets-y = $(build_dir)/lib/libsbi.a targets-y = $(build_dir)/lib/libsbi.a
ifdef PLATFORM ifdef PLATFORM
targets-y += $(platform_build_dir)/lib/libplatsbi.a targets-y += $(build_dir)/$(platform_subdir)/lib/libplatsbi.a
targets-y += $(platform-dtb-path-y)
endif endif
targets-y += $(firmware-bins-path-y) targets-y += $(firmware-bins-path-y)
# The default "make all" rule # Default rule "make" should always be first rule
.PHONY: all .PHONY: all
all: $(targets-y) all: $(targets-y)
# Preserve all intermediate files # Preserve all intermediate files
.SECONDARY: .SECONDARY:
# Rules for lib/sbi sources $(build_dir)/%.bin: $(build_dir)/%.elf
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y) $(call compile_objcopy,$@,$<)
$(build_dir)/%.elf: $(build_dir)/%.o $(build_dir)/%.elf.ld $(build_dir)/$(platform_subdir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(build_dir)/$(platform_subdir)/lib/libplatsbi.a)
$(build_dir)/$(platform_subdir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(build_dir)/lib/libsbi.a: $(lib-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y) $(build_dir)/$(platform_subdir)/lib/libplatsbi.a: $(lib-objs-path-y) $(platform-common-objs-path-y) $(platform-objs-path-y)
$(call compile_ar,$@,$^) $(call compile_ar,$@,$^)
$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_AUTOHEADER) $(build_dir)/%.dep: $(src_dir)/%.c
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_AUTOHEADER))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.carray.c: $(src_dir)/%.carray $(src_dir)/scripts/carray.sh
$(call compile_carray,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_AUTOHEADER)
$(call compile_cc_dep,$@,$<) $(call compile_cc_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.c $(build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<) $(call compile_cc,$@,$<)
$(build_dir)/%.o: $(build_dir)/%.c $(build_dir)/%.dep: $(src_dir)/%.S
$(call compile_cc,$@,$<)
ifeq ($(BUILD_INFO),y)
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
endif
$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_AUTOHEADER)
$(call compile_as_dep,$@,$<) $(call compile_as_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.S $(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
# Rules for platform sources $(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.c
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_AUTOHEADER)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_AUTOHEADER))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.carray.c: $(platform_src_dir)/%.carray $(src_dir)/scripts/carray.sh
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_AUTOHEADER)
$(call compile_cc_dep,$@,$<) $(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_AUTOHEADER) $(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<) $(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S $(build_dir)/$(platform_subdir)/%.dep: $(src_dir)/%.S
$(call compile_as_dep,$@,$<) $(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S $(build_dir)/$(platform_subdir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<) $(call compile_as,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_AUTOHEADER) $(build_dir)/%.dtb: $(src_dir)/%.dts
$(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_AUTOHEADER))
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
$(call compile_d2c,$@,platform,$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<))),16,dt,$<)
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
$(call compile_dts,$@,$<) $(call compile_dts,$@,$<)
# Rules for lib/utils and firmware sources
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
$(platform_build_dir)/%.dep: $(src_dir)/%.ldS $(KCONFIG_AUTOHEADER)
$(call compile_cpp_dep,$@,.ld,$<)
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
$(call compile_cpp,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_AUTOHEADER)
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_AUTOHEADER))
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(platform_build_dir)/%.carray.c: $(src_dir)/%.carray $(src_dir)/scripts/carray.sh
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_AUTOHEADER)
$(call compile_cc_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_AUTOHEADER)
$(call compile_as_dep,$@,$<)
$(platform_build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
# Rule for "make docs" # Rule for "make docs"
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex $(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
$(CMD_PREFIX)mkdir -p $(build_dir)/docs $(CMD_PREFIX)mkdir -p $(build_dir)/docs
@ -668,7 +323,7 @@ ifneq ($(platform-runcmd),)
$(platform-runcmd) $(RUN_ARGS) $(platform-runcmd) $(RUN_ARGS)
else else
ifdef PLATFORM ifdef PLATFORM
@echo "Platform $(PLATFORM) doesn't specify a run command" @echo Platform $(PLATFORM) doesn't specify a run command
@false @false
else else
@echo Run command only available when targeting a platform @echo Run command only available when targeting a platform
@ -688,32 +343,21 @@ install: $(install_targets-y)
.PHONY: install_libsbi .PHONY: install_libsbi
install_libsbi: $(build_dir)/lib/libsbi.a install_libsbi: $(build_dir)/lib/libsbi.a
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi) $(call inst_header_dir,$(install_dir)/include,$(include_dir)/sbi)
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a) $(call inst_file,$(install_dir)/lib/libsbi.a,$(build_dir)/lib/libsbi.a)
.PHONY: install_libplatsbi .PHONY: install_libplatsbi
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a install_libplatsbi: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a) $(call inst_file,$(install_dir)/$(platform_subdir)/lib/libplatsbi.a,$(build_dir)/$(platform_subdir)/lib/libplatsbi.a)
.PHONY: install_firmwares .PHONY: install_firmwares
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y) install_firmwares: $(build_dir)/$(platform_subdir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y)
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y)) $(call inst_file_list,$(install_dir),$(build_dir),$(platform_subdir)/firmware,$(firmware-elfs-path-y))
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y)) $(call inst_file_list,$(install_dir),$(build_dir),$(platform_subdir)/firmware,$(firmware-bins-path-y))
.PHONY: install_docs .PHONY: install_docs
install_docs: $(build_dir)/docs/latex/refman.pdf install_docs: $(build_dir)/docs/latex/refman.pdf
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf) $(call inst_file,$(install_dir)/docs/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
.PHONY: cscope
cscope:
$(CMD_PREFIX)find \
"$(src_dir)/firmware" \
"$(src_dir)/include" \
"$(src_dir)/lib" \
"$(platform_src_dir)" \
-name "*.[chS]" -print > cscope.files
$(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files
$(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out
# Rule for "make clean" # Rule for "make clean"
.PHONY: clean .PHONY: clean
@ -721,16 +365,12 @@ clean:
$(CMD_PREFIX)mkdir -p $(build_dir) $(CMD_PREFIX)mkdir -p $(build_dir)
$(if $(V), @echo " RM $(build_dir)/*.o") $(if $(V), @echo " RM $(build_dir)/*.o")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.o" -exec rm -rf {} + $(CMD_PREFIX)find $(build_dir) -type f -name "*.o" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.carray.c")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.carray.c" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.a") $(if $(V), @echo " RM $(build_dir)/*.a")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.a" -exec rm -rf {} + $(CMD_PREFIX)find $(build_dir) -type f -name "*.a" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.elf") $(if $(V), @echo " RM $(build_dir)/*.elf")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} + $(CMD_PREFIX)find $(build_dir) -type f -name "*.elf" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.bin") $(if $(V), @echo " RM $(build_dir)/*.bin")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} + $(CMD_PREFIX)find $(build_dir) -type f -name "*.bin" -exec rm -rf {} +
$(if $(V), @echo " RM $(build_dir)/*.dtb")
$(CMD_PREFIX)find $(build_dir) -type f -name "*.dtb" -exec rm -rf {} +
# Rule for "make distclean" # Rule for "make distclean"
.PHONY: distclean .PHONY: distclean
@ -742,12 +382,7 @@ ifeq ($(build_dir),$(CURDIR)/build)
$(if $(V), @echo " RM $(build_dir)") $(if $(V), @echo " RM $(build_dir)")
$(CMD_PREFIX)rm -rf $(build_dir) $(CMD_PREFIX)rm -rf $(build_dir)
endif endif
ifeq ($(install_root_dir),$(install_root_dir_default)/usr) ifeq ($(install_dir),$(CURDIR)/install)
$(if $(V), @echo " RM $(install_root_dir_default)") $(if $(V), @echo " RM $(install_dir)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default) $(CMD_PREFIX)rm -rf $(install_dir)
endif endif
$(if $(V), @echo " RM $(src_dir)/cscope*")
$(CMD_PREFIX)rm -f $(src_dir)/cscope*
.PHONY: FORCE
FORCE:

447
README.md
View File

@ -1,17 +1,135 @@
RISC-V Open Source Supervisor Binary Interface (OpenSBI) RISC-V Open Source Supervisor Binary Interface (OpenSBI)
======================================================== ========================================================
![RISC-V OpenSBI](docs/riscv_opensbi_logo_final_color.png) The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between:
Copyright and License 1. A platform specific firmware running in M-mode and bootloader, hypervisor or
--------------------- a general purpose OS executing in S-mode or HS-mode.
2. A hypervisor running in HS-mode and a bootloader or a general purpose OS
executing in VS-mode.
The OpenSBI project is: The *RISC-V SBI specification* is maintained as an independent project by the
RISC-V Foundation in [Github].
* Copyright (c) 2019 Western Digital Corporation or its affiliates The goal of the OpenSBI project is to provide an open-source reference
* Copyright (c) 2023 RISC-V International implementation of the RISC-V SBI specifications for platform specific firmwares
executing in M-mode (case 1 mentioned above). OpenSBI implementation can be
easily extended by RISC-V platform and system-on-chip vendors to fit a
particular hardware configuration.
It is distributed under the terms of the BSD 2-clause license The main component of OpenSBI is provided in the form of a platform independent
static library **libsbi.a** implementing the SBI interface. A firmware or
bootloader implementation can link against this library to ensure conformance
with the SBI interface specifications. *libsbi.a* also defines an interface for
integrating with platform specific operations provided by the platform firmware
implementation (e.g. console access functions, inter-processor interrupts
control, etc).
To illustrate the use of *libsbi.a* library, OpenSBI also provides a set of
platform specific support examples. For each example, a platform
specific static library *libplatsbi.a* can be compiled. This library implements
SBI calls processing by integrating *libsbi.a* with necessary platform dependent
hardware manipulation functions. For all supported platforms, OpenSBI also
provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy
*riskv-pk* bootloader (aka BBL) and enable the use of well known bootloaders
such as [U-Boot].
Required Toolchain
------------------
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your tool chain or just download from
the [bootlin] (https://toolchains.bootlin.com/).
Please note that only 64bit version of toolchain is available in bootlin
for now.
Building and Installing OpenSBI Platform Independent Library
------------------------------------------------------------
OpenSBI platform independent static library *libsbi.a* can be natively compiled
or cross-compiled on a host with a different base architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
To build *libsbi.a* simply execute:
```
make
```
All compiled binaries as well as the result *libsbi.a* static library file will
be placed in the *build/lib* directory. To specify an alternate build root
directory path, run:
```
make O=<build_directory>
```
To generate files to be installed for using *libsbi.a* in other projects, run:
```
make install
```
This will create the *install* directory with all necessary include files
copied under the *install/include* directory and library file copied in the
*install/lib* directory. To specify an alternate installation root directory
path, run:
```
make I=<install_directory> install
```
Building and Installing a Reference Platform Static Library and Firmwares
-------------------------------------------------------------------------
When the *PLATFORM=<platform_subdir>* argument is specified on the make command
line, the platform specific static library *libplatsbi.a* and firmware examples
are built for the platform *<platform_subdir>* present in the directory
*platform* in OpenSBI top directory. For example, to compile the platform
library and firmware examples for QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *qemu/virt*.
To build *libsbi.a*, *libplatsbi.a* and the firmwares for one of the supported
platform, run:
```
make PLATFORM=<platform_subdir>
```
An alternate build directory path can also be specified.
```
make PLATFORM=<platform_subdir> O=<build_directory>
```
The platform specific library *libplatsbi.a* will be generated in the
*build/platform/<platform_subdir>/lib* directory. The platform firmware files
will be under the *build/platform/<platform_subdir>/firmware* directory.
The compiled firmwares will be available in two different format: an ELF file
and an expanded image file.
To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
```
make PLATFORM=<platform_subdir> install
```
This will copy the compiled platform specific libraries and firmware files
under the *install/platform/<platform_subdir>/* directory. An alternate
install root directory path can be specified as follows.
```
make PLATFORM=<platform_subdir> I=<install_directory> install
```
In addition, platform specific configuration options can be specified with the
top-level make command line. These options, such as *PLATFORM_<xyz>* or
*FW_<abc>*, are platform specific and described in more details in the
*docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files.
License
-------
OpenSBI is distributed under the terms of the BSD 2-clause license
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*). ("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
A copy of this license with OpenSBI copyright can be found in the file A copy of this license with OpenSBI copyright can be found in the file
[COPYING.BSD]. [COPYING.BSD].
@ -30,308 +148,18 @@ OpenSBI source code also contains code reused from other projects as listed
below. The original license text of these projects is included in the source below. The original license text of these projects is included in the source
files where the reused code is present. files where the reused code is present.
* The libfdt source code is disjunctively dual licensed 1. The libfdt source code is disjunctively dual licensed
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI (GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
under the terms of the BSD 2-Clause license. Any contributions to this under the terms of the BSD 2-Clause license. Any contributions to this
code must be made under the terms of both licenses. code must be made under the terms of both licenses.
See also the [third party notices] file for more information.
Introduction
------------
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
between:
1. A platform-specific firmware running in M-mode and a bootloader, a
hypervisor or a general-purpose OS executing in S-mode or HS-mode.
2. A hypervisor running in HS-mode and a bootloader or a general-purpose OS
executing in VS-mode.
The *RISC-V SBI specification* is maintained as an independent project by the
RISC-V Foundation on [Github].
The goal of the OpenSBI project is to provide an open-source reference
implementation of the RISC-V SBI specifications for platform-specific firmwares
executing in M-mode (case 1 mentioned above). An OpenSBI implementation can be
easily extended by RISC-V platform and system-on-chip vendors to fit a
particular hardware configuration.
The main component of OpenSBI is provided in the form of a platform-independent
static library **libsbi.a** implementing the SBI interface. A firmware or
bootloader implementation can link against this library to ensure conformance
with the SBI interface specifications. *libsbi.a* also defines an interface for
integrating with platform-specific operations provided by the platform firmware
implementation (e.g. console access functions, inter-processor interrupt
control, etc).
To illustrate the use of the *libsbi.a* library, OpenSBI also provides a set of
platform-specific support examples. For each example, a platform-specific
static library *libplatsbi.a* can be compiled. This library implements
SBI call processing by integrating *libsbi.a* with the necessary
platform-dependent hardware manipulation functions. For all supported platforms,
OpenSBI also provides several runtime firmware examples built using the platform
*libplatsbi.a*. These example firmwares can be used to replace the legacy
*riscv-pk* bootloader (aka BBL) and enable the use of well-known bootloaders
such as [U-Boot].
Supported SBI version
---------------------
Currently, OpenSBI fully supports SBI specification *v0.2*. OpenSBI also
supports Hart State Management (HSM) SBI extension starting from OpenSBI v0.7.
HSM extension allows S-mode software to boot all the harts a defined order
rather than legacy method of random booting of harts. As a result, many
required features such as CPU hotplug, kexec/kdump can also be supported easily
in S-mode. HSM extension in OpenSBI is implemented in a non-backward compatible
manner to reduce the maintenance burden and avoid confusion. That's why, any
S-mode software using OpenSBI will not be able to boot more than 1 hart if HSM
extension is not supported in S-mode.
Linux kernel already supports SBI v0.2 and HSM SBI extension starting from
**v5.7-rc1**. If you are using an Linux kernel older than **5.7-rc1** or any
other S-mode software without HSM SBI extension, you should stick to OpenSBI
v0.6 to boot all the harts. For a UMP systems, it doesn't matter.
N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
as it doesn't need to boot all the harts. The operating system should be
capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain and Packages
-------------------------------
OpenSBI can be compiled natively or cross-compiled on a host machine. For
cross-compilation, you can build your own toolchain, download a prebuilt one
from the [Bootlin toolchain repository] or install a distribution-provided
toolchain; if you opt to use LLVM/Clang, most distribution toolchains will
support cross-compiling for RISC-V using the same toolchain as your native
LLVM/Clang toolchain due to LLVM's ability to support multiple backends in the
same binary, so is often an easy way to obtain a working cross-compilation
toolchain.
Toolchains with Position Independent Executable (PIE) support like
*riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or *Clang/LLVM* are
required in order to generate PIE firmware images that can run at arbitrary
address with appropriate alignment. Bare-metal GNU toolchains (e.g.
*riscv64-unknown-elf-gcc*) cannot be used. *Clang/LLVM* can still generate PIE
images if a bare-metal triple is used (e.g. *-target riscv64-unknown-elf*).
In addition to a toolchain, OpenSBI also requires the following packages on
the host:
1. device-tree-compiler: The device tree compiler for compiling device
tree sources (DTS files).
2. python3: The python 3.0 (or compatible) language support for various
scripts.
Building and Installing the OpenSBI Platform-Independent Library
----------------------------------------------------------------
The OpenSBI platform-independent static library *libsbi.a* can be compiled
natively or it can be cross-compiled on a host with a different base
architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
*riscv64-linux-gnu-* if the gcc executable used is *riscv64-linux-gnu-gcc*.
To build *libsbi.a* simply execute:
```
make
```
All compiled binaries as well as the resulting *libsbi.a* static library file
will be placed in the *build/lib* directory. To specify an alternate build root
directory path, run:
```
make O=<build_directory>
```
To generate files to be installed for using *libsbi.a* in other projects, run:
```
make install
```
This will create the *install* directory with all necessary include files
copied under the *install/include* directory and the library file copied into
the *install/lib* directory. To specify an alternate installation root
directory path, run:
```
make I=<install_directory> install
```
Building and Installing a Reference Platform Static Library and Firmware
------------------------------------------------------------------------
When the *PLATFORM=<platform_subdir>* argument is specified on the make command
line, the platform-specific static library *libplatsbi.a* and firmware examples
are built for the platform *<platform_subdir>* present in the directory
*platform* in the OpenSBI top directory. For example, to compile the platform
library and the firmware examples for the QEMU RISC-V *virt* machine,
*<platform_subdir>* should be *generic*.
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
platforms, run:
```
make PLATFORM=<platform_subdir>
```
An alternate build directory path can also be specified:
```
make PLATFORM=<platform_subdir> O=<build_directory>
```
The platform-specific library *libplatsbi.a* will be generated in the
*build/platform/<platform_subdir>/lib* directory. The platform firmware files
will be under the *build/platform/<platform_subdir>/firmware* directory.
The compiled firmwares will be available in two different formats: an ELF file
and an expanded image file.
To install *libsbi.a*, *libplatsbi.a*, and the compiled firmwares, run:
```
make PLATFORM=<platform_subdir> install
```
This will copy the compiled platform-specific libraries and firmware files
under the *install/platform/<platform_subdir>/* directory. An alternate
install root directory path can be specified as follows:
```
make PLATFORM=<platform_subdir> I=<install_directory> install
```
In addition, platform-specific configuration options can be specified with the
top-level make command line. These options, such as *PLATFORM_<xyz>* or
*FW_<abc>*, are platform-specific and described in more details in the
*docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files.
All OpenSBI platforms support Kconfig style build-time configuration. Users
can change the build-time configuration of a platform using a graphical
interface as follows:
```
make PLATFORM=<platform_subdir> menuconfig
```
Alternately, an OpenSBI platform can have multiple default configurations
and users can select a custom default configuration as follows:
```
make PLATFORM=<platform_subdir> PLATFORM_DEFCONFIG=<platform_custom_defconfig>
```
Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
to *riscv64-linux-gnu-*, 64-bit OpenSBI images will be generated. If building
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
pre-configured to generate 32-bit RISC-V codes, like *riscv32-linux-gnu-*.
However it's possible to explicitly specify the image bits we want to build with
a given RISC-V toolchain. This can be done by setting the environment variable
*PLATFORM_RISCV_XLEN* to the desired width, for example:
```
export CROSS_COMPILE=riscv64-linux-gnu-
export PLATFORM_RISCV_XLEN=32
```
will generate 32-bit OpenSBI images. And vice vesa.
Building with Clang/LLVM
------------------------
OpenSBI can also be built with Clang/LLVM. To build with just Clang but keep
the default binutils (which will still use the *CROSS_COMPILE* prefix if
defined), override the *CC* make variable with:
```
make CC=clang
```
To build with a full LLVM-based toolchain, not just Clang, enable the *LLVM*
option with:
```
make LLVM=1
```
To build with a specific version of LLVM, a path to a directory containing the
LLVM tools can be provided:
```
make LLVM=/path/to/llvm/
```
If you have versioned llvm tools you would like to use, such as `clang-17`, the LLVM variable can
be set as:
```
make LLVM=-17
```
When using Clang, *CROSS_COMPILE* often does not need to be defined unless
using GNU binutils with prefixed binary names. *PLATFORM_RISCV_XLEN* will be
used to infer a default triple to pass to Clang, so if *PLATFORM_RISCV_XLEN*
itself defaults to an undesired value then prefer setting that rather than the
full triple via *CROSS_COMPILE*. If *CROSS_COMPILE* is nonetheless defined,
rather than being used as a prefix for the executable name, it will instead be
passed via the `--target` option with the trailing `-` removed, so must be a
valid triple.
These can also be mixed; for example using a GCC cross-compiler but LLVM
binutils would be:
```
make CC=riscv64-linux-gnu-gcc LLVM=1
```
These variables must be passed for all the make invocations described in this
document.
NOTE: Using Clang with a `riscv*-linux-gnu` GNU binutils linker has been seen
to produce broken binaries with missing relocations; it is therefore currently
recommended that this combination be avoided.
Building with timestamp and compiler info
-----------------------------------------
When doing development, we may want to know the build time and compiler info
for debug purpose. OpenSBI can also be built with timestamp and compiler info.
To build with those info and print it out at boot time, we can just simply add
`BUILD_INFO=y`, like:
```
make BUILD_INFO=y
```
But if you have used `BUILD_INFO=y`, and want to switch back to `BUILD_INFO=n`,
you must do
```
make clean
```
before the next build.
NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate
[reproducible builds]. This definition is ONLY for development and debug
purpose, and should NOT be used in a product which follows "reproducible
builds".
Building with optimization off for debugging
--------------------------------------------
When debugging OpenSBI, we may want to turn off the compiler optimization and
make debugging produce the expected results for a better debugging experience.
To build with optimization off we can just simply add `DEBUG=1`, like:
```
make DEBUG=1
```
This definition is ONLY for development and debug purpose, and should NOT be
used in a product build.
Contributing to OpenSBI Contributing to OpenSBI
----------------------- -----------------------
The OpenSBI project encourages and welcomes contributions. Contributions should The OpenSBI project encourages and welcomes contributions. Contributions should
follow the rules described in the OpenSBI [Contribution Guideline] document. follow the rules described in OpenSBI [Contribution Guideline] document.
In particular, all patches sent should contain a Signed-off-by tag. In particular, all patches sent should contain a Signed-off-by tag.
The [Contributors List] document provides a list of individuals and
organizations actively contributing to the OpenSBI project.
Documentation Documentation
------------- -------------
@ -340,16 +168,13 @@ Detailed documentation of various aspects of OpenSBI can be found under the
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project * [Contribution Guideline]: Guideline for contributing code to OpenSBI project
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a* * [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
* [Platform Requirements]: Requirements for using OpenSBI on a platform
* [Platform Support Guide]: Guideline for implementing support for new platforms * [Platform Support Guide]: Guideline for implementing support for new platforms
* [Platform Documentation]: Documentation of the platforms currently supported. * [Platform Documentation]: Documentation of the platforms currently supported.
* [Firmware Documentation]: Documentation for the different types of firmware * [Firmware Documentation]: Documentation for the different types of firmware
examples build supported by OpenSBI. examples build supported by OpenSBI.
* [Domain Support]: Documentation for the OpenSBI domain support which helps
users achieve system-level partitioning using OpenSBI.
OpenSBI source code is also well documented. For source level documentation, OpenSBI source code is also well documented. For source level documentation,
doxygen style is used. Please refer to the [Doxygen manual] for details on this doxygen style is used. Please refer to [Doxygen manual] for details on this
format. format.
Doxygen can be installed on Linux distributions using *.deb* packages using Doxygen can be installed on Linux distributions using *.deb* packages using
@ -390,18 +215,12 @@ make I=<install_directory> install_docs
[Github]: https://github.com/riscv/riscv-sbi-doc [Github]: https://github.com/riscv/riscv-sbi-doc
[U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode [U-Boot]: https://www.denx.de/wiki/U-Boot/SourceCode
[Bootlin toolchain repository]: https://toolchains.bootlin.com/
[COPYING.BSD]: COPYING.BSD [COPYING.BSD]: COPYING.BSD
[SPDX]: http://spdx.org/licenses/ [SPDX]: http://spdx.org/licenses/
[Contribution Guideline]: docs/contributing.md [Contribution Guideline]: docs/contributing.md
[Contributors List]: CONTRIBUTORS.md
[Library Usage]: docs/library_usage.md [Library Usage]: docs/library_usage.md
[Platform Requirements]: docs/platform_requirements.md
[Platform Support Guide]: docs/platform_guide.md [Platform Support Guide]: docs/platform_guide.md
[Platform Documentation]: docs/platform/platform.md [Platform Documentation]: docs/platform/platform.md
[Firmware Documentation]: docs/firmware/fw.md [Firmware Documentation]: docs/firmware/fw.md
[Domain Support]: docs/domain_support.md [Doxygen manual]: http://www.stack.nl/~dimitri/doxygen/manual.html
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md
[reproducible builds]: https://reproducible-builds.org

View File

@ -1,18 +0,0 @@
Copyright (c) 2019 Western Digital Corporation or its affiliates.
Third Party Notices
===================
This project includes or partly uses code from the following open source
software subject to the following open source licenses.
libfdt
------
Copyright (C) 2016 Free Electrons
Copyright (C) 2016 NextThing Co.
The libfdt source code is disjunctively dual licensed (GPL-2.0+ or
BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
the BSD 2-Clause license. The full text of this license can be found in the
file [COPYING.BSD](COPYING.BSD).

View File

@ -1,18 +1,11 @@
OpenSBI Contribution Guideline OpenSBI Contribution Guideline
============================== ==============================
All contributions to OpenSBI must be sent via email patches to the OpenSBI All contributions to OpenSBI should be sent as GitHub Pull Requests (PRs) to
mailing list at `opensbi@lists.infradead.org`
To join the OpenSBI mailing list, please visit the [OpenSBI infradead page].
The mailing list based patch approach is preferred over github PRs so that they
are visible to a wider audience. All accepted patches on the OpenSBI mailing
list will be taken by one of the OpenSBI maintainers and merged into the
[OpenSBI main repository]. [OpenSBI main repository].
All contributed work must follow the following rules: All contributed work must follow the following rules:
1. OpenSBI code should be written in accordance to the [Linux coding style]. 1. OpenSBI code should be written in accordance to [Linux coding style].
2. This project embraces the [Developer Certificate of Origin (DCO)] for 2. This project embraces the [Developer Certificate of Origin (DCO)] for
contributions. This means that you must agree to the following prior to contributions. This means that you must agree to the following prior to
submitting patches: if you agree with this developer certificate you submitting patches: if you agree with this developer certificate you
@ -22,15 +15,17 @@ Every submitted patch must have this tag.
followed by a description of the patch content. A blank line and the author followed by a description of the patch content. A blank line and the author
Signed-off-by tag must follow this description. Signed-off-by tag must follow this description.
4. A commit subject line must start with a prefix followed by a ":". Common 4. A commit subject line must start with a prefix followed by a ":". Common
prefixes are for example "lib:", "platform:", "firmware:", "docs:", "utils:" prefixes are for example "lib:", "platform:", "firmware:", "docs:" and "top:".
and "top:".
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull 5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
requests to avoid creating unnecessary merge commits. requests to avoid creating unnecessary merge commits.
6. Maintainers should avoid creating branches directly in the main 6. Maintainers should avoid creating branches directly in the main
riscv/opensbi repository. Instead, prefer using a fork of the riscv/opensbi main riscv/opensbi repository. Instead prefer using a fork of riscv/opensbi main
repository and branches within that fork to create pull requests. repository and branches within that fork to create pull requests.
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main 7. A maintainer cannot merge his own pull requests in riscv/opensbi main
repository. repository.
8. A pull request must get at least one review from a maintainer.
9. A pull request must spend at least 24 hours in review to allow for other
developers to review.
----------------------------------------------------------------------- -----------------------------------------------------------------------
@ -74,6 +69,6 @@ By making a contribution to this project, I certify that:
----------------------------------------------------------------------- -----------------------------------------------------------------------
[OpenSBI main repository]: https://github.com/riscv/opensbi [OpenSBI main repository]: https://github.com/riscv/opensbi
[OpenSBI infradead page]: http://lists.infradead.org/mailman/listinfo/opensbi
[Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html [Linux coding style]: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
[Developer Certificate of Origin (DCO)]: http://developercertificate.org/ [Developer Certificate of Origin (DCO)]: http://developercertificate.org/

View File

@ -1,325 +0,0 @@
OpenSBI Domain Support
======================
An OpenSBI domain is a system-level partition (subset) of underlying hardware
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
will try to achieve secure isolation between domains using RISC-V platform
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
Important entities which help implement OpenSBI domain support are:
* **struct sbi_domain_memregion** - Representation of a domain memory region
* **struct sbi_hartmask** - Representation of domain HART set
* **struct sbi_domain** - Representation of a domain instance
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
The OpenSBI platform support is responsible for populating domains and
providing HART id to domain mapping. The OpenSBI domain support will by
default assign **the ROOT domain** to all HARTs of a RISC-V platform, so
it is not mandatory for the OpenSBI platform support to populate domains.
Domain Memory Region
--------------------
A domain memory region is represented by **struct sbi_domain_memregion** in
OpenSBI and has following details:
* **order** - The size of a memory region is **2 ^ order** where **order**
must be **3 <= order <= __riscv_xlen**
* **base** - The base address of a memory region is **2 ^ order**
aligned start address
* **flags** - The flags of a memory region represent memory type (i.e.
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
Domain Instance
---------------
A domain instance is represented by **struct sbi_domain** in OpenSBI and
has following details:
* **index** - Logical index of this domain
* **name** - Name of this domain
* **assigned_harts** - HARTs assigned to this domain
* **possible_harts** - HARTs possible in this domain
* **regions** - Array of memory regions terminated by a memory region
with order zero
* **boot_hartid** - HART id of the HART booting this domain. The domain
boot HART will be started at boot-time if boot HART is possible and
assigned for this domain.
* **next_addr** - Address of the next booting stage for this domain
* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for
this domain
* **next_mode** - Privilege mode of the next booting stage for this
domain. This can be either S-mode or U-mode.
* **system_reset_allowed** - Is domain allowed to reset the system?
* **system_suspend_allowed** - Is domain allowed to suspend the system?
The memory regions represented by **regions** in **struct sbi_domain** have
following additional constraints to align with RISC-V PMP requirements:
* A memory region to protect OpenSBI firmware from S-mode and U-mode
should always be present
* For two overlapping memory regions, one should be sub-region of another
* Two overlapping memory regions should not be of same size
* Two overlapping memory regions cannot have same flags
* Memory access checks on overlapping address should prefer smallest
overlapping memory region flags.
ROOT Domain
-----------
**The ROOT domain** is the default OpenSBI domain which is assigned by
default to all HARTs of a RISC-V platform. The OpenSBI domain support
will hand-craft **the ROOT domain** very early at boot-time in the
following manner:
* **index** - Logical index of the ROOT domain is always zero
* **name** - Name of the ROOT domain is "root"
* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform
are assigned the ROOT domain which changes later based on OpenSBI
platform support
* **possible_harts** - All valid HARTs of a RISC-V platform are possible
HARTs of the ROOT domain
* **regions** - Two memory regions available to the ROOT domain:
**A)** A memory region to protect OpenSBI firmware from S-mode and U-mode
**B)** A memory region of **order=__riscv_xlen** allowing S-mode and
U-mode access to full memory address space
* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain
* **next_addr** - Next booting stage address in coldboot HART scratch
space is the next address for the ROOT domain
* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space
is the next arg1 for the ROOT domain
* **next_mode** - Next booting stage mode in coldboot HART scratch space
is the next mode for the ROOT domain
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
Domain Effects
--------------
Few noteworthy effects of a system partitioned into domains are as follows:
* At any point in time, a HART is running in exactly one OpenSBI domain context
* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in
domain assigned to HART A
* The SBI HSM calls which try to change/read state of HART B from HART A will
only work if both HART A and HART B are assigned same domain
* A HART running in S-mode or U-mode can only access memory based on the
memory regions of the domain assigned to the HART
Domain Device Tree Bindings
---------------------------
The OpenSBI domains can be described in the **device tree (DT) blob** (or
flattened device tree) passed to the OpenSBI firmwares by the previous
booting stage. This allows OpenSBI platform support to parse and populate
OpenSBI domains from the device tree blob (or flattened device tree).
### Domain Configuration Node
All OpenSBI domain description related DT nodes should be under the domain
configuration DT node. The **/chosen** DT node is the preferred parent of
the domain configuration DT node.
The DT properties of a domain configuration DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain
configuration. This DT property should have value *"opensbi,domain,config"*
### Domain Memory Region Node
The domain memory region DT node describes details of a memory region and
can be pointed by multiple domain instance DT nodes. The access permissions
of the memory region are specified separately in domain instance node.
The DT properties of a domain memory region DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain memory
region. This DT property should have value *"opensbi,domain,memregion"*
* **base** (Mandatory) - The base address of the domain memory region. This
DT property should have a **2 ^ order** aligned 64 bit address (i.e. two
DT cells).
* **order** (Mandatory) - The order of the domain memory region. This DT
property should have a 32 bit value (i.e. one DT cell) in the range
**3 <= order <= __riscv_xlen**.
* **mmio** (Optional) - A boolean flag representing whether the domain
memory region is a memory-mapped I/O (MMIO) region.
* **devices** (Optional) - The list of device DT node phandles for devices
which fall under this domain memory region.
### Domain Instance Node
The domain instance DT node describes set of possible HARTs, set of memory
regions, and other details of a domain instance.
The DT properties of a domain instance DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain instance.
This DT property should have value *"opensbi,domain,instance"*
* **possible-harts** (Optional) - The list of CPU DT node phandles for the
the domain instance. This list represents the possible HARTs of the
domain instance.
* **regions** (Optional) - The list of domain memory region DT node phandle
and access permissions for the domain instance. Each list entry is a pair
of DT node phandle and access permissions. The access permissions are
represented as a 32bit bitmask having bits: **M readable** (BIT[0]),
**M writeable** (BIT[1]), **M executable** (BIT[2]), **SU readable**
(BIT[3]), **SU writable** (BIT[4]), and **SU executable** (BIT[5]).
The enforce permission bit (BIT[6]), if set, will lock the permissions
in the PMP. This will enforce the permissions on M-mode as well which
otherwise will have unrestricted access. This bit must be used with
caution because no changes can be made to a PMP entry once its locked
until the hart is reset.
Any region of a domain defined in DT node cannot have only M-bits set
in access permissions i.e. it cannot be an m-mode only accessible region.
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
domain instance. If coldboot HART is assigned to the domain instance then
this DT property is ignored and the coldboot HART is assumed to be the
boot HART of the domain instance.
* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **next booting stage arg1 of coldboot HART**
is used as default value.
* **next-addr** (Optional) - The 64 bit next booting stage address for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **0x0** is used as default
value. If this DT property is not available and coldboot HART is assigned
to the domain instance then **next booting stage address of coldboot HART**
is used as default value.
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
domain instance. The possible values of this DT property are: **0x1**
(S-mode), and **0x0** (U-mode). If this DT property is not available
and coldboot HART is not assigned to the domain instance then **0x1**
is used as default value. If this DT property is not available and
coldboot HART is assigned to the domain instance then **next booting
stage mode of coldboot HART** is used as default value.
* **system-reset-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system reset.
* **system-suspend-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system suspend.
### Assigning HART To Domain Instance
By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI
platform support can provide the HART to domain instance assignment using
platform specific callback.
The HART to domain instance assignment can be parsed from the device tree
using optional DT property **opensbi-domain** in each CPU DT node. The
value of DT property **opensbi-domain** is the DT phandle of the domain
instance DT node. If **opensbi-domain** DT property is not specified then
corresponding HART is assigned to **the ROOT domain**.
### Domain Configuration Only Accessible to OpenSBI
The software running inside a domain instance should only be aware of
devices and hardware resources accessible to itself.
To hide domain configuration from domain instances, the following should
be done:
* The previous booting stage should preferably provide a separate device
tree for each domain instance and mention location of device tree in
respective domain instance DT nodes using **next-arg1** DT property.
* If domain assigned to a HART does not have separate device tree then
OpenSBI platform support should remove all domain configuration details
from the device tree passed by previous booting stage before passing it
to the next booting stage.
### Example
```
chosen {
opensbi-domains {
compatible = "opensbi,domain,config";
tmem: tmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x80100000>;
order = <20>;
};
tuart: tuart {
compatible = "opensbi,domain,memregion";
base = <0x0 0x10011000>;
order = <12>;
mmio;
devices = <&uart1>;
};
allmem: allmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x0>;
order = <64>;
};
tdomain: trusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu0>;
regions = <&tmem 0x3f>, <&tuart 0x3f>;
boot-hart = <&cpu0>;
next-arg1 = <0x0 0x0>;
next-addr = <0x0 0x80100000>;
next-mode = <0x0>;
system-reset-allowed;
system-suspend-allowed;
};
udomain: untrusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x3f>;
};
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <10000000>;
cpu0: cpu@0 {
device_type = "cpu";
reg = <0x00>;
compatible = "riscv";
opensbi-domain = <&tdomain>;
...
};
cpu1: cpu@1 {
device_type = "cpu";
reg = <0x01>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu2: cpu@2 {
device_type = "cpu";
reg = <0x02>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu3: cpu@3 {
device_type = "cpu";
reg = <0x03>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu4: cpu@4 {
device_type = "cpu";
reg = <0x04>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
};
uart1: serial@10011000 {
...
};
```

View File

@ -44,7 +44,7 @@ PROJECT_NUMBER = "v@@OPENSBI_MAJOR@@.@@OPENSBI_MINOR@@"
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Open source implemenation of the supervisor binary interface" PROJECT_BRIEF = "Open source implemenation of supervisor binary interface"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55
@ -793,11 +793,7 @@ WARN_LOGFILE =
INPUT = @@SRC_DIR@@/README.md \ INPUT = @@SRC_DIR@@/README.md \
@@SRC_DIR@@/docs/contributing.md \ @@SRC_DIR@@/docs/contributing.md \
@@SRC_DIR@@/docs/platform_guide.md \ @@SRC_DIR@@/docs/platform_guide.md \
@@SRC_DIR@@/docs/platform_requirements.md \
@@SRC_DIR@@/docs/library_usage.md \ @@SRC_DIR@@/docs/library_usage.md \
@@SRC_DIR@@/docs/domain_support.md \
@@SRC_DIR@@/docs/opensbi_config.md \
@@SRC_DIR@@/docs/writing_tests.md \
@@SRC_DIR@@/docs/firmware \ @@SRC_DIR@@/docs/firmware \
@@SRC_DIR@@/docs/platform \ @@SRC_DIR@@/docs/platform \
@@SRC_DIR@@/include \ @@SRC_DIR@@/include \
@ -952,7 +948,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub # (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output. # and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = README.md USE_MDFILE_AS_MAINPAGE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to source browsing # Configuration options related to source browsing
@ -1448,7 +1444,7 @@ DISABLE_INDEX = NO
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation. # doxygen will group on one line in the generated HTML documentation.

View File

@ -1,32 +0,0 @@
OpenSBI as coreboot payload
===========================
[coreboot] is a free/libre and open source firmware platform support multiple
hardware architectures(x86, ARMv7, arm64, PowerPC64, MIPS and RISC-V) and
diverse hardware models. In RISC-V world, coreboot currently support HiFive
Unleashed with OpenSBI as a payload to boot GNU/Linux:
```
SiFive HiFive unleashed's original firmware boot process:
+-----------+
+------+ +------+ +------+ | BBL |
| MSEL |--->| ZSBL |--->| FSBL |--->| +-------+
+------+ +------+ +------+ | | linux |
+---+-------+
coreboot boot process:
+---------------------------------------------------------------------+
| coreboot |
+------+ +------+ | +-----------+ +----------+ +----------+ +-----------------------+
| MSEL |-->| ZSBL |-->| | bootblock |->| romstage |->| ramstage |->| payload ( OpenSBI) |
+------+ +------+ | +-----------+ +----------+ +----------+ | +-------+ |
| | | linux | |
+---------------------------------------------+-------------+-------+-+
```
The upstreaming work is still in progress. There's a [documentation] about how
to build [out-of-tree code] to load OpenSBI.
[coreboot]: https://www.coreboot.org/
[documentation]: https://github.com/hardenedlinux/embedded-iot_profile/blob/master/docs/riscv/hifiveunleashed_coreboot_notes-en.md
[out-of-tree code]: https://github.com/hardenedlinux/coreboot-HiFiveUnleashed

View File

@ -9,29 +9,12 @@ OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed. how the boot stage following the firmware will be handled and executed.
The previous booting stage will pass information via the following registers OpenSBI currently supports two different types of firmwares.
of RISC-V CPU:
* hartid via *a0* register
* device tree blob address in memory via *a1* register. The address must
be aligned to 8 bytes.
OpenSBI currently supports three different types of firmwares.
Firmware with Dynamic Information (*FW_DYNAMIC*)
------------------------------------------------
The *FW_DYNAMIC* firmware gets information about the next booting stage entry,
e.g. a bootloader or an OS kernel, from previous booting stage at runtime.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware
and the booting stage binary to follow OpenSBI firmware.
Firmware with Jump Address (*FW_JUMP*) Firmware with Jump Address (*FW_JUMP*)
-------------------------------------- --------------------------------------
The *FW_JUMP* firmware assumes a fixed address of the next booting stage The *FW_JUMP* firmware only handles the address of the next booting stage
entry, e.g. a bootloader or an OS kernel, without directly including the entry, e.g. a bootloader or an OS kernel, without directly including the
binary code for this next stage. binary code for this next stage.
@ -53,36 +36,26 @@ the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
.rodata section of the final firmware. .text section of the final firmware.
Firmware Configuration and Compilation Firmware Configuration and Compilation
-------------------------------------- --------------------------------------
All firmware types support the following common compile time configuration All firmware types mandate the definition of the following compile time
parameters: configuration parameter.
* **FW_TEXT_START** - Defines the compile time address of the OpenSBI * **FW_TEXT_ADDR** - Defines the address at which the previous booting stage
firmware. This configuration parameter is optional and assumed to be loads OpenSBI firmware.
`0` if not specified.
* **FW_FDT_PATH** - Path to an external flattened device tree binary file to
be embedded in the *.rodata* section of the final firmware. If this option
is not provided then the firmware will expect the FDT to be passed as an
argument by the prior booting stage.
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
device tree binary file specified by **FW_FDT_PATH** option.
Additionally, each firmware type as a set of type specific configuration Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the parameters. Detailed information for each firmware type can be found in the
following documents. following documents.
* *[FW_DYNAMIC]*: The *Firmware with Dynamic Information (FW_DYNAMIC)* is
described in more details in the file *fw_dynamic.md*.
* *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more * *[FW_JUMP]*: The *Firmware with Jump Address (FW_JUMP)* is described in more
details in the file *fw_jump.md*. details in the file *fw_jump.md*.
* *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more * *[FW_PAYLOAD]*: The *Firmware with Payload (FW_PAYLOAD)* is described in more
details in the file *fw_payload.md*. details in the file *fw_payload.md*.
[FW_DYNAMIC]: fw_dynamic.md
[FW_JUMP]: fw_jump.md [FW_JUMP]: fw_jump.md
[FW_PAYLOAD]: fw_payload.md [FW_PAYLOAD]: fw_payload.md
@ -102,18 +75,3 @@ make PLATFORM=<platform_subdir> FW_PAYLOAD_PATH=<payload path>
The instructions to build each payload is different and the details can The instructions to build each payload is different and the details can
be found in the be found in the
*docs/firmware/payload_<payload_name>.md* files. *docs/firmware/payload_<payload_name>.md* files.
Options for OpenSBI Firmware behaviors
--------------------------------------
An optional compile time flag FW_OPTIONS can be used to control the OpenSBI
firmware run-time behaviors.
```
make PLATFORM=<platform_subdir> FW_OPTIONS=<options>
```
FW_OPTIONS is a bitwise or'ed value of various options, eg: *FW_OPTIONS=0x1*
stands for disabling boot prints from the OpenSBI library.
For all supported options, please check "enum sbi_scratch_options" in the
*include/sbi/sbi_scratch.h* header file.

View File

@ -1,36 +0,0 @@
OpenSBI Firmware with Dynamic Information (FW_DYNAMIC)
======================================================
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
information about next booting stage (e.g. a bootloader or an OS) and runtime
OpenSBI library options from previous booting stage.
The previous booting stage will pass information to *FW_DYNAMIC* by creating
*struct fw_dynamic_info* in memory and passing its address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU. The address must be aligned to 8 bytes on
RV64 and 4 bytes on RV32.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
the booting stage binary to follow OpenSBI firmware.
*FW_DYNAMIC* Compilation
------------------------
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
2. Specifying `FW_DYNAMIC=y` in the target platform *objects.mk* configuration
file.
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
expanded image file is *fw_dynamic.bin*. Both files are created in the platform
specific build directory under the *build/platform/<platform_subdir>/firmware*
directory.
*FW_DYNAMIC* Firmware Configuration Options
-------------------------------------------
The *FW_DYNAMIC* firmware does not require any platform specific configuration
parameters because all required information is passed by previous booting stage
at runtime via *struct fw_dynamic_info*.

View File

@ -1,4 +1,4 @@
OpenSBI Firmware with Jump Address (FW_JUMP) OpenSBI Firmware with Jump Address *FW_JUMP*
============================================ ============================================
OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only
@ -6,19 +6,19 @@ handles the address of the next booting stage entry, e.g. a bootloader or an OS
kernel, without directly including the binary code for this next stage. kernel, without directly including the binary code for this next stage.
A *FW_JUMP* firmware is particularly useful when the booting stage executed A *FW_JUMP* firmware is particularly useful when the booting stage executed
prior to the OpenSBI firmware is capable of loading both the OpenSBI firmware prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and
and the booting stage binary to follow the OpenSBI firmware. the booting stage binary to follow OpenSBI firmware.
*FW_JUMP* Compilation *FW_JUMP* Compilation
--------------------- ---------------------
A platform *FW_JUMP* firmware can be enabled by any of the following methods: A platform *FW_JUMP* firmware can be enabled by any of the following methods.
1. Specifying `FW_JUMP=y` on the top level `make` command line. 1. Specifying `FW_JUMP=y` on the top level `make` command line.
2. Specifying `FW_JUMP=y` in the target platform *objects.mk* configuration file. 2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
image file is *fw_jump.bin*. Both files are created in the platform-specific image file is *fw_jump.bin*. Both files are created in the platform specific
build directory under the *build/platform/<platform_subdir>/firmware* directory. build directory under the *build/platform/<platform_subdir>/firmware* directory.
*FW_JUMP* Firmware Configuration Options *FW_JUMP* Firmware Configuration Options
@ -26,53 +26,27 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
To operate correctly, a *FW_JUMP* firmware requires some configuration To operate correctly, a *FW_JUMP* firmware requires some configuration
parameters to be defined using either the top level `make` command line or the parameters to be defined using either the top level `make` command line or the
target platform *objects.mk* configuration file. The possible parameters are as target platform *config.mk* configuration file. The possible parameters are as
follows: follows.
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be * **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
executed following OpenSBI firmware. This address generally corresponds executed following OpenSBI firmware. This address generally correspond
exactly to the address where this next booting stage was loaded. exactly to the address where this next booting stage was loaded. This is a
At least one of *FW_JUMP_ADDR* and *FW_JUMP_OFFSET* (see below) should be mandatory parameter. Compilation errors will result from not defining this
defined. Compilation errors will result from not defining one of them. address.
* **FW_JUMP_OFFSET** - Address offset from the opensbi load address where the
entry point of the next booting stage is located. This offset is used as
relocatable address of the next booting stage entry point. If *FW_JUMP_ADDR*
is also defined, the firmware will prefer *FW_JUMP_ADDR*.
* **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)* * **FW_JUMP_FDT_ADDR** - Address where the *flattened device tree (FDT file)*
passed by the prior booting stage will be placed in memory before executing passed by the prior booting stage will be placed in memory before executing
the booting stage following the OpenSBI firmware. If this option is not the booting stage following OpenSBI firmware. If this option is not provided,
provided, then the OpenSBI firmware will pass the FDT address passed by the then OpenSBI firmware will pass zero as the FDT address to the following
previous booting stage to the next booting stage. booting stage.
When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must
ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel.
You can use the following method (e.g., using bash or zsh):
```
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | awk -n '
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
```
* **FW_JUMP_FDT_OFFSET** - Address offset from the opensbi load address where
the FDT will be passed to the next booting stage. This offset is used
as relocatable address of the FDT passed to the next booting stage. If
*FW_JUMP_FDT_ADDR* is also defined, the firmware will prefer
*FW_JUMP_FDT_ADDR*.
*FW_JUMP* Example *FW_JUMP* Example
----------------- -----------------
The *[qemu/virt]* platform illustrates how to configure and use a *FW_JUMP* The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure
firmware. Detailed information regarding these platforms can be found in the and use a *FW_JUMP* firmware. Detailed information regarding these platforms
platform documentation files. can be found in the platforms documentation files.
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@ -1,31 +1,31 @@
OpenSBI Firmware with Payload (FW_PAYLOAD) OpenSBI Firmware with Payload *FW_PAYLOAD*
========================================== ==========================================
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
includes the binary for the booting stage to follow the OpenSBI firmware includes the binary for the booting stage to follow OpenSBI firmware execution.
execution. Typically, this payload will be a bootloader or an OS kernel. Typically, this payload will be a bootloader or an OS kernel.
A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed A *FW_PAYLOAD* firmware is particularly useful when the booting stage executed
prior to the OpenSBI firmware is not capable of loading both the OpenSBI prior to OpenSBI firmware is not capable of loading both OpenSBI firmware and
firmware and the booting stage to follow OpenSBI firmware. the booting stage to follow OpenSBI firmware.
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
in the .rodata section of the final firmware. .text section of the final firmware.
Enabling *FW_PAYLOAD* compilation Enabling *FW_PAYLOAD* compilation
--------------------------------- ---------------------------------
The *FW_PAYLOAD* firmware can be enabled by any of the following methods: The *FW_PAYLOAD* firmware can be enabled by any of the following methods.
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line. 1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
2. Specifying `FW_PAYLOAD=y` in the target platform *objects.mk* configuration 2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
file. file.
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_payload.elf*. Its The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
expanded image file is *fw_payload.bin*. Both files are created in the expanded image file is *fw_payload.bin*. Both files are created in the
platform-specific build directory under the platform specific build directory under the
*build/platform/<platform_subdir>/firmware* directory. *build/platform/<platform_subdir>/firmware* directory.
Configuration Options Configuration Options
@ -33,11 +33,11 @@ Configuration Options
A *FW_PAYLOAD* firmware is built according to configuration parameters and A *FW_PAYLOAD* firmware is built according to configuration parameters and
options. These configuration parameters can be defined using either the top options. These configuration parameters can be defined using either the top
level `make` command line or the target platform *objects.mk* configuration level `make` command line or the target platform *config.mk* configuration
file. The parameters currently defined are as follows: file. The parameters currently defined are as follows.
* **FW_PAYLOAD_OFFSET** - Offset from the opensbi load address where the payload * **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
binary will be linked in the final *FW_PAYLOAD* firmware binary image. This will be linked in the final *FW_PAYLOAD* firmware binary image. This
configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined. configuration parameter is mandatory if *FW_PAYLOAD_ALIGN* is not defined.
Compilation errors will result from an incorrect definition of Compilation errors will result from an incorrect definition of
*FW_PAYLOAD_OFFSET* or of *FW_PAYLOAD_ALIGN*, or if neither of these *FW_PAYLOAD_OFFSET* or of *FW_PAYLOAD_ALIGN*, or if neither of these
@ -48,30 +48,43 @@ file. The parameters currently defined are as follows:
*FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory *FW_PAYLOAD* firmware binary image. This configuration parameter is mandatory
if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and if *FW_PAYLOAD_OFFSET* is not defined. If both *FW_PAYLOAD_OFFSET* and
*FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and *FW_PAYLOAD_ALIGN* are defined, *FW_PAYLOAD_OFFSET* is used and
*FW_PAYLOAD_ALIGN* is ignored. *FW_PAYLOAD_ALIGN* ignored.
* **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage * **FW_PAYLOAD_PATH** - Path to the image file of the next booting stage
binary. If this option is not provided then a simple test payload is binary. If this option is not provided then a simple test payload is
automatically generated and used as a payload. This test payload executes automatically generated and used as a payload. This test payload executes
an infinite `while (1)` loop after printing a message on the platform console. an infinite `while (1)` loop after printing a message on the platform console.
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting * **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
stage or specified by the *FW_FDT_PATH* parameter and embedded in the file to be embedded in the *.text* section of the final firmware. If this
*.rodata* section will be placed before executing the next booting stage, option is not provided and no internal device tree file is specified by the
that is, the payload firmware. If this option is not provided, then the platform (c.f. *FW_PAYLOAD_FDT*), then the firmware will expect the FDT to
firmware will pass the FDT address passed by the previous booting stage be passed as an argument by the prior booting stage.
to the next booting stage.
* **FW_PAYLOAD_FDT_OFFSET** - Address offset from the opensbi load address where * **FW_PAYLOAD_FDT** - Path to an internal flattened device tree binary file
the FDT will be passed to the next booting stage. This offset is used as defined by the platform code. The file name must match the DTB file name
relocatable address of the FDT passed to the next booting stage. If specified in the platform *objects.mk* file with the *platform-dtb-y* entry.
*FW_PAYLOAD_FDT_ADDR* is also defined, the firmware will prefer *FW_PAYLOAD_FDT_ADDR*. This option results in *FW_PAYLOAD_FDT_PATH* to be automatically set.
Specifying *FW_PAYLOAD_FDT_PATH* on the `make` command line disables
*FW_PAYLOAD_FDT* and the command line specified device tree binary file is
used for building the final firmware.
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
the *.text* section will be placed before executing the next booting stage,
that is, the payload firmware. If this option is not provided, then the
firmware will pass zero as the FDT address to the next booting stage.
*FW_PAYLOAD* Example *FW_PAYLOAD* Example
-------------------- --------------------
The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD* The *[qemu/virt]* and *[qemu/sifive_u]* platforms illustrates how to configure
firmware. Detailed information regarding these platforms can be found in the and use a *FW_PAYLOAD* firmware. Detailed information regarding these platforms
platform documentation files. can be found in the platforms documentation files.
The *kendryte/k210* platform also enables build of a *FW_PAYLOAD* using an
internally defined device tree file (*FW_PAYLOAD_FDT*).
[qemu/virt]: ../platform/qemu_virt.md [qemu/virt]: ../platform/qemu_virt.md
[qemu/sifive_u]: ../platform/qemu_sifive_u.md

View File

@ -1,9 +1,11 @@
Linux as a direct payload to OpenSBI Linux as a direct payload to OpenSBI
==================================== ====================================
OpenSBI has the capability to load a Linux kernel image directly in supervisor OpenSBI has the capability to load Linux kernel image directly in supervisor
mode. The flattened image generated by the Linux kernel build process can be mode. The flattened image generated by the Linux kernel build process can be
provided as a payload to OpenSBI. provided as payload to OpenSBI.
Detailed examples and platform guides can be found in both [QEMU](
../platform/qemu_virt.md) and [HiFive Unleashed](../platform/sifive_fu540.md)
platform guide respectively.
Detailed examples can be found in both the [QEMU](../platform/qemu_virt.md)
and the [HiFive Unleashed](../platform/sifive_fu540.md) platform guides.

View File

@ -3,13 +3,36 @@ U-Boot as a payload to OpenSBI
[U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader. [U-Boot](https://www.denx.de/wiki/U-Boot) is an open-source primary boot loader.
It can be used as first and/or second stage boot loader in an embedded It can be used as first and/or second stage boot loader in an embedded
environment. In the context of OpenSBI, U-Boot can be specified as a payload to environment. In the context of OpenSBI, U-boot can be specified as a payload to
the OpenSBI firmware, becoming the boot stage following the OpenSBI firmware OpenSBI firmware, becoming the boot stage following OpenSBI firmware
execution. execution.
The current stable upstream code of U-boot does not yet include all patches
necessary to fully support OpenSBI. To use U-Boot as an OpenSBI payload, the
following out-of-tree patch series must be applied to the upstream U-Boot source
code.
HiFive Unleashed support for U-Boot
https://lists.denx.de/pipermail/u-boot/2019-February/358058.html
This patch series enables a single CPU to execute U-Boot. As a result, the next
stage boot code such as Linux kernel can also only execute a single CPU. U-Boot
SMP support for RISC-V can be enabled with the following additional patches.
https://lists.denx.de/pipermail/u-boot/2019-February/358393.html
Building and Generating U-Boot images Building and Generating U-Boot images
===================================== =====================================
Please refer to the U-Boot build documentation for detailed instructions on Please refer to U-Boot build documentation for detailed instructions on how to build U-Boot images.
how to build U-Boot image and boot high level operating systems from U-Boot
prompt.
Once U-Boot images are built, Linux kernel image need to be converted to a format
that U-Boot understands.
```
<uboot-dir>/tools/mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
Copy the uImage to your tftpboot server path if network boot is required.

View File

@ -3,46 +3,46 @@ OpenSBI Library Usage
OpenSBI provides two types of static libraries: OpenSBI provides two types of static libraries:
1. *libsbi.a* - A platform-independent generic static library implementing the 1. *libsbi.a* - A platform independent generic static library implementing the
interface defined by the SBI specifications. Platform-specific processing interface defined by the SBI specifications. Platform specific processing
hooks for the execution of this interface must be provided by the firmware or hooks for the execution of this interface must be provided by the firmware or
bootloader linking with this library. This library is installed as bootloader linking with this library. This library is installed as
*<install_directory>/lib/libsbi.a* *<install_directory>/lib/libsbi.a*
2. *libplatsbi.a* - An example platform-specific static library integrating 2. *libplatsbi.a* - An example platform specific static library integrating
*libsbi.a* with platform-specific hooks. This library is available only for *libsbi.a* with platform specific hooks. This library is available only for
the platforms supported by OpenSBI. This library is installed as the platforms supported by OpenSBI. This library is installed as
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a* *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
Implementations may choose either *libsbi.a* or *libplatsbi.a* to link with Implementations may choose either *libsbi.a* or *libplatsbi.a* to link with
their firmware or bootloader. In the case of *libsbi.a*, platform-specific their firmware or bootloader. In the case of *libsbi.a*, platform specific
hooks in the form of a *struct sbi_platform* instance need to be provided. hooks in the form of a *struct sbi_platform* instance needs to be provided.
The platform-specific example firmwares provided by OpenSBI are not mandatory. The platform specific example firmwares provided by OpenSBI are not mandatory.
An implementation may choose to link the OpenSBI generic static library together An implementation may choose to link OpenSBI generic static library together
with an M-mode firmware or bootloader providing the hardware-specific hooks. with an M-mode firmware or bootloader providing hardware specific hooks. Since
Since OpenSBI is a statically linked library, users must ensure that the OpenSBI is a statically linked library, users must ensure that the license of
license of these external components is compatible with the OpenSBI license. these external components is compatible with OpenSBI license.
Constraints on OpenSBI usage from external firmware Constraints on OpenSBI usage from external firmware
--------------------------------------------------- ---------------------------------------------------
Users have to ensure that an external firmware or bootloader linking against Users have to ensure that an external firmware or bootloader linking against
OpenSBI static libraries (*libsbi.a* or *libplatsbi.a*) is compiled with the OpenSBI static libraries (*libsbi.a* or *libplatsbi.a*) are compiled with the
same GCC target options *-mabi*, *-march*, and *-mcmodel*. same GCC target options *-mabi*, *-march*, and *-mcmodel*.
There are only two constraints on calling any OpenSBI library function from an There are only two constraints on calling any OpenSBI library function from an
external M-mode firmware or bootloader: external M-mode firmware or bootloader:
1. The RISC-V *MSCRATCH* CSR must point to a valid OpenSBI scratch space 1. The RISC-V *MSCRATCH* CSR must point to a valid OpenSBI scratch space
(i.e. a *struct sbi_scratch* instance). (i.e. *struct sbi_scratch* instance)
2. The RISC-V *SP* register (i.e. the stack pointer) must be set per-HART 2. The RISC-V *SP* register (i.e. stack pointer) must be set per-HART
pointing to distinct non-overlapping stacks. pointing to distinct non-overlapping stacks
The most important functions from an external firmware or bootloader The most important functions from an external firmware or bootloader
perspective are *sbi_init()* and *sbi_trap_handler()*. perspective are *sbi_init()* and *sbi_trap_handler()*.
In addition to the above constraints, the external firmware or bootloader must In addition to the above constraints, the external firmware or bootloader must
ensure that interrupts are disabled in the *MSTATUS* and *MIE* CSRs when calling ensure that interrupts are disabled in *MSTATUS* and *MIE* CSRs when calling
the functions *sbi_init()* and *sbi_trap_handler()*. the functions *sbi_init()* and *sbi_trap_handler()*.
The *sbi_init()* function should be called by the external firmware or The *sbi_init()* function should be called by the external firmware or
@ -63,23 +63,3 @@ bootloader to service the following interrupts and traps:
**Note:** external firmwares or bootloaders can be more conservative by **Note:** external firmwares or bootloaders can be more conservative by
forwarding all traps and interrupts to *sbi_trap_handler()*. forwarding all traps and interrupts to *sbi_trap_handler()*.
Definitions of OpenSBI Data Types for the External Firmware
-----------------------------------------------------------
OpenSBI can be built as library using external firmware build system such as EDK2
code base (The open source of UEFI firmware implementation) and linked with external
firmware drivers based on the external firmware architecture.
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
external header file during the build preprocess in order to define OpensSBI data types
based on external firmware data type binding.
For example, *bool* is declared as *int* in sbi_types.h. However, in EDK2 build system,
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
header file maintained in its code tree. However, the external build system has to address
the additional include directory for the external header file based on its own build system.
For example,
*-D***OPENSBI_EXTERNAL_SBI_TYPES***=OpensbiTypes.h*
Above tells *sbi_types.h* to refer to *OpensbiTypes.h* instead of using original definitions of
data types.

View File

@ -1,91 +0,0 @@
OpenSBI Device Tree Configuration Guideline
==================================
Some configurations of OpenSBI's Generic Platform can be described
in the **device tree (DT) blob** (or flattened device tree) passed
to the OpenSBI firmwares by the previous booting stage. OpenSBI will
parse and use these configurations during the boot phase, but delete
them from the device tree at the end of cold boot.
### OpenSBI Configuration Node
All nodes related to OpenSBI configuration should be under the OpenSBI
configuration DT node. The **/chosen** DT node is the preferred parent
of the OpenSBI configuration DT node.
The DT properties of a domain configuration DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the OpenSBI
configuration. This DT property should have value *"opensbi,config"*
* **cold-boot-harts** (Optional) - If a platform lacks an override
cold_boot_allowed() mechanism, this DT property specifies that a
set of harts is permitted to perform a cold boot. Otherwise, all
harts are allowed to cold boot.
* **heap-size** (Optional) - When present, the specified value is used
as the size of the heap in bytes.
* **system-suspend-test** (Optional) - When present, enable a system
suspend test implementation which simply waits five seconds and issues a WFI.
The OpenSBI Configuration Node will be deleted at the end of cold boot
(replace the node (subtree) with nop tags).
### Example
```text
chosen {
opensbi-config {
compatible = "opensbi,config";
cold-boot-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
heap-size = <0x400000>;
system-suspend-test;
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <10000000>;
cpu0: cpu@0 {
device_type = "cpu";
reg = <0x00>;
compatible = "riscv";
...
};
cpu1: cpu@1 {
device_type = "cpu";
reg = <0x01>;
compatible = "riscv";
...
};
cpu2: cpu@2 {
device_type = "cpu";
reg = <0x02>;
compatible = "riscv";
...
};
cpu3: cpu@3 {
device_type = "cpu";
reg = <0x03>;
compatible = "riscv";
...
};
cpu4: cpu@4 {
device_type = "cpu";
reg = <0x04>;
compatible = "riscv";
...
};
};
uart1: serial@10011000 {
...
};
```

View File

@ -1,207 +0,0 @@
Andes AE350 SoC Platform
========================
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
memories, interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
AXI-to-AHB Bridge and a collection of fundamental AHB/APB bus IP components
pre-integrated together as a system design. The high-quality and configurable
AHB/APB IPs suites a majority embedded systems, and the verified platform serves
as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
AE350's dts is included in https://github.com/andestech/linux/tree/RISCV-Linux-5.4-ast-v5_1_0-branch
**Linux Kernel Payload**
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
```
DTS Example: (Quad-core AX45MP)
-------------------------------
```
compatible = "andestech,ae350";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <60000000>;
CPU0: cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU0_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU1: cpu@1 {
device_type = "cpu";
reg = <1>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU1_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU2: cpu@2 {
device_type = "cpu";
reg = <2>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU2_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
CPU3: cpu@3 {
device_type = "cpu";
reg = <3>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
riscv,priv-major = <1>;
riscv,priv-minor = <10>;
mmu-type = "riscv,sv48";
clock-frequency = <60000000>;
i-cache-size = <0x8000>;
i-cache-sets = <256>;
i-cache-line-size = <64>;
i-cache-block-size = <64>;
d-cache-size = <0x8000>;
d-cache-sets = <128>;
d-cache-line-size = <64>;
d-cache-block-size = <64>;
next-level-cache = <&L2>;
CPU3_intc: interrupt-controller {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "andestech,riscv-ae350-soc", "simple-bus";
ranges;
plic0: interrupt-controller@e4000000 {
compatible = "riscv,plic0";
reg = <0x00000000 0xe4000000 0x00000000 0x02000000>;
interrupts-extended = < &CPU0_intc 11 &CPU0_intc 9
&CPU1_intc 11 &CPU1_intc 9
&CPU2_intc 11 &CPU2_intc 9
&CPU3_intc 11 &CPU3_intc 9 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
riscv,ndev = <71>;
};
plicsw: interrupt-controller@e6400000 {
compatible = "andestech,plicsw";
reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
interrupts-extended = < &CPU0_intc 3
&CPU1_intc 3
&CPU2_intc 3
&CPU3_intc 3 >;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
plmt0: plmt0@e6000000 {
compatible = "andestech,plmt0";
reg = <0x00000000 0xe6000000 0x00000000 0x00100000>;
interrupts-extended = < &CPU0_intc 7
&CPU1_intc 7
&CPU2_intc 7
&CPU3_intc 7 >;
};
wdt: watchdog@f0500000 {
compatible = "andestech,atcwdt200";
reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
interrupts = <3 4>;
interrupt-parent = <&plic0>;
clock-frequency = <15000000>;
};
serial0: serial@f0300000 {
compatible = "andestech,uart16550", "ns16550a";
reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
interrupts = <9 4>;
interrupt-parent = <&plic0>;
clock-frequency = <19660800>;
current-speed = <38400>;
reg-shift = <2>;
reg-offset = <32>;
reg-io-width = <4>;
no-loopback-test = <1>;
};
smu: smu@f0100000 {
compatible = "andestech,atcsmu";
reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
};
};
```

View File

@ -1,38 +0,0 @@
Ariane FPGA SoC Platform
========================
Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit
RISC-V instruction set. The Ariane FPGA development platform is based on FPGA
SoC (which currently supports only Genesys 2 board) and is capable of running
Linux.
The FPGA SoC currently contains the following peripherals:
- DDR3 memory controller
- SPI controller to connect to an SDCard
- Ethernet controller
- JTAG port (see debugging section below)
- Bootrom containing zero stage bootloader and device tree.
To build platform specific library and firmwares, provide the
*PLATFORM=fpga/ariane* parameter to the top level `make` command.
Platform Options
----------------
The *Ariane FPGA* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
```
make PLATFORM=fpga/ariane FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform
----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
directly boot into Linux directly after powered on.

View File

@ -1,33 +0,0 @@
OpenPiton FPGA SoC Platform
========================
OpenPiton is the world's first open source, general purpose, multithreaded
manycore processor. It is a tiled manycore framework scalable from one to
1/2 billion cores. Currently, OpenPiton supports the 64bit Ariane RISC-V
processor from ETH Zurich. To this end, Ariane has been equipped with a
different L1 cache subsystem that follows a write-through protocol and that has
support for cache invalidations and atomics.
To build platform specific library and firmwares, provide the *PLATFORM=generic*
parameter to the top level `make` command.
Platform Options
----------------
The *OpenPiton* platform does not have any platform-specific options.
Building Ariane FPGA Platform
-----------------------------
**Linux Kernel Payload**
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Booting Ariane FPGA Platform
----------------------------
**Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, Ariane will
directly boot into Linux directly after powered on.

View File

@ -1,59 +0,0 @@
Generic Platform
================
The **Generic** platform is a flattened device tree (FDT) based platform
where all platform specific functionality is provided based on FDT passed
by previous booting stage. The **Generic** platform allows us to use same
OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
boards.
By default, the generic FDT platform makes following assumptions:
1. platform features are default
2. platform stack size is default
3. platform has no quirks or work-arounds
The above assumptions (except 1) can be overridden by adding special platform
callbacks which will be called based on FDT root node compatible string.
Users of the generic FDT platform will have to ensure that:
1. Various FDT based drivers under lib/utils directory are upto date
based on their platform requirements
2. The FDT passed by previous booting stage has DT compatible strings and
DT properties in sync with the FDT based drivers under lib/utils directory
3. The FDT must have "stdout-path" DT property in the "/chosen" DT node when
a platform has multiple serial ports or consoles
4. On multi-HART platform, the FDT must have a DT node for IPI device and
lib/utils/ipi directory must have corresponding FDT based IPI driver
5. The FDT must have a DT node for timer device and lib/utils/timer directory
must have corresponding FDT based timer driver
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The *Generic* platform does not have any platform-specific options.
RISC-V Platforms Using Generic Platform
---------------------------------------
* **Andes AE350 Platform** (*[andes-ae350.md]*)
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Renesas RZ/Five SoC** (*[renesas-rzfive.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
* **Spike** (*[spike.md]*)
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
* **OpenPiton FPGA SoC** (*[fpga-openpiton.md]*)
[andes-ae350.md]: andes-ae350.md
[qemu_virt.md]: qemu_virt.md
[renesas-rzfive.md]: renesas-rzfive.md
[shakti_cclass.md]: shakti_cclass.md
[sifive_fu540.md]: sifive_fu540.md
[spike.md]: spike.md
[thead-c9xx.md]: thead-c9xx.md
[fpga-openpiton.md]: fpga-openpiton.md

View File

@ -1,22 +0,0 @@
Nuclei UX600 Platform
=====================
The **Nuclei UX600** is a 64-bit RISC-V Core which is capable of running Linux.
> Nuclei UX600: single core, pipeline as single-issue and 6~9 variable stages, in-order dispatch and out-of-order write-back, running up to >1.2GHz
To build the platform-specific library and firmware images, provide the
*PLATFORM=nuclei/ux600* parameter to the top level `make` command.
Platform Options
----------------
The *Nuclei UX600* platform does not have any platform-specific options.
Building Nuclei UX600 Platform
------------------------------
```
make PLATFORM=nuclei/ux600 clean all
```

View File

@ -1,56 +1,30 @@
OpenSBI Supported Platforms OpenSBI Supported Platforms
=========================== ===========================
OpenSBI currently supports the following virtual and hardware platforms: OpenSBI currently supports the following virtual and hardware platforms.
* **Generic**: Flattened device tree (FDT) based platform where platform * **QEMU RISC-V Virt Machine**: Platform support for QEMU *virt* virtual RISC-V
specific functionality is provided based on the FDT passed by previous machine. This virtual machine is intended for RISC-V software development and
booting stage. More details on this platform can be found in the file test. More details on this platform can be found in the file *[qemu_virt.md]*.
*[generic.md]*.
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual * **QEMU SiFive Unleashed Machine**: Platform support for the *sifive_u* QEMU
RISC-V machine. This virtual machine is intended for RISC-V software virtual RISC-V machine. This is an emulation machine of the HiFive Unleashed
development and tests. More details on this platform can be found in the board by SiFive. More details on this platform can be found in the file
file *[qemu_virt.md]*. *[qemu_sifive_u.md]*.
* **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the * **SiFive FU540 SoC**: Platform support for SiFive FU540 SoC used on the
HiFive Unleashed board, as well as the *sifive_u* QEMU virtual RISC-V HiFive Unleashed board. This platform is very similar to the *QEMU sifive_u*
machine. More details on this platform can be found in the file platform. More details on this platform can be found in the file
*[sifive_fu540.md]*. *[sifive_fu540.md]*.
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on * **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
boards such as the Kendryte KD233 or the Sipeed MAIX Dock. boards such as the Kendryte KD233 and Sipeed MAIX Dock boards.
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
Genesys 2 board. More details on this platform can be found in the file
*[fpga-ariane.md]*.
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
details on this platform can be found in the file *[andes-ae350.md]*.
* **Spike**: Platform support for the Spike emulator. More
details on this platform can be found in the file *[spike.md]*.
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
processor based SOCs. More details on this platform can be found in the
file *[shakti_cclass.md]*.
* **Renesas RZ/Five SoC**: Platform support for Renesas RZ/Five (R9A07G043F) SoC
used on the Renesas RZ/Five SMARC EVK board. More details on this platform can
be found in the file *[renesas-rzfive.md]*.
The code for these supported platforms can be used as example to implement The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *objects.mk*, template files for implementing support for a new platform. The *object.mk*,
*Kconfig*, *configs/defconfig* and *platform.c* template files provides enough *config.mk* and *platform.c* template files provides enough comments to facilitate
comments to facilitate the implementation. the implementation.
[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md [qemu_virt.md]: qemu_virt.md
[sifive_fu540.md]: sifive_fu540.md [qemu_sifive_u.md]: qemu_sifive_u.md
[fpga-ariane.md]: fpga-ariane.md
[andes-ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md
[shakti_cclass.md]: shakti_cclass.md
[renesas-rzfive.md]: renesas-rzfive.md

View File

@ -0,0 +1,52 @@
QEMU SiFive Unleashed Machine Platform
======================================
The **QEMU SiFive Unleashed Machine** is an emulation of the SiFive Unleashed
platform.
To build this platform specific library and firmwares, provide the
*PLATFORM=qemu/sifive_u* parameter to the top level `make` command line.
Platform Options
----------------
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
options.
Executing on QEMU RISC-V 64bit
------------------------------
**No Payload Case**
Build:
```
make PLATFORM=qemu/virt
```
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
```
**U-Boot as a Payload**
Note: the command line examples here assume that U-Boot was compiled using
the `qemu-riscv64_smode_defconfig` configuration.
Build:
```
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_payload.elf
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -display none -serial stdio \
-kernel build/platform/qemu/sifive_u/firmware/fw_jump.elf \
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
```

View File

@ -1,34 +1,34 @@
QEMU RISC-V Virt Machine Platform QEMU RISC-V Virt Machine Platform
================================= =================================
The **QEMU RISC-V Virt Machine** is a virtual platform created for RISC-V The **QEMU RISC-V Virt Machine** is virtual platform created for RISC-V
software development and testing. It is also referred to as software development and testing. It is also referred as
*QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network, *QEMU RISC-V VirtIO machine* because it uses VirtIO devices for network,
storage, and other types of IO. storage, and other types of IO.
To build the platform-specific library and firmware images, provide the To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level `make` command. *PLATFORM=qemu/virt* parameter to the top level `make` command.
Platform Options Platform Options
---------------- ----------------
The *QEMU RISC-V Virt Machine* platform does not have any platform-specific The *QEMU RISC-V Virt Machine* platform does not have any platform specific
options. options.
Execution on QEMU RISC-V 64-bit Execution on QEMU RISC-V 64bit
------------------------------- ------------------------------
**No Payload Case** **No Payload Case**
Build: Build:
``` ```
make PLATFORM=generic make PLATFORM=qemu/virt
``` ```
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -nographic \ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-bios build/platform/generic/firmware/fw_payload.bin -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
**U-Boot Payload** **U-Boot Payload**
@ -38,143 +38,46 @@ the `qemu-riscv64_smode_defconfig` configuration.
Build: Build:
``` ```
make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
``` ```
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -nographic \ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-bios build/platform/generic/firmware/fw_payload.elf -kernel build/platform/qemu/virt/firmware/fw_payload.elf
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -nographic \ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-bios build/platform/generic/firmware/fw_jump.bin \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-kernel <uboot_build_directory>/u-boot.bin -device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000
``` ```
**Linux Kernel Payload** **Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using Note: We assume that Linux kernel is compiled using
*arch/riscv/configs/defconfig*. The kernel must be a flattened image (a file *arch/riscv/configs/defconfig*.
called `Image`) rather than an ELF (`vmlinux`).
Example of building a Linux kernel:
```
make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux- Image
```
Build: Build:
``` ```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
``` ```
Run: Run:
``` ```
qemu-system-riscv64 -M virt -m 256M -nographic \ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-bios build/platform/generic/firmware/fw_payload.elf \ -kernel build/platform/qemu/virt/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \ -device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0" -append "root=/dev/vda rw console=ttyS0"
``` ```
or or
``` ```
qemu-system-riscv64 -M virt -m 256M -nographic \ qemu-system-riscv64 -M virt -m 256M -display none -serial stdio \
-bios build/platform/generic/firmware/fw_jump.bin \ -kernel build/platform/qemu/virt/firmware/fw_jump.elf \
-kernel <linux_build_directory>/arch/riscv/boot/Image \ -device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \ -drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \ -device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0" -append "root=/dev/vda rw console=ttyS0"
``` ```
Execution on QEMU RISC-V 32-bit
-------------------------------
**No Payload Case**
Build:
```
make PLATFORM=generic PLATFORM_RISCV_XLEN=32
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin
```
**U-Boot Payload**
Note: the command line examples here assume that U-Boot was compiled using
the `qemu-riscv32_smode_defconfig` configuration.
Build:
```
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.elf
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <uboot_build_directory>/u-boot.bin
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/rv32_defconfig*.
Build:
```
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.elf \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
or
```
qemu-system-riscv32 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <linux_build_directory>/arch/riscv/boot/Image \
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
Debugging with GDB
------------------
In a first console start OpenSBI with QEMU:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin \
-gdb tcp::1234 \
-S
```
Parameter *-gdb tcp::1234* specifies 1234 as the debug port.
Parameter *-S* lets QEMU wait at the first instruction.
In a second console start GDB:
```
gdb build/platform/generic/firmware/fw_payload.elf \
-ex 'target remote localhost:1234'
```

View File

@ -1,160 +0,0 @@
Renesas RZ/Five SoC (R9A07G043F) Platform
=========================================
The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
- Memory controller for DDR4-1600 / DDR3L-1333 with 16 bits
- System RAM (RAM of 128 Kbytes (ECC))
- SPI Multi I/O Bus Controller 1ch
- SD Card Host Interface/Multimedia Card Interface (SD/MMC) 2ch
- Serial Sound Interface (SSI) 4ch
- Sampling Rate Converter (SRC) 1ch
- USB2.0 host/function interface 2ch (ch0: Host-Function ch1: Host only)
- Gigabit Ethernet Interface (GbE) 2ch
- Controller Area Network Interface (CAN) 2ch (CAN-FD ISO 11898-1 (CD2014) compliant)
- Multi-function Timer Pulse Unit 3 (MTU3a) 9 ch (16 bits × 8 channels, 32 bits × 1 channel)
- Port Output Enable 3 (POE3)
- Watchdog Timer (WDT) 1ch
- General Timer (GTM) 3ch (32bits)
- I2C Bus Interface (I2C) 4ch
- Serial Communication Interface with FIFO (SCIFA) 5ch
- Serial Communication Interface (SCI) 2ch
- Renesas Serial Peripheral Interface (RSPI) 3ch
- A/D Converter (ADC) 2ch
making it ideal for applications such as entry-class social infrastructure
gateway control and industrial gateway control. More details can be found at
below link [0].
[0] https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level make command.
Platform Options
----------------
The Renesas RZ/Five platform does not have any platform-specific options.
Building Renesas RZ/Five Platform
---------------------------------
```
make PLATFORM=generic
```
DTS Example: (RZ/Five AX45MP)
-----------------------------
```
compatible = "renesas,r9a07g043f01", "renesas,r9a07g043";
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <12000000>;
cpu0: cpu@0 {
compatible = "andestech,ax45mp", "riscv";
device_type = "cpu";
reg = <0x0>;
status = "okay";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
i-cache-size = <0x8000>;
i-cache-line-size = <0x40>;
d-cache-size = <0x8000>;
d-cache-line-size = <0x40>;
clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
ranges;
scif0: serial@1004b800 {
compatible = "renesas,scif-r9a07g043",
"renesas,scif-r9a07g044";
reg = <0 0x1004b800 0 0x400>;
interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
<414 IRQ_TYPE_LEVEL_HIGH>,
<415 IRQ_TYPE_LEVEL_HIGH>,
<413 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>,
<416 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi",
"bri", "dri", "tei";
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
clock-names = "fck";
power-domains = <&cpg>;
resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
status = "disabled";
};
cpg: clock-controller@11010000 {
compatible = "renesas,r9a07g043-cpg";
reg = <0 0x11010000 0 0x10000>;
clocks = <&extal_clk>;
clock-names = "extal";
#clock-cells = <2>;
#reset-cells = <1>;
#power-domain-cells = <0>;
};
sysc: system-controller@11020000 {
compatible = "renesas,r9a07g043-sysc";
reg = <0 0x11020000 0 0x10000>;
status = "disabled";
};
pinctrl: pinctrl@11030000 {
compatible = "renesas,r9a07g043-pinctrl";
reg = <0 0x11030000 0 0x10000>;
gpio-controller;
#gpio-cells = <2>;
#interrupt-cells = <2>;
interrupt-controller;
gpio-ranges = <&pinctrl 0 0 152>;
clocks = <&cpg CPG_MOD R9A07G043_GPIO_HCLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_GPIO_RSTN>,
<&cpg R9A07G043_GPIO_PORT_RESETN>,
<&cpg R9A07G043_GPIO_SPARE_RESETN>;
};
plmt0: plmt0@110c0000 {
compatible = "andestech,plmt0", "riscv,plmt0";
reg = <0x0 0x110c0000 0x0 0x10000>;
interrupts-extended = <&cpu0_intc 7>;
};
plic: interrupt-controller@12c00000 {
compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
#interrupt-cells = <2>;
#address-cells = <0>;
riscv,ndev = <511>;
interrupt-controller;
reg = <0x0 0x12c00000 0x0 0x400000>;
clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
power-domains = <&cpg>;
resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
};
plicsw: interrupt-controller@13000000 {
compatible = "andestech,plicsw";
reg = <0x0 0x13000000 0x0 0x400000>;
interrupts-extended = <&cpu0_intc 3>;
interrupt-controller;
#address-cells = <2>;
#interrupt-cells = <2>;
};
};
```

View File

@ -1,33 +0,0 @@
Shakti C-class SoC Platform
===========================
C-Class is a member of the SHAKTI family of processors from
Indian Institute of Technology - Madras (IIT-M).
It is an extremely configurable and commercial-grade 5-stage
in-order core supporting the standard RV64GCSUN ISA extensions.
For more details, refer:
* https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md
* https://c-class.readthedocs.io/en/latest
* https://shakti.org.in
Platform Options
----------------
The *Shakti C-class SoC* platform does not have any platform-specific
options.
Building Shakti C-class Platform
--------------------------------
**Linux Kernel Payload**
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<shakti.dtb path>
```
**Test Payload**
```
make PLATFORM=generic FW_FDT_PATH=<shakti.dtb path>
```

View File

@ -1,74 +1,105 @@
SiFive FU540 SoC Platform SiFive FU540 SoC Platform
========================= ==========================
The FU540-C000 is the worlds first 4+1 64-bit RISC-V SoC from SiFive. The FU540-C000 is the worlds first 4+1 64-bit RISC-V SoC from SiFive.
The HiFive Unleashed development platform is based on FU540-C000 and capable The HiFive Unleashed development platform is based on FU540-C000 and capable
of running Linux. of running Linux.
With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
OpenSBI image built for the real hardware as well.
To build platform specific library and firmwares, provide the To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level `make` command. *PLATFORM=sifive/fu540* parameter to the top level `make` command.
Platform Options Platform Options
---------------- ----------------
The *SiFive FU540 SoC* platform does not have any platform-specific As hart0 in the FU540 doesn't have an MMU, only harts 1-4 boot by default.
options. A hart mask i.e. *FU540_ENABLED_HART_MASK* compile time option is provided to
select any other hart for booting. Please keep in mind that this is not
platform wide option. It can only be specified for FU540 platform in following way.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=Image FU540_ENABLED_HART_MASK=0x02
```
This will let the board boot only hart1 instead of default 1-4.
Building SiFive Fu540 Platform Building SiFive Fu540 Platform
------------------------------ -----------------------------
In order to boot SMP Linux in U-Boot, Linux v5.1 (or higher) and latest As of this writing, the required Linux kernel and U-Boot patches are not
U-Boot v2020.01 (or higher) should be used. accepted in mainline. Please follow the below instructions to cherry-pick
them into your repository.
[U-Boot patches](../firmware/payload_uboot.md)
[Linux kernel patches](../firmware/payload_linux.md)
**Linux Kernel Payload** **Linux Kernel Payload**
The HiFive Unleashed device tree(DT) is merged in Linux v5.2 release. This
DT (device tree) is not backward compatible with the DT passed from FSBL.
To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
(or higher) should be used to build SiFive FU540 OpenSBI binaries by using
the compile time option *FW_FDT_PATH*.
``` ```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
``` ```
**U-Boot Payload** **U-Boot Payload**
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to The command-line example here assumes that U-Boot was compiled using sifive_fu540_defconfig configuration.
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
With SMP support enabled in U-Boot:
``` ```
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
```
Without SMP support enabled in U-Boot:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FU540_ENABLED_HART_MASK=0x02
```
**U-Boot & Linux Kernel as a single payload**
A single monolithic image containing both U-Boot & Linux can also be used if network boot setup is
not available.
1. Generate the uImage from Linux Image.
```
mkimage -A riscv -O linux -T kernel -C none -a 0x80200000 -e 0x80200000 -n Linux -d \
<linux_build_directory>arch/riscv/boot/Image \
<linux_build_directory>/arch/riscv/boot/uImage
```
2. Create a temporary image with u-boot.bin as the first payload. The command-line
example here assumes that U-Boot was compiled using sifive_fu540_defconfig
configuration.
```
dd if=~/workspace/u-boot-riscv/u-boot.bin of=/tmp/temp.bin bs=1M
```
3. Append the Linux Kernel image generated in step 1.
```
dd if=<linux_build_directory>/arch/riscv/boot/uImage of=/tmp/temp.bin bs=1M seek=4
```
4. Compile OpenSBI with temp.bin (generated in step 3) as payload.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
``` ```
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
Please refer to the detailed U-Boot booting guide available at [U-Boot].
Flashing the OpenSBI firmware binary to storage media: Flashing the OpenSBI firmware binary to storage media:
------------------------------------------------------ -----------------------------------------------------
The first stage boot loader ([FSBL]) expects the storage media to have a GPT The first stage boot loader([FSBL](https://github.com/sifive/freedom-u540-c000-bootloader))
partition table. It tries to look for a partition with following GUID to load expects the storage media to have a GPT partition table. It tries to look for a
the next stage boot loader (OpenSBI in this case). partition with following GUID to load the next stage boot loader (OpenSBI in this case).
``` ```
2E54B353-1271-4842-806F-E436D6AF6985 2E54B353-1271-4842-806F-E436D6AF6985
``` ```
That's why the generated firmware binary in above steps should be copied to That's why the generated firmware binary in above steps should be copied to the
the partition of the sdcard with above GUID. partition of the sdcard with above GUID.
``` ```
dd if=build/platform/generic/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024 dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
``` ```
In my case, it is the first partition is **disk2s1** that has been formatted In my case, it is the first partition is **disk2s1** that has been formatted with the
with the above specified GUID. above specified GUID.
In case of a brand new sdcard, it should be formatted with below partition In case of a brand new sdcard, it should be formatted with below partition
tables as described here. tables as described here.
@ -77,7 +108,7 @@ tables as described here.
sgdisk --clear \ sgdisk --clear \
--new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \ --new=1:2048:67583 --change-name=1:bootloader --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \
--new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \ --new=2:264192: --change-name=2:root --typecode=2:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
${DISK} $(DISK)
``` ```
Booting SiFive Fu540 Platform Booting SiFive Fu540 Platform
@ -85,55 +116,67 @@ Booting SiFive Fu540 Platform
**Linux Kernel Payload** **Linux Kernel Payload**
As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive As Linux kernel image is embedded in the OpenSBI firmware binary, HiFive Unleashed will directly
Unleashed will directly boot into Linux directly after powered on. boot into Linux directly after powered on.
**U-Boot Payload** **U-Boot Payload**
As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot As U-Boot image is used as payload, HiFive Unleashed will boot into a U-Boot prompt.
prompt. U-Boot tftp boot method can be used to load kernel image in U-Boot U-Boot tftp boot method can be used to load kernel image in U-Boot prompt.
prompt. Here are the steps do a tftpboot. Here are the steps do a tftpboot.
1. Set the mac address of the board.
```
setenv ethaddr <mac address of the board>
```
2. Set the ip address of the board.
1. Set the ip address of the board.
``` ```
setenv ipaddr <ipaddr of the board> setenv ipaddr <ipaddr of the board>
``` ```
2. Set the tftpboot server IP. 3. Set the tftpboot server IP.
``` ```
setenv serverip <ipaddr of the tftp server> setenv serverip <ipaddr of the tftp server>
``` ```
3. Set the network gateway address. 4. Set the network gateway address.
``` ```
setenv gatewayip <ipaddress of the network gateway> setenv gatewayip <ipaddress of the network gateway>
``` ```
4. Load the Linux kernel image from the tftp server. 5. Load the Linux kernel image from the tftp server.
``` ```
tftpboot ${kernel_addr_r} <Image path in tftpboot directory> tftpboot ${kernel_addr_r} /sifive/fu540/uImage
``` ```
5. Load the ramdisk image from the tftp server. This is only required if
ramdisk is loaded from tftp server. This step is optional, if rootfs is 6. Load the ramdisk image from the tftp server. This is only required if ramdisk
already part of the kernel or loaded from an external storage by kernel. is loaded from tftp server. This step is optional, if rootfs is already part
of the kernel or loaded from an external storage by kernel.
``` ```
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory> tftpboot ${ramdisk_addr_r} /sifive/fu540/uRamdisk
```
6. Load the pre-compiled device tree via tftpboot.
```
tftpboot ${fdt_addr_r} <hifive-unleashed-a00.dtb path in tftpboot directory>
``` ```
7. Set the boot command-line arguments. 7. Set the boot command-line arguments.
``` ```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi" setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
``` ```
(Note: root partition should point to
** /dev/ram ** - If a ramdisk is used N.B. root partition should point to
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition ** /dev/ram ** - If a ramdisk is used
of sdcard) ** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition of sdcard
8. Now boot into Linux. 8. Now boot into Linux.
``` ```
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
or
(If ramdisk is not loaded from network) ```
booti ${kernel_addr_r} - ${fdt_addr_r} or (if ramdisk is not loaded from network)
```
bootm ${kernel_addr_r} - ${fdtcontroladdr}
``` ```
**U-Boot & Linux Kernel as a single payload** **U-Boot & Linux Kernel as a single payload**
@ -141,56 +184,19 @@ booti ${kernel_addr_r} - ${fdt_addr_r}
At U-Boot prompt execute the following boot command to boot Linux. At U-Boot prompt execute the following boot command to boot Linux.
``` ```
booti ${kernel_addr_r} - ${fdt_addr_r} bootm ${kernel_addr_r} - ${fdtcontroladdr}
``` ```
Booting SiFive Fu540 Platform with Microsemi Expansion board
------------------------------------------------------------
QEMU Specific Instructions Until the Linux kernel has in-tree support for device trees and mainline u-boot
-------------------------- is fully supported on the HiFive Unleashed you can follow these steps to boot
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the Linux with the Microsemi expansion board. This method should not be copied on
same instructions above, with the exception of not passing FW_FDT_PATH. future boards and is considered a temporary solution until we can use a more
standardised boot flow.
This is because QEMU generates a device tree blob on the fly based on the
command line parameters, and it's compatible with the one used in the upstream
Linux kernel.
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
reason above, we need to switch the U-Boot sifive_unleashed_defconfig
configuration from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that
U-Boot uses the DTB generated by QEMU, and u-boot.bin should be used as the
payload image, like:
To boot the Linux kernel with a device tree that has support for the Microsemi
Expansion board you can include the following line when compiling the firmware:
``` ```
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin FW_PAYLOAD_FDT="HiFiveUnleashed-MicroSemi-Expansion.dtb"
``` ```
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
hence a build error will be seen after you switch to **CONFIG_OF_PRIOR_STAGE**.
```
./tools/mkimage: Can't open arch/riscv/dts/hifive-unleashed-a00.dtb: No such file or directory
./tools/mkimage: failed to build FIT
Makefile:1402: recipe for target 'u-boot.img' failed
make: *** [u-boot.img] Error 1
```
The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel <uboot_build_dir>/u-boot.bin
```
While the real hardware operates at the 64-bit mode, it's possible for QEMU to
test the 32-bit OpenSBI firmware. This can be helpful for testing 32-bit SiFive
specific drivers.
[U-Boot]: https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst
[FSBL]: https://github.com/sifive/freedom-u540-c000-bootloader

View File

@ -1,100 +0,0 @@
Spike Simulator Platform
========================
The **Spike** is a RISC-V ISA simulator which implements a functional model
of one or more RISC-V harts. The **Spike** compatible virtual platform is
also available on QEMU. In fact, we can use same OpenSBI firmware binaries
on **Spike** simulator and QEMU Spike machine.
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The *Spike* platform does not have any platform-specific options.
Execution on Spike Simulator
----------------------------
**No Payload Case**
Build:
```
make PLATFORM=generic
```
Run:
```
spike build/platform/generic/firmware/fw_payload.elf
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*.
Build:
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
spike -m256 \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_payload.elf
```
or
```
spike -m256 \
--kernel <linux_build_directory>/arch/riscv/boot/Image \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_jump.elf
```
Execution on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**
Build:
```
make PLATFORM=generic
```
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.elf
```
**Linux Kernel Payload**
Note: We assume that the Linux kernel is compiled using
*arch/riscv/configs/defconfig*.
Build:
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
```
Run:
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.elf \
-initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
```
or
```
qemu-system-riscv64 -M spike -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.elf \
-kernel <linux_build_directory>/arch/riscv/boot/Image \
-initrd <path_to_cpio_ramdisk> \
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
```

View File

@ -1,27 +0,0 @@
T-HEAD C9xx Series Processors
=============================
The C9xx series processors are high-performance RISC-V architecture
multi-core processors with AI vector acceleration engine.
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The T-HEAD C9xx does not have any platform-specific compile options
because it uses generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic make
```
Here is the simplest boot flow for a fpga prototype:
(Jtag gdbinit) -> (zsb) -> (opensbi) -> (linux)
For more details, refer:
[zero stage boot](https://github.com/c-sky/zero_stage_boot)

View File

@ -1,15 +1,15 @@
OpenSBI Platform Support Guideline OpenSBI Platform Support Guideline
================================== ==================================
The OpenSBI platform support allows an implementation to define a set of OpenSBI platform support allows an implementation to define a set of platform
platform-specific hooks (hardware manipulation functions) in the form of a specific hooks (hardware manipulation functions) in the form of a
*struct sbi_platform* data structure instance. This instance is required by *struct sbi_platform* data structure instance. This instance is required by
the platform-independent *libsbi.a* to execute platform-specific operations. platform independent *libsbi.a* to execute platform specific operations.
Each of the reference platform supports provided by OpenSBI defines an instance Each of the reference platform support provided by OpenSBI define an instance
of the *struct sbi_platform* data structure. For each supported platform, of the *struct sbi_platform* data structure. For each supported platform,
*libplatsbi.a* integrates this instance with *libsbi.a* to create a *libplatsbi.a* integrates this instance with *libsbi.a* to create a platform
platform-specific OpenSBI static library. This library is installed specific OpenSBI static library. This library is installed
in *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a* in *<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
OpenSBI also provides implementation examples of bootable runtime firmwares for OpenSBI also provides implementation examples of bootable runtime firmwares for
@ -17,27 +17,26 @@ the supported platforms. These firmwares are linked against *libplatsbi.a*.
Firmware binaries are installed in Firmware binaries are installed in
*<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be *<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be
used as executable runtime firmwares on the supported platforms as a replacement used as executable runtime firmwares on the supported platforms as a replacement
for the legacy *riscv-pk* boot loader (BBL). for the legacy *riskv-pk* boot loader (BBL).
A complete doxygen-style documentation of *struct sbi_platform* and related A complete doxygen-style documentation of *struct sbi_platform* and related
APIs is available in the file *include/sbi/sbi_platform.h*. APIs is available in the file *include/sbi/sbi_platform.h*.
Adding support for a new platform Adding a new platform support
--------------------------------- -----------------------------
Support for a new platform named *&lt;xyz&gt;* can be added as follows: Support for a new platform named *<xyz>* can be added as follows:
1. Create a directory named *&lt;xyz&gt;* under the *platform/* directory. 1. Create a directory named *<xyz>* under *platform/* directory
2. Create platform configuration files named *Kconfig* and *configs/defconfig* 2. Create a platform configuration file named *config.mk* under
under the *platform/&lt;xyz&gt;/* directory. These configuration files will *platform/<xyz>/* directory. This configuration file will provide
provide the build time configuration for the sources to be compiled. compiler flags, select common drivers, and select firmware options
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the platform 3. Create *platform/<xyz>/objects.mk* file for listing the platform
object files to be compiled. This file also provides platform-specific specific object files to be compiled
compiler flags, and select firmware options. 4. Create *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
4. Create a *platform/&lt;xyz&gt;/platform.c* file providing a instance
*struct sbi_platform* instance.
A platform support code template is available under the *platform/template* A template platform support code is available under the *platform/template*
directory. Copying this directory and its content as a new directory named directory. Copying this directory and its content as a new directory named
*&lt;xyz&gt;* under the *platform/* directory will create all the files *<xyz>* under the *platform/* directory will create all the files mentioned
mentioned above. above.

View File

@ -1,48 +0,0 @@
OpenSBI Platform Requirements
=============================
The RISC-V platform requirements for OpenSBI can change over time
with advances in RISC-V specifications and ecosystem.
To handle this, we have two types of RISC-V platform requirements:
1. **Base platform requirements** which apply to all OpenSBI releases
2. **Release specific platform requirements** which apply to a OpenSBI
release and later releases
Currently, we don't have any **Release specific platform requirements**,
but such platform requirements will be added in future.
Base Platform Requirements
--------------------------
The base RISC-V platform requirements for OpenSBI are as follows:
1. At least rv32ima_zicsr or rv64ima_zicsr required on all HARTs
* Users may restrict the usage of atomic instructions to lr/sc
via rv32im_zalrsc_zicsr or rv64im_zalrsc_zicsr if preferred
2. At least one HART should have S-mode support because:
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
* OpenSBI implements SBI calls for S-mode software
3. The MTVEC CSR on all HARTs must support direct mode
4. The PMP CSRs are optional. If PMP CSRs are not implemented then
OpenSBI cannot protect M-mode firmware and secured memory regions
5. The TIME CSR is optional. If TIME CSR is not implemented in
hardware then a 64-bit MMIO counter is required to track time
and emulate TIME CSR
6. Hardware support for injecting M-mode software interrupts on
a multi-HART platform
The RISC-V extensions not covered by rv32ima_zicsr or rv64ima_zicsr are optional
for OpenSBI. Although, OpenSBI will detect and handle some of these
optional RISC-V extensions at runtime.
The optional RISC-V extensions handled by OpenSBI at runtime are:
* D-extension: Double precision floating point
* F-extension: Single precision floating point
* H-extension: Hypervisor

View File

@ -1,209 +0,0 @@
OpenSBI SBI PMU extension support
==================================
SBI PMU extension supports allow supervisor software to configure/start/stop
any performance counter at anytime. Thus, a user can leverage full
capability of performance analysis tools such as perf if SBI PMU extension is
enabled. The OpenSBI implementation makes the following assumptions about the
hardware platform.
* The platform must provide information about PMU event to counter mapping
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
not be enabled.
* The platforms should provide information about the PMU event selector values
that should be encoded in the expected value of MHPMEVENTx while configuring
MHPMCOUNTERx for that specific event. This can be done via a device tree or
platform specific hooks. The exact value to be written to he MHPMEVENTx is
completely depends on platform. Generic platform writes the zero-extended event_idx
as the expected value for hardware cache/generic events as suggested by the SBI
specification.
SBI PMU Device Tree Bindings
----------------------------
Platforms may choose to describe PMU event selector and event to counter mapping
values via device tree. The following sections describe the PMU DT node
bindings in details.
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
This DT property must have the value **riscv,pmu**.
* **riscv,event-to-mhpmevent**(Optional) - It represents an ONE-to-ONE mapping
between a PMU event and the event selector value that platform expects to be
written to the MHPMEVENTx CSR for that event. The mapping is encoded in a
table format where each row represents an event. The first column represent the
event idx where the 2nd & 3rd column represent the event selector value that
should be encoded in the expected value to be written in MHPMEVENTx.
This property shouldn't encode any raw hardware event.
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
that can be used to monitor these range of events. The information is encoded in
a table format where each row represents a certain range of events and
corresponding counters. The first column represents starting of the pmu event id
and 2nd column represents the end of the pmu event id. The third column
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
riscv,event-to-mhpmevent is present. Otherwise, it can be omitted. This property
shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
a bitmap format that can be used to monitor that raw event. The encoding of the
raw events are platform specific. The information is encoded in a table format
where each row represents the specific raw event(s). The first column is a 64bit
match value where the invariant bits of range of events are set. The second
column is a 64 bit mask that will have all the variant bits of the range of
events cleared. All other bits should be set in the mask.
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
can monitor these set of event(s).
If a platform directly encodes each raw PMU event as a unique ID, the value of
select_mask must be 0xffffffff_ffffffff.
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
### Example 1
```
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>;
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>;
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-15 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0xf 0xffffffff 0xffffff0f 0x00000ff0>;
};
```
### Example 2
```
/*
* For HiFive Unmatched board. The encodings can be found here
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
* This example also binds standard SBI PMU hardware id's to U74 PMU event codes, U74 uses bitfield for
* events encoding, so several U74 events can be bound to single perf id.
* See SBI PMU hardware id's in include/sbi/sbi_ecall_interface.h
*/
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent =
/* SBI_PMU_HW_CACHE_REFERENCES -> Instruction cache/ITIM busy | Data cache/DTIM busy */
<0x00003 0x00000000 0x1801>,
/* SBI_PMU_HW_CACHE_MISSES -> Instruction cache miss | Data cache miss or memory-mapped I/O access */
<0x00004 0x00000000 0x0302>,
/* SBI_PMU_HW_BRANCH_INSTRUCTIONS -> Conditional branch retired */
<0x00005 0x00000000 0x4000>,
/* SBI_PMU_HW_BRANCH_MISSES -> Branch direction misprediction | Branch/jump target misprediction */
<0x00006 0x00000000 0x6001>,
/* L1D_READ_MISS -> Data cache miss or memory-mapped I/O access */
<0x10001 0x00000000 0x0202>,
/* L1D_WRITE_ACCESS -> Data cache write-back */
<0x10002 0x00000000 0x0402>,
/* L1I_READ_ACCESS -> Instruction cache miss */
<0x10009 0x00000000 0x0102>,
/* LL_READ_MISS -> UTLB miss */
<0x10011 0x00000000 0x2002>,
/* DTLB_READ_MISS -> Data TLB miss */
<0x10019 0x00000000 0x1002>,
/* ITLB_READ_MISS-> Instruction TLB miss */
<0x10021 0x00000000 0x0802>;
riscv,event-to-mhpmcounters = <0x00003 0x00006 0x18>,
<0x10001 0x10002 0x18>,
<0x10009 0x10009 0x18>,
<0x10011 0x10011 0x18>,
<0x10019 0x10019 0x18>,
<0x10021 0x10021 0x18>;
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0x18>,
<0x0 0x1 0xffffffff 0xfff800ff 0x18>,
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
};
```
### Example 3
```
/*
* For Andes 45-series platforms. The encodings can be found in the
* "Machine Performance Monitoring Event Selector" section
* http://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
*/
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent =
<0x1 0x0000 0x10>, /* CPU_CYCLES -> Cycle count */
<0x2 0x0000 0x20>, /* INSTRUCTIONS -> Retired instruction count */
<0x3 0x0000 0x41>, /* CACHE_REFERENCES -> D-Cache access */
<0x4 0x0000 0x51>, /* CACHE_MISSES -> D-Cache miss */
<0x5 0x0000 0x80>, /* BRANCH_INSTRUCTIONS -> Conditional branch instruction count */
<0x6 0x0000 0x02>, /* BRANCH_MISSES -> Misprediction of conditional branches */
<0x10000 0x0000 0x61>, /* L1D_READ_ACCESS -> D-Cache load access */
<0x10001 0x0000 0x71>, /* L1D_READ_MISS -> D-Cache load miss */
<0x10002 0x0000 0x81>, /* L1D_WRITE_ACCESS -> D-Cache store access */
<0x10003 0x0000 0x91>, /* L1D_WRITE_MISS -> D-Cache store miss */
<0x10008 0x0000 0x21>, /* L1I_READ_ACCESS -> I-Cache access */
<0x10009 0x0000 0x31>; /* L1I_READ_MISS -> I-Cache miss */
riscv,event-to-mhpmcounters = <0x1 0x6 0x78>,
<0x10000 0x10003 0x78>,
<0x10008 0x10009 0x78>;
riscv,raw-event-to-mhpmcounters =
<0x0 0x10 0xffffffff 0xffffffff 0x78>, /* Cycle count */
<0x0 0x20 0xffffffff 0xffffffff 0x78>, /* Retired instruction count */
<0x0 0x30 0xffffffff 0xffffffff 0x78>, /* Integer load instruction count */
<0x0 0x40 0xffffffff 0xffffffff 0x78>, /* Integer store instruction count */
<0x0 0x50 0xffffffff 0xffffffff 0x78>, /* Atomic instruction count */
<0x0 0x60 0xffffffff 0xffffffff 0x78>, /* System instruction count */
<0x0 0x70 0xffffffff 0xffffffff 0x78>, /* Integer computational instruction count */
<0x0 0x80 0xffffffff 0xffffffff 0x78>, /* Conditional branch instruction count */
<0x0 0x90 0xffffffff 0xffffffff 0x78>, /* Taken conditional branch instruction count */
<0x0 0xA0 0xffffffff 0xffffffff 0x78>, /* JAL instruction count */
<0x0 0xB0 0xffffffff 0xffffffff 0x78>, /* JALR instruction count */
<0x0 0xC0 0xffffffff 0xffffffff 0x78>, /* Return instruction count */
<0x0 0xD0 0xffffffff 0xffffffff 0x78>, /* Control transfer instruction count */
<0x0 0xE0 0xffffffff 0xffffffff 0x78>, /* EXEC.IT instruction count */
<0x0 0xF0 0xffffffff 0xffffffff 0x78>, /* Integer multiplication instruction count */
<0x0 0x100 0xffffffff 0xffffffff 0x78>, /* Integer division instruction count */
<0x0 0x110 0xffffffff 0xffffffff 0x78>, /* Floating-point load instruction count */
<0x0 0x120 0xffffffff 0xffffffff 0x78>, /* Floating-point store instruction count */
<0x0 0x130 0xffffffff 0xffffffff 0x78>, /* Floating-point addition/subtraction instruction count */
<0x0 0x140 0xffffffff 0xffffffff 0x78>, /* Floating-point multiplication instruction count */
<0x0 0x150 0xffffffff 0xffffffff 0x78>, /* Floating-point fused multiply-add instruction count */
<0x0 0x160 0xffffffff 0xffffffff 0x78>, /* Floating-point division or square-root instruction count */
<0x0 0x170 0xffffffff 0xffffffff 0x78>, /* Other floating-point instruction count */
<0x0 0x180 0xffffffff 0xffffffff 0x78>, /* Integer multiplication and add/sub instruction count */
<0x0 0x190 0xffffffff 0xffffffff 0x78>, /* Retired operation count */
<0x0 0x01 0xffffffff 0xffffffff 0x78>, /* ILM access */
<0x0 0x11 0xffffffff 0xffffffff 0x78>, /* DLM access */
<0x0 0x21 0xffffffff 0xffffffff 0x78>, /* I-Cache access */
<0x0 0x31 0xffffffff 0xffffffff 0x78>, /* I-Cache miss */
<0x0 0x41 0xffffffff 0xffffffff 0x78>, /* D-Cache access */
<0x0 0x51 0xffffffff 0xffffffff 0x78>, /* D-Cache miss */
<0x0 0x61 0xffffffff 0xffffffff 0x78>, /* D-Cache load access */
<0x0 0x71 0xffffffff 0xffffffff 0x78>, /* D-Cache load miss */
<0x0 0x81 0xffffffff 0xffffffff 0x78>, /* D-Cache store access */
<0x0 0x91 0xffffffff 0xffffffff 0x78>, /* D-Cache store miss */
<0x0 0xA1 0xffffffff 0xffffffff 0x78>, /* D-Cache writeback */
<0x0 0xB1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for I-Cache fill data */
<0x0 0xC1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for D-Cache fill data */
<0x0 0xD1 0xffffffff 0xffffffff 0x78>, /* Uncached fetch data access from bus */
<0x0 0xE1 0xffffffff 0xffffffff 0x78>, /* Uncached load data access from bus */
<0x0 0xF1 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached fetch data from bus */
<0x0 0x101 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for uncached load data from bus */
<0x0 0x111 0xffffffff 0xffffffff 0x78>, /* Main ITLB access */
<0x0 0x121 0xffffffff 0xffffffff 0x78>, /* Main ITLB miss */
<0x0 0x131 0xffffffff 0xffffffff 0x78>, /* Main DTLB access */
<0x0 0x141 0xffffffff 0xffffffff 0x78>, /* Main DTLB miss */
<0x0 0x151 0xffffffff 0xffffffff 0x78>, /* Cycles waiting for Main ITLB fill data */
<0x0 0x161 0xffffffff 0xffffffff 0x78>, /* Pipeline stall cycles caused by Main DTLB miss */
<0x0 0x171 0xffffffff 0xffffffff 0x78>, /* Hardware prefetch bus access */
<0x0 0x02 0xffffffff 0xffffffff 0x78>, /* Misprediction of conditional branches */
<0x0 0x12 0xffffffff 0xffffffff 0x78>, /* Misprediction of taken conditional branches */
<0x0 0x22 0xffffffff 0xffffffff 0x78>; /* Misprediction of targets of Return instructions */
};
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -1,127 +0,0 @@
Writing tests for OpenSBI
=========================
SBIUnit
-------
SBIUnit is a set of macros and functions which simplify the test development and
automate the test execution and evaluation. All of the SBIUnit definitions are
in the `include/sbi/sbi_unit_test.h` header file, and implementations are
available in `lib/sbi/tests/sbi_unit_test.c`.
Simple SBIUnit test
-------------------
For instance, we would like to test the following function from
`lib/sbi/sbi_string.c`:
```c
size_t sbi_strlen(const char *str)
{
unsigned long ret = 0;
while (*str != '\0') {
ret++;
str++;
}
return ret;
}
```
which calculates the string length.
Create the file `lib/sbi/tests/sbi_string_test.c` with the following content:
```c
#include <sbi/sbi_unit_test.h>
#include <sbi/sbi_string.h>
static void strlen_test(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, sbi_strlen("Hello"), 5);
SBIUNIT_EXPECT_EQ(test, sbi_strlen("Hell\0o"), 4);
}
static struct sbiunit_test_case string_test_cases[] = {
SBIUNIT_TEST_CASE(strlen_test),
SBIUNIT_END_CASE,
};
SBIUNIT_TEST_SUITE(string_test_suite, string_test_cases);
```
Then, add the corresponding Makefile entries to `lib/sbi/tests/objects.mk`:
```lang-makefile
...
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += string_test_suite
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_string_test.o
```
Now, run `make clean` in order to regenerate the carray-related files.
Recompile OpenSBI with the CONFIG_SBIUNIT option enabled and run it in QEMU.
You will see something like this:
```
# make PLATFORM=generic run
...
# Running SBIUNIT tests #
...
## Running test suite: string_test_suite
[PASSED] strlen_test
1 PASSED / 0 FAILED / 1 TOTAL
```
Now let's try to change this test in the way that it will fail:
```c
- SBIUNIT_EXPECT_EQ(test, sbi_strlen("Hello"), 5);
+ SBIUNIT_EXPECT_EQ(test, sbi_strlen("Hello"), 100);
```
`make all` and `make run` it again:
```
...
# Running SBIUNIT tests #
...
## Running test suite: string_test_suite
[SBIUnit] [.../opensbi/lib/sbi/tests/sbi_string_test.c:6]: strlen_test: Condition "(sbi_strlen("Hello")) == (100)" expected to be true!
[FAILED] strlen_test
0 PASSED / 1 FAILED / 1 TOTAL
```
Covering the static functions / using the static definitions
------------------------------------------------------------
SBIUnit also allows you to test static functions. In order to do so, simply
include your test source in the file you would like to test. Complementing the
example above, just add this to the `lib/sbi/sbi_string.c` file:
```c
#ifdef CONFIG_SBIUNIT
#include "tests/sbi_string_test.c"
#endif
```
In this case you should only add a new carray entry pointing to the test suite
to `lib/sbi/tests/objects.mk`:
```lang-makefile
...
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += string_test_suite
```
You don't have to compile the `sbi_string_test.o` separately, because the
test code will be included into the `sbi_string` object file.
"Mocking" the structures
------------------------
See the example of structure "mocking" in `lib/sbi/tests/sbi_console_test.c`,
where the sbi_console_device structure was mocked to be used in various
console-related functions in order to test them.
API Reference
-------------
All of the `SBIUNIT_EXPECT_*` macros will cause a test case to fail if the
corresponding conditions are not met, however, the execution of a particular
test case will not be stopped.
All of the `SBIUNIT_ASSERT_*` macros will cause a test case to fail and stop
immediately, triggering a panic.

View File

@ -1,28 +0,0 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "Stack Protector Support"
config STACK_PROTECTOR
bool "Stack Protector buffer overflow detection"
default n
help
This option turns on the "stack-protector" compiler feature.
config STACK_PROTECTOR_STRONG
bool "Strong Stack Protector"
depends on STACK_PROTECTOR
default n
help
Turn on the "stack-protector" with "-fstack-protector-strong" option.
Like -fstack-protector but includes additional functions to be
protected.
config STACK_PROTECTOR_ALL
bool "Almighty Stack Protector"
depends on STACK_PROTECTOR
default n
help
Turn on the "stack-protector" with "-fstack-protector-all" option.
Like -fstack-protector except that all functions are protected.
endmenu

View File

@ -7,8 +7,5 @@
# Anup Patel <anup.patel@wdc.com> # Anup Patel <anup.patel@wdc.com>
# #
$(platform_build_dir)/firmware/fw_dynamic.o: $(FW_FDT_PATH) $(build_dir)/$(platform_subdir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)
$(platform_build_dir)/firmware/fw_jump.o: $(FW_FDT_PATH) $(build_dir)/$(platform_subdir)/firmware/fw_payload.o: $(FW_PAYLOAD_FDT_PATH)
$(platform_build_dir)/firmware/fw_payload.o: $(FW_FDT_PATH)
$(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)

View File

@ -9,248 +9,40 @@
#include <sbi/riscv_asm.h> #include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
#include <sbi/riscv_elf.h>
#include <sbi/sbi_platform.h> #include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h> #include <sbi/sbi_trap.h>
#define BOOT_LOTTERY_ACQUIRED 1
#define BOOT_STATUS_BOOT_HART_DONE 1
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
.endm
.macro MOV_5R __d0, __s0, __d1, __s1, __d2, __s2, __d3, __s3, __d4, __s4
add \__d0, \__s0, zero
add \__d1, \__s1, zero
add \__d2, \__s2, zero
add \__d3, \__s3, zero
add \__d4, \__s4, zero
.endm
.macro CLEAR_MDT tmp
#if __riscv_xlen == 32
li \tmp, MSTATUSH_MDT
csrc CSR_MSTATUSH, \tmp
#else
li \tmp, MSTATUS_MDT
csrc CSR_MSTATUS, \tmp
#endif
.endm
.section .entry, "ax", %progbits
.align 3 .align 3
.section .entry, "ax", %progbits
.globl _start .globl _start
.globl _start_warm .globl _start_warm
_start: _start:
/* Find preferred boot HART id */ /*
MOV_3R s0, a0, s1, a1, s2, a2 * Jump to warm-boot if this is not the first core booting,
call fw_boot_hart * that is, for mhartid != 0
add a6, a0, zero */
MOV_3R a0, s0, a1, s1, a2, s2 csrr a6, CSR_MHARTID
li a7, -1 blt zero, a6, _wait_for_boot_hart
beq a6, a7, _try_lottery
/* Jump to relocation wait loop if we are not boot hart */
bne a0, a6, _wait_for_boot_hart
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
lla a6, _boot_lottery
li a7, BOOT_LOTTERY_ACQUIRED
#ifdef __riscv_atomic
amoswap.w a6, a7, (a6)
bnez a6, _wait_for_boot_hart
#elif __riscv_zalrsc
_sc_fail:
lr.w t0, (a6)
sc.w t1, a7, (a6)
bnez t1, _sc_fail
bnez t0, _wait_for_boot_hart
#else
#error "need a or zalrsc"
#endif
/* relocate the global table content */
li t0, FW_TEXT_START /* link start */
lla t1, _fw_start /* load start */
sub t2, t1, t0 /* load offset */
lla t0, __rela_dyn_start
lla t1, __rela_dyn_end
beq t0, t1, _relocate_done
2:
REG_L t5, __SIZEOF_LONG__(t0) /* t5 <-- relocation info:type */
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
bne t5, t3, 3f
REG_L t3, 0(t0)
REG_L t5, (__SIZEOF_LONG__ * 2)(t0) /* t5 <-- addend */
add t5, t5, t2
add t3, t3, t2
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
3:
addi t0, t0, (__SIZEOF_LONG__ * 3)
blt t0, t1, 2b
_relocate_done:
/* At this point we are running from link address */
/* Reset all registers except ra, a0, a1, a2, a3 and a4 for boot HART */
li ra, 0
call _reset_regs
/* Zero-out BSS */ /* Zero-out BSS */
lla s4, _bss_start la a4, _bss_start
lla s5, _bss_end la a5, _bss_end
_bss_zero: _bss_zero:
REG_S zero, (s4) REG_S zero, (a4)
add s4, s4, __SIZEOF_POINTER__ add a4, a4, __SIZEOF_POINTER__
blt s4, s5, _bss_zero blt a4, a5, _bss_zero
/* Setup temporary trap handler */ /* Override pervious arg1 */
lla s4, _start_hang add s0, a0, zero
csrw CSR_MTVEC, s4 add s1, a1, zero
call fw_prev_arg1
/* add t1, a0, zero
* While at this point, trap handling is rudimentary, if a trap happens, add a0, s0, zero
* it will end up in _start_hang which is enough to hook up a GDB. Clear add a1, s1, zero
* MDT to avoid generating a double trap and thus entering a beqz t1, _prev_arg1_override_done
* critical-error state. add a1, t1, zero
*/ _prev_arg1_override_done:
CLEAR_MDT t0
/* Setup temporary stack */
lla s4, _fw_end
li s5, (SBI_SCRATCH_SIZE * 2)
add sp, s4, s5
/* Allow main firmware to save info */
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_save_info
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
#ifdef FW_FDT_PATH
/* Override previous arg1 */
lla a1, fw_fdt_bin
#endif
/*
* Initialize platform
* Note: The a0 to a4 registers passed to the
* firmware are parameters to this function.
*/
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
call fw_platform_init
add t0, a0, zero
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
add a1, t0, zero
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
lla a4, platform
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lwu s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lw s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#endif
/* Setup scratch space for all the HARTs*/
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Setup heap base address */
lla s10, _fw_start
sub s10, tp, s10
add tp, tp, s9
/* Keep a copy of tp */
add t3, tp, zero
/* Counter */
li t2, 1
/* hartid 0 is mandated by ISA */
li t1, 0
_scratch_init:
/*
* The following registers hold values that are computed before
* entering this block, and should remain unchanged.
*
* t3 -> the firmware end address
* s7 -> HART count
* s8 -> HART stack size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
add tp, t3, zero
sub tp, tp, s9
mul a5, s8, t1
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
lla a4, _fw_start
sub a5, t3, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store R/W section's offset in scratch space */
lla a5, _fw_rw_start
sub a5, a5, a4
REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp)
/* Store fw_heap_offset and fw_heap_size in scratch space */
REG_S s10, SBI_SCRATCH_FW_HEAP_OFFSET(tp)
REG_S s9, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next address in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store next mode in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_mode
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store warm_boot address in scratch space */
lla a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
/* Store platform address in scratch space */
lla a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
/* Store hartid-to-scratch function address in scratch space */
lla a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Clear trap_context and tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TRAP_CONTEXT_OFFSET(tp)
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Store firmware options in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
#ifdef FW_OPTIONS
li a0, FW_OPTIONS
#else
call fw_options
#endif
REG_S a0, SBI_SCRATCH_OPTIONS_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store hart index in scratch space */
REG_S t1, SBI_SCRATCH_HARTINDEX_OFFSET(tp)
/* Move to next scratch space */
add t1, t1, t2
blt t1, s7, _scratch_init
/* /*
* Relocate Flatened Device Tree (FDT) * Relocate Flatened Device Tree (FDT)
@ -261,25 +53,45 @@ _scratch_init:
* previous booting stage. * previous booting stage.
*/ */
beqz a1, _fdt_reloc_done beqz a1, _fdt_reloc_done
/* Mask values in a4 */ /* Mask values in a3 and a4 */
li a3, ~0xf
li a4, 0xff li a4, 0xff
/* t1 = destination FDT start address */ /* t1 = destination FDT start address */
MOV_3R s0, a0, s1, a1, s2, a2 add s0, a0, zero
add s1, a1, zero
call fw_next_arg1 call fw_next_arg1
add t1, a0, zero add t1, a0, zero
MOV_3R a0, s0, a1, s1, a2, s2 add a0, s0, zero
add a1, s1, zero
beqz t1, _fdt_reloc_done beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done and t1, t1, a3
/* t0 = source FDT start address */ /* t0 = source FDT start address */
add t0, a1, zero add t0, a1, zero
/* t2 = source FDT size (convert from big-endian) */ and t0, t0, a3
lbu t2, 7(t0) /* t2 = source FDT size in big-endian */
lbu t3, 6(t0) #if __riscv_xlen == 64
lbu t4, 5(t0) lwu t2, 4(t0)
lbu t5, 4(t0) #else
lw t2, 4(t0)
#endif
/* t3 = bit[15:8] of FDT size */
add t3, t2, zero
srli t3, t3, 16
and t3, t3, a4
slli t3, t3, 8 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 slli t4, t4, 16
/* t5 = bit[31:24] of FDT size */
add t5, t2, zero
and t5, t5, a4
slli t5, t5, 24 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, t3
or t2, t2, t4 or t2, t2, t4
or t2, t2, t5 or t2, t2, t5
@ -295,204 +107,177 @@ _fdt_reloc_again:
blt t1, t2, _fdt_reloc_again blt t1, t2, _fdt_reloc_again
_fdt_reloc_done: _fdt_reloc_done:
/* mark boot hart done */ /* Update boot hart flag */
li t0, BOOT_STATUS_BOOT_HART_DONE la a4, _boot_hart_done
lla t1, _boot_status li a5, 1
fence rw, rw REG_S a5, (a4)
REG_S t0, 0(t1) j _wait_for_boot_hart
j _start_warm
/* waiting for boot hart to be done (_boot_status == BOOT_STATUS_BOOT_HART_DONE) */ .align 3
_boot_hart_done:
RISCV_PTR 0
.align 3
/* Wait for boot hart */
_wait_for_boot_hart: _wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE la a4, _boot_hart_done
lla t1, _boot_status REG_L a5, (a4)
REG_L t1, 0(t1) beqz a5, _wait_for_boot_hart
/* Reduce the bus traffic so that boot hart may proceed faster */
div t2, t2, zero
div t2, t2, zero
div t2, t2, zero
bne t0, t1, _wait_for_boot_hart
_start_warm: _start_warm:
/* Reset all registers except ra, a0, a1, a2, a3 and a4 for non-boot HART */ /* Disable and clear all interrupts */
li ra, 0
call _reset_regs
/* Disable all interrupts */
csrw CSR_MIE, zero csrw CSR_MIE, zero
csrw CSR_MIP, zero
/* Find HART count and HART stack size */ /* Preload per-HART details
lla a4, platform * s6 -> HART ID
#if __riscv_xlen > 32 * s7 -> HART Count
* s8 -> HART Stack Size
*/
csrr s6, CSR_MHARTID
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4) lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else #else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4) lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif #endif
REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
/* Find HART id */ /* HART ID should be within expected limit */
csrr s6, CSR_MHARTID csrr s6, CSR_MHARTID
bge s6, s7, _start_hang
/* Find HART index */ /* Setup scratch space */
beqz s9, 3f la tp, _fw_end
li a4, 0
1:
#if __riscv_xlen > 32
lwu a5, (s9)
#else
lw a5, (s9)
#endif
beq a5, s6, 2f
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
2: add s6, a4, zero
3: bge s6, s7, _start_hang
/* Find the scratch space based on HART index */
lla tp, _fw_end
mul a5, s7, s8 mul a5, s7, s8
add tp, tp, a5 add tp, tp, a5
mul a5, s8, s6 mul a5, s8, s6
sub tp, tp, a5 sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE li a5, SBI_SCRATCH_SIZE
sub tp, tp, a5 sub tp, tp, a5
/* update the mscratch */
csrw CSR_MSCRATCH, tp csrw CSR_MSCRATCH, tp
/* Initialize scratch space */
la a4, _fw_start
la a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Note: fw_next_arg1() uses a0, a1, and ra */
call fw_next_arg1
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
/* Note: fw_next_addr() uses a0, a1, and ra */
call fw_next_addr
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
li a4, PRV_S
REG_S a4, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
la a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
la a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
la a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
REG_S zero, SBI_SCRATCH_IPI_TYPE_OFFSET(tp)
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
/* Setup stack */ /* Setup stack */
add sp, tp, zero add sp, tp, zero
/* Setup trap handler */ /* Setup trap handler */
lla a4, _trap_handler la a4, _trap_handler
csrr a5, CSR_MISA
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_handler_hyp
lla a4, _trap_handler_hyp
_skip_trap_handler_hyp:
csrw CSR_MTVEC, a4 csrw CSR_MTVEC, a4
/* Clear MDT here again for all harts */
CLEAR_MDT t0
/* Initialize SBI runtime */ /* Initialize SBI runtime */
csrr a0, CSR_MSCRATCH csrr a0, CSR_MSCRATCH
call sbi_init Call sbi_init
/* We don't expect to reach here hence just hang */ /* We don't expect to reach here hence just hang */
j _start_hang j _start_hang
.data
.align 3 .align 3
_boot_lottery:
RISCV_PTR 0
_boot_status:
RISCV_PTR 0
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3
.globl _hartid_to_scratch .globl _hartid_to_scratch
_hartid_to_scratch: _hartid_to_scratch:
add sp, sp, -(3 * __SIZEOF_POINTER__)
REG_S s0, (sp)
REG_S s1, (__SIZEOF_POINTER__)(sp)
REG_S s2, (__SIZEOF_POINTER__ * 2)(sp)
/* /*
* a0 -> HART ID (passed by caller) * a0 -> HART ID (passed by caller)
* a1 -> HART Index (passed by caller) * s0 -> HART Stack Size
* t0 -> HART Stack Size * s1 -> HART Stack End
* t1 -> HART Stack End * s2 -> Temporary
* t2 -> Temporary
*/ */
lla t2, platform la s2, platform
#if __riscv_xlen > 32 #if __riscv_xlen == 64
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2) lwu s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2) lwu s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
#else #else
lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2) lw s0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(s2)
lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2) lw s2, SBI_PLATFORM_HART_COUNT_OFFSET(s2)
#endif #endif
sub t2, t2, a1 mul s2, s2, s0
mul t2, t2, t0 la s1, _fw_end
lla t1, _fw_end add s1, s1, s2
add t1, t1, t2 mul s2, s0, a0
li t2, SBI_SCRATCH_SIZE sub s1, s1, s2
sub a0, t1, t2 li s2, SBI_SCRATCH_SIZE
sub a0, s1, s2
REG_L s0, (sp)
REG_L s1, (__SIZEOF_POINTER__)(sp)
REG_L s2, (__SIZEOF_POINTER__ * 2)(sp)
add sp, sp, (3 * __SIZEOF_POINTER__)
ret ret
.section .entry, "ax", %progbits
.align 3 .align 3
.section .entry, "ax", %progbits
.globl _start_hang .globl _start_hang
_start_hang: _start_hang:
wfi wfi
j _start_hang j _start_hang
.align 3
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3 .globl _trap_handler
.weak fw_platform_init _trap_handler:
fw_platform_init:
add a0, a1, zero
ret
/* Map implicit memcpy() added by compiler to sbi_memcpy() */
.section .text
.align 3
.globl memcpy
memcpy:
tail sbi_memcpy
/* Map implicit memset() added by compiler to sbi_memset() */
.section .text
.align 3
.globl memset
memset:
tail sbi_memset
/* Map implicit memmove() added by compiler to sbi_memmove() */
.section .text
.align 3
.globl memmove
memmove:
tail sbi_memmove
/* Map implicit memcmp() added by compiler to sbi_memcmp() */
.section .text
.align 3
.globl memcmp
memcmp:
tail sbi_memcmp
.macro TRAP_SAVE_AND_SETUP_SP_T0
/* Swap TP and MSCRATCH */ /* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp csrrw tp, CSR_MSCRATCH, tp
/* Save T0 in scratch space */ /* Save T0 in scratch space */
REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp) REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp)
/* /* Check which mode we came from */
* Set T0 to appropriate exception stack
*
* Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1;
* Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP))
*
* Came_From_M_Mode = 0 ==> Exception_Stack = TP
* Came_From_M_Mode = -1 ==> Exception_Stack = SP
*/
csrr t0, CSR_MSTATUS csrr t0, CSR_MSTATUS
srl t0, t0, MSTATUS_MPP_SHIFT srl t0, t0, MSTATUS_MPP_SHIFT
and t0, t0, PRV_M and t0, t0, PRV_M
slti t0, t0, PRV_M xori t0, t0, PRV_M
add t0, t0, -1 beq t0, zero, _trap_handler_m_mode
xor sp, sp, tp
and t0, t0, sp
xor sp, sp, tp
xor t0, tp, t0
/* Save original SP on exception stack */ /* We came from S-mode or U-mode */
REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_CONTEXT_SIZE)(t0) _trap_handler_s_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Set SP to exception stack and make room for trap context */ /* Setup exception stack */
add sp, t0, -(SBI_TRAP_CONTEXT_SIZE) add sp, tp, -(SBI_TRAP_REGS_SIZE)
/* Jump to code common for all modes */
j _trap_handler_all_mode
/* We came from M-mode */
_trap_handler_m_mode:
/* Set T0 to original SP */
add t0, sp, zero
/* Re-use current SP as exception stack */
add sp, sp, -(SBI_TRAP_REGS_SIZE)
_trap_handler_all_mode:
/* Save original SP (from T0) on stack */
REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp)
/* Restore T0 from scratch space */ /* Restore T0 from scratch space */
REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp) REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp)
@ -502,23 +287,13 @@ memcmp:
/* Swap TP and MSCRATCH */ /* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp csrrw tp, CSR_MSCRATCH, tp
.endm
.macro TRAP_SAVE_MEPC_MSTATUS have_mstatush
/* Save MEPC and MSTATUS CSRs */ /* Save MEPC and MSTATUS CSRs */
csrr t0, CSR_MEPC csrr t0, CSR_MEPC
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrr t0, CSR_MSTATUS csrr t0, CSR_MSTATUS
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
.if \have_mstatush
csrr t0, CSR_MSTATUSH
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
.else
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
.endif
.endm
.macro TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
/* Save all general regisers except SP and T0 */ /* Save all general regisers except SP and T0 */
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp) REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
@ -550,220 +325,53 @@ memcmp:
REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp) REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp) REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp) REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
.endm
.macro TRAP_SAVE_INFO have_mstatush have_h_extension
csrr t0, CSR_MCAUSE
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(cause))(sp)
csrr t0, CSR_MTVAL
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval))(sp)
.if \have_h_extension
csrr t0, CSR_MTVAL2
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval2))(sp)
csrr t0, CSR_MTINST
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tinst))(sp)
.if \have_mstatush
csrr t0, CSR_MSTATUSH
srli t0, t0, MSTATUSH_GVA_SHIFT
.else
csrr t0, CSR_MSTATUS
srli t0, t0, MSTATUS_GVA_SHIFT
.endif
and t0, t0, 0x1
.else
REG_S zero, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tval2))(sp)
REG_S zero, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(tinst))(sp)
li t0, 0
.endif
REG_S t0, (SBI_TRAP_REGS_SIZE + SBI_TRAP_INFO_OFFSET(gva))(sp)
/* We are ready to take another trap, clear MDT */
CLEAR_MDT t0
.endm
.macro TRAP_CALL_C_ROUTINE
/* Call C routine */ /* Call C routine */
add a0, sp, zero add a0, sp, zero
csrr a1, CSR_MSCRATCH
call sbi_trap_handler call sbi_trap_handler
.endm
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0 /* Restore all general regisers except SP and T0 */
/* Restore all general regisers except A0 and T0 */ REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0) REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0) REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0) REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0) REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0) REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0) REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0) REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0) REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0) REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0) REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0) REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0) REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0) REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0) REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0) REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0) REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0) REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0) REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0) REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0) REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0) REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0) REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0) REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0) REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0) REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0) REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0) REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0) REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
.endm
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush /* Restore MEPC and MSTATUS CSRs */
/* REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
* Restore MSTATUS and MEPC CSRs starting with MSTATUS/H to set MDT
* flags since we can not take a trap now or MEPC would be cloberred
*/
.if \have_mstatush
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(a0)
csrw CSR_MSTATUSH, t0
.endif
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
csrw CSR_MSTATUS, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
csrw CSR_MEPC, t0 csrw CSR_MEPC, t0
.endm REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
csrw CSR_MSTATUS, t0
.macro TRAP_RESTORE_A0_T0
/* Restore T0 */ /* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0) REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
/* Restore A0 */ /* Restore SP */
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0) REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
.endm
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
_trap_handler:
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 0
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_SAVE_INFO 0 0
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_A0_T0
mret mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler_hyp
_trap_handler_hyp:
TRAP_SAVE_AND_SETUP_SP_T0
#if __riscv_xlen == 32
TRAP_SAVE_MEPC_MSTATUS 1
#else
TRAP_SAVE_MEPC_MSTATUS 0
#endif
TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
#if __riscv_xlen == 32
TRAP_SAVE_INFO 1 1
#else
TRAP_SAVE_INFO 0 1
#endif
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
#if __riscv_xlen == 32
TRAP_RESTORE_MEPC_MSTATUS 1
#else
TRAP_RESTORE_MEPC_MSTATUS 0
#endif
TRAP_RESTORE_A0_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _reset_regs
_reset_regs:
/* flush the instruction cache */
fence.i
/* Reset all registers except ra, a0, a1, a2, a3 and a4 */
li sp, 0
li gp, 0
li tp, 0
li t0, 0
li t1, 0
li t2, 0
li s0, 0
li s1, 0
li a5, 0
li a6, 0
li a7, 0
li s2, 0
li s3, 0
li s4, 0
li s5, 0
li s6, 0
li s7, 0
li s8, 0
li s9, 0
li s10, 0
li s11, 0
li t3, 0
li t4, 0
li t5, 0
li t6, 0
csrw CSR_MSCRATCH, 0
ret
.section .rodata
.Lstack_corrupt_msg:
.string "stack smashing detected\n"
/* This will be called when the stack corruption is detected */
.section .text
.align 3
.globl __stack_chk_fail
.type __stack_chk_fail, %function
__stack_chk_fail:
la a0, .Lstack_corrupt_msg
call sbi_panic
/* Initial value of the stack guard variable */
.section .data
.align 3
.globl __stack_chk_guard
.type __stack_chk_guard, %object
__stack_chk_guard:
RISCV_PTR 0x95B5FF5A
#ifdef FW_FDT_PATH
.section .rodata
.align 4
.globl fw_fdt_bin
fw_fdt_bin:
.incbin FW_FDT_PATH
#ifdef FW_FDT_PADDING
.fill FW_FDT_PADDING, 1, 0
#endif
#endif

View File

@ -8,7 +8,7 @@
*/ */
. = FW_TEXT_START; . = FW_TEXT_START;
/* Don't add any section between FW_TEXT_START and _fw_start */
PROVIDE(_fw_start = .); PROVIDE(_fw_start = .);
. = ALIGN(0x1000); /* Need this to create proper sections */ . = ALIGN(0x1000); /* Need this to create proper sections */
@ -20,59 +20,36 @@
PROVIDE(_text_start = .); PROVIDE(_text_start = .);
*(.entry) *(.entry)
*(.text) *(.text)
*(.text.*)
. = ALIGN(8); . = ALIGN(8);
PROVIDE(_text_end = .); PROVIDE(_text_end = .);
} }
/* End of the code sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */ . = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
/* Beginning of the read-only data sections */ /* Beginning of the read-only data sections */
PROVIDE(_rodata_start = .); . = ALIGN(0x1000); /* Ensure next section is page aligned */
.rodata : .rodata :
{ {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*) *(.rodata .rodata.*)
. = ALIGN(8); . = ALIGN(8);
PROVIDE(_rodata_end = .);
} }
.dynsym :
{
*(.dynsym)
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.rela.dyn : {
PROVIDE(__rela_dyn_start = .);
*(.rela*)
PROVIDE(__rela_dyn_end = .);
}
PROVIDE(_rodata_end = .);
/* End of the read-only data sections */ /* End of the read-only data sections */
/*
* PMP regions must be to be power-of-2. RX/RW will have separate
* regions, so ensure that the split is power-of-2.
*/
. = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text)
+ SIZEOF(.dynsym) + SIZEOF(.rela.dyn))));
PROVIDE(_fw_rw_start = .);
/* Beginning of the read-write data sections */ /* Beginning of the read-write data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.data : .data :
{ {
PROVIDE(_data_start = .); PROVIDE(_data_start = .);
*(.sdata)
*(.sdata.*)
*(.data) *(.data)
*(.data.*) *(.data.*)
*(.readmostly.data) *(.readmostly.data)
@ -87,8 +64,6 @@
.bss : .bss :
{ {
PROVIDE(_bss_start = .); PROVIDE(_bss_start = .);
*(.sbss)
*(.sbss.*)
*(.bss) *(.bss)
*(.bss.*) *(.bss.*)
. = ALIGN(8); . = ALIGN(8);

View File

@ -1,137 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/fw_dynamic.h>
#include "fw_base.S"
.section .entry, "ax", %progbits
.align 3
.global fw_boot_hart
/*
* This function is called very early even before
* fw_save_info() is called.
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
/* Sanity checks */
li a1, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a0, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a0, a1, _start_hang
li a1, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a0, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a0, a1, _start_hang
/* Read boot HART id */
li a1, FW_DYNAMIC_INFO_VERSION_2
blt a0, a1, 2f
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
ret
2: li a0, -1
ret
.section .entry, "ax", %progbits
.align 3
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
/* Save next arg1 in 'a1' */
lla a4, _dynamic_next_arg1
REG_S a1, (a4)
/* Save version == 0x1 fields */
lla a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
REG_S a3, (a4)
lla a4, _dynamic_next_mode
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
REG_S a3, (a4)
lla a4, _dynamic_options
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
REG_S a3, (a4)
/* Save version == 0x2 fields */
li a4, FW_DYNAMIC_INFO_VERSION_2
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
blt a3, a4, 2f
lla a4, _dynamic_boot_hart
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
REG_S a3, (a4)
2:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
lla a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr:
lla a0, _dynamic_next_addr
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
lla a0, _dynamic_next_mode
REG_L a0, (a0)
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
lla a0, _dynamic_options
REG_L a0, (a0)
ret
.section .data
.align 3
_dynamic_next_arg1:
RISCV_PTR 0x0
_dynamic_next_addr:
RISCV_PTR 0x0
_dynamic_next_mode:
RISCV_PTR PRV_S
_dynamic_options:
RISCV_PTR 0x0
_dynamic_boot_hart:
RISCV_PTR -1

View File

@ -1,18 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
#include "fw_base.ldS"
PROVIDE(_fw_reloc_end = .);
}

View File

@ -9,98 +9,40 @@
#include "fw_base.S" #include "fw_base.S"
.section .entry, "ax", %progbits
.align 3 .align 3
.global fw_boot_hart
/*
* This function is called very early even before
* fw_save_info() is called.
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
li a0, -1
ret
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3 .global fw_prev_arg1
.global fw_save_info fw_prev_arg1:
/* /* We return previous arg1 in 'a0' */
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
#ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR
#elif defined(FW_JUMP_FDT_OFFSET)
lla a0, _fw_start
li a1, FW_JUMP_FDT_OFFSET
add a0, a0, a1
#else
add a0, a1, zero
#endif
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr:
#ifdef FW_JUMP_ADDR
lla a0, _jump_addr
REG_L a0, (a0)
#elif defined(FW_JUMP_OFFSET)
lla a0, _fw_start
li a1, FW_JUMP_OFFSET
add a0, a0, a1
#else
#error "Must define at least FW_JUMP_ADDR or FW_JUMP_OFFSET"
#endif
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'
*/
fw_next_mode:
li a0, PRV_S
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero add a0, zero, zero
ret ret
#ifdef FW_JUMP_ADDR
.section .rodata
.align 3 .align 3
.section .entry, "ax", %progbits
.global fw_next_arg1
fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_JUMP_FDT_ADDR
li a0, FW_JUMP_FDT_ADDR
#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: _jump_addr:
RISCV_PTR FW_JUMP_ADDR RISCV_PTR FW_JUMP_ADDR
#endif

View File

@ -13,6 +13,4 @@ ENTRY(_start)
SECTIONS SECTIONS
{ {
#include "fw_base.ldS" #include "fw_base.ldS"
PROVIDE(_fw_reloc_end = .);
} }

View File

@ -9,88 +9,48 @@
#include "fw_base.S" #include "fw_base.S"
.align 4
.section .entry, "ax", %progbits .section .entry, "ax", %progbits
.align 3 .global fw_prev_arg1
.global fw_boot_hart fw_prev_arg1:
/* /* We return previous arg1 in 'a0' */
* This function is called very early even before #ifdef FW_PAYLOAD_FDT_PATH
* fw_save_info() is called. la a0, fdt_bin
* We can only use a0, a1, and a2 registers here.
* The boot HART id should be returned in 'a0'.
*/
fw_boot_hart:
li a0, -1
ret
.section .entry, "ax", %progbits
.align 3
.global fw_save_info
/*
* We can only use a0, a1, a2, a3, and a4 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* Nothing to be returned here.
*/
fw_save_info:
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_arg1
/*
* We can only use a0, a1, and a2 registers here.
* The a0, a1, and a2 registers will be same as passed by
* previous booting stage.
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
#ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR
#elif defined(FW_PAYLOAD_FDT_OFFSET)
lla a0, _fw_start
li a1, FW_PAYLOAD_FDT_OFFSET
add a0, a0, a1
#else #else
add a0, a1, zero add a0, zero, zero
#endif #endif
ret ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_addr
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_addr:
lla a0, payload_bin
ret
.section .entry, "ax", %progbits
.align 3
.global fw_next_mode
/*
* We can only use a0, a1, and a2 registers here.
* The next address should be returned in 'a0'.
*/
fw_next_mode:
li a0, PRV_S
ret
.section .entry, "ax", %progbits
.align 3
.global fw_options
/*
* We can only use a0, a1, and a2 registers here.
* The 'a4' register will have default options.
* The next address should be returned in 'a0'.
*/
fw_options:
add a0, zero, zero
ret
.section .payload, "ax", %progbits
.align 4 .align 4
.section .entry, "ax", %progbits
.global fw_next_arg1
fw_next_arg1:
/* We return next arg1 in 'a0' */
#ifdef FW_PAYLOAD_FDT_ADDR
li a0, FW_PAYLOAD_FDT_ADDR
#else
add a0, zero, zero
#endif
ret
.align 4
.section .entry, "ax", %progbits
.global fw_next_addr
fw_next_addr:
/* We return next address in 'a0' */
la a0, payload_bin
ret
#ifdef FW_PAYLOAD_FDT_PATH
.align 4
.section .text, "ax", %progbits
.globl fdt_bin
fdt_bin:
.incbin FW_PAYLOAD_FDT_PATH
#endif
.align 4
.section .payload, "ax", %progbits
.globl payload_bin .globl payload_bin
payload_bin: payload_bin:
#ifndef FW_PAYLOAD_PATH #ifndef FW_PAYLOAD_PATH

View File

@ -27,6 +27,4 @@ SECTIONS
. = ALIGN(8); . = ALIGN(8);
PROVIDE(_payload_end = .); PROVIDE(_payload_end = .);
} }
PROVIDE(_fw_reloc_end = .);
} }

View File

@ -15,29 +15,12 @@ firmware-ldflags-y +=
ifdef FW_TEXT_START ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START) firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
else
firmware-genflags-y += -DFW_TEXT_START=0x0
endif endif
ifdef FW_FDT_PATH
firmware-genflags-y += -DFW_FDT_PATH=\"$(FW_FDT_PATH)\"
ifdef FW_FDT_PADDING
firmware-genflags-y += -DFW_FDT_PADDING=$(FW_FDT_PADDING)
endif
endif
firmware-bins-$(FW_DYNAMIC) += fw_dynamic.bin
firmware-bins-$(FW_JUMP) += fw_jump.bin firmware-bins-$(FW_JUMP) += fw_jump.bin
ifdef FW_JUMP_OFFSET
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_OFFSET=$(FW_JUMP_OFFSET)
endif
ifdef FW_JUMP_ADDR ifdef FW_JUMP_ADDR
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR) firmware-genflags-$(FW_JUMP) += -DFW_JUMP_ADDR=$(FW_JUMP_ADDR)
endif endif
ifdef FW_JUMP_FDT_OFFSET
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_FDT_OFFSET=$(FW_JUMP_FDT_OFFSET)
endif
ifdef FW_JUMP_FDT_ADDR ifdef FW_JUMP_FDT_ADDR
firmware-genflags-$(FW_JUMP) += -DFW_JUMP_FDT_ADDR=$(FW_JUMP_FDT_ADDR) firmware-genflags-$(FW_JUMP) += -DFW_JUMP_FDT_ADDR=$(FW_JUMP_FDT_ADDR)
endif endif
@ -46,7 +29,7 @@ firmware-bins-$(FW_PAYLOAD) += fw_payload.bin
ifdef FW_PAYLOAD_PATH ifdef FW_PAYLOAD_PATH
FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH) FW_PAYLOAD_PATH_FINAL=$(FW_PAYLOAD_PATH)
else else
FW_PAYLOAD_PATH_FINAL=$(platform_build_dir)/firmware/payloads/test.bin FW_PAYLOAD_PATH_FINAL=$(build_dir)/$(platform_subdir)/firmware/payloads/test.bin
endif endif
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\" firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_PATH=\"$(FW_PAYLOAD_PATH_FINAL)\"
ifdef FW_PAYLOAD_OFFSET ifdef FW_PAYLOAD_OFFSET
@ -56,22 +39,14 @@ ifdef FW_PAYLOAD_ALIGN
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN) firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
endif endif
ifdef FW_PAYLOAD_FDT_OFFSET ifndef FW_PAYLOAD_FDT_PATH
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_OFFSET=$(FW_PAYLOAD_FDT_OFFSET) ifdef FW_PAYLOAD_FDT
FW_PAYLOAD_FDT_PATH=$(build_dir)/$(platform_subdir)/$(FW_PAYLOAD_FDT)
endif
endif
ifdef FW_PAYLOAD_FDT_PATH
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
endif endif
ifdef FW_PAYLOAD_FDT_ADDR ifdef FW_PAYLOAD_FDT_ADDR
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR) firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_ADDR=$(FW_PAYLOAD_FDT_ADDR)
endif endif
ifdef FW_OPTIONS
firmware-genflags-y += -DFW_OPTIONS=$(FW_OPTIONS)
endif
ifeq ($(CONFIG_STACK_PROTECTOR),y)
stack-protector-cflags-$(CONFIG_STACK_PROTECTOR) := -fstack-protector
stack-protector-cflags-$(CONFIG_STACK_PROTECTOR_STRONG) := -fstack-protector-strong
stack-protector-cflags-$(CONFIG_STACK_PROTECTOR_ALL) := -fstack-protector-all
else
stack-protector-cflags-y := -fno-stack-protector
endif
firmware-cflags-y += $(stack-protector-cflags-y)

View File

@ -33,12 +33,14 @@ SECTIONS
PROVIDE(_text_end = .); PROVIDE(_text_end = .);
} }
/* End of the code sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */ . = ALIGN(0x1000); /* Ensure next section is page aligned */
/* End of the code sections */
/* Beginning of the read-only data sections */ /* Beginning of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.rodata : .rodata :
{ {
PROVIDE(_rodata_start = .); PROVIDE(_rodata_start = .);
@ -49,10 +51,10 @@ SECTIONS
/* End of the read-only data sections */ /* End of the read-only data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
/* Beginning of the read-write data sections */ /* Beginning of the read-write data sections */
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.data : .data :
{ {
PROVIDE(_data_start = .); PROVIDE(_data_start = .);

View File

@ -23,36 +23,25 @@
#define REG_L __REG_SEL(ld, lw) #define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw) #define REG_S __REG_SEL(sd, sw)
.section .entry, "ax", %progbits
.align 3 .align 3
.section .entry, "ax", %progbits
.globl _start .globl _start
_start: _start:
/* Pick one hart to run the main boot sequence */ /* Pick one hart to run the main boot sequence */
lla a3, _hart_lottery la a3, _hart_lottery
li a2, 1 li a2, 1
#ifdef __riscv_atomic
amoadd.w a3, a2, (a3) amoadd.w a3, a2, (a3)
#elif __riscv_zalrsc
_sc_fail:
lr.w t0, (a3)
addw t1, t0, a2
sc.w t1, t1, (a3)
bnez t1, _sc_fail
move a3, t0
#else
#error "need a or zalrsc"
#endif
bnez a3, _start_hang bnez a3, _start_hang
/* Save a0 and a1 */ /* Save a0 and a1 */
lla a3, _boot_a0 la a3, _boot_a0
REG_S a0, 0(a3) REG_S a0, 0(a3)
lla a3, _boot_a1 la a3, _boot_a1
REG_S a1, 0(a3) REG_S a1, 0(a3)
/* Zero-out BSS */ /* Zero-out BSS */
lla a4, _bss_start la a4, _bss_start
lla a5, _bss_end la a5, _bss_end
_bss_zero: _bss_zero:
REG_S zero, (a4) REG_S zero, (a4)
add a4, a4, __SIZEOF_POINTER__ add a4, a4, __SIZEOF_POINTER__
@ -64,51 +53,36 @@ _start_warm:
csrw CSR_SIP, zero csrw CSR_SIP, zero
/* Setup exception vectors */ /* Setup exception vectors */
lla a3, _start_hang la a3, _start_hang
csrw CSR_STVEC, a3 csrw CSR_STVEC, a3
/* Setup stack */ /* Setup stack */
lla a3, _payload_end la a3, _payload_end
li a4, 0x2000 li a4, 0x2000
add sp, a3, a4 add sp, a3, a4
/* Jump to C main */ /* Jump to C main */
lla a3, _boot_a0 la a3, _boot_a0
REG_L a0, 0(a3) REG_L a0, 0(a3)
lla a3, _boot_a1 la a3, _boot_a1
REG_L a1, 0(a3) REG_L a1, 0(a3)
call test_main call test_main
/* We don't expect to reach here hence just hang */ /* We don't expect to reach here hence just hang */
j _start_hang j _start_hang
.section .entry, "ax", %progbits
.align 3 .align 3
.section .entry, "ax", %progbits
.globl _start_hang .globl _start_hang
_start_hang: _start_hang:
wfi wfi
j _start_hang j _start_hang
.section .data
.align 3 .align 3
.section .entry, "ax", %progbits
_hart_lottery: _hart_lottery:
RISCV_PTR 0 RISCV_PTR 0
_boot_a0: _boot_a0:
RISCV_PTR 0 RISCV_PTR 0
_boot_a1: _boot_a1:
RISCV_PTR 0 RISCV_PTR 0
/* This will be called when the stack corruption is detected */
.section .text
.align 3
.globl __stack_chk_fail
.type __stack_chk_fail, %function
.equ __stack_chk_fail, _start_hang
/* Initial value of the stack guard variable */
.section .data
.align 3
.globl __stack_chk_guard
.type __stack_chk_guard, %object
__stack_chk_guard:
RISCV_PTR 0x95B5FF5A

View File

@ -8,59 +8,16 @@
*/ */
#include <sbi/sbi_ecall_interface.h> #include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_string.h>
struct sbiret { #define wfi() \
unsigned long error; do { \
unsigned long value; __asm__ __volatile__ ("wfi" ::: "memory"); \
}; } while (0)
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5)
{
struct sbiret ret;
register unsigned long a0 asm ("a0") = (unsigned long)(arg0);
register unsigned long a1 asm ("a1") = (unsigned long)(arg1);
register unsigned long a2 asm ("a2") = (unsigned long)(arg2);
register unsigned long a3 asm ("a3") = (unsigned long)(arg3);
register unsigned long a4 asm ("a4") = (unsigned long)(arg4);
register unsigned long a5 asm ("a5") = (unsigned long)(arg5);
register unsigned long a6 asm ("a6") = (unsigned long)(fid);
register unsigned long a7 asm ("a7") = (unsigned long)(ext);
asm volatile ("ecall"
: "+r" (a0), "+r" (a1)
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
: "memory");
ret.error = a0;
ret.value = a1;
return ret;
}
static inline void sbi_ecall_console_puts(const char *str)
{
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
sbi_strlen(str), (unsigned long)str, 0, 0, 0, 0);
}
static inline void sbi_ecall_shutdown(void)
{
sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET,
SBI_SRST_RESET_TYPE_SHUTDOWN, SBI_SRST_RESET_REASON_NONE,
0, 0, 0, 0);
}
#define wfi() \
do { \
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
void test_main(unsigned long a0, unsigned long a1) void test_main(unsigned long a0, unsigned long a1)
{ {
sbi_ecall_console_puts("\nTest payload running\n"); sbi_ecall_console_puts("\nTest payload running\n");
sbi_ecall_shutdown();
sbi_ecall_console_puts("sbi_ecall_shutdown failed to execute.\n"); while (1)
wfi();
} }

View File

@ -1,91 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FW_DYNAMIC_H__
#define __FW_DYNAMIC_H__
#include <sbi/riscv_asm.h>
/* clang-format off */
/** Offset of magic member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_LONG__)
/** Offset of version member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_LONG__)
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_LONG__)
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_LONG__)
/** Offset of options member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_LONG__)
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_LONG__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_2 0x2
#define FW_DYNAMIC_INFO_VERSION_MAX FW_DYNAMIC_INFO_VERSION_2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1
#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3
/* clang-format on */
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>
/** Representation dynamic info passed by previous booting stage */
struct fw_dynamic_info {
/** Info magic */
unsigned long magic;
/** Info version */
unsigned long version;
/** Next booting stage address */
unsigned long next_addr;
/** Next booting stage mode */
unsigned long next_mode;
/** Options for OpenSBI library */
unsigned long options;
/**
* Preferred boot HART id
*
* It is possible that the previous booting stage uses same link
* address as the FW_DYNAMIC firmware. In this case, the relocation
* lottery mechanism can potentially overwrite the previous booting
* stage while other HARTs are still running in the previous booting
* stage leading to boot-time crash. To avoid this boot-time crash,
* the previous booting stage can specify last HART that will jump
* to the FW_DYNAMIC firmware as the preferred boot HART.
*
* To avoid specifying a preferred boot HART, the previous booting
* stage can set it to -1UL which will force the FW_DYNAMIC firmware
* to use the relocation lottery mechanism.
*/
unsigned long boot_hart;
} __packed;
/**
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_OFFSET
*/
assert_member_offset(struct fw_dynamic_info, magic, FW_DYNAMIC_INFO_MAGIC_OFFSET);
assert_member_offset(struct fw_dynamic_info, version, FW_DYNAMIC_INFO_VERSION_OFFSET);
assert_member_offset(struct fw_dynamic_info, next_addr, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET);
assert_member_offset(struct fw_dynamic_info, next_mode, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET);
assert_member_offset(struct fw_dynamic_info, options, FW_DYNAMIC_INFO_OPTIONS_OFFSET);
assert_member_offset(struct fw_dynamic_info, boot_hart, FW_DYNAMIC_INFO_BOOT_HART_OFFSET);
#endif
#endif

View File

@ -12,9 +12,7 @@
#include <sbi/riscv_encoding.h> #include <sbi/riscv_encoding.h>
/* clang-format off */ #ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define __ASM_STR(x) x #define __ASM_STR(x) x
#else #else
#define __ASM_STR(x) #x #define __ASM_STR(x) #x
@ -28,17 +26,14 @@
#error "Unexpected __riscv_xlen" #error "Unexpected __riscv_xlen"
#endif #endif
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define REG_L __REG_SEL(ld, lw) #define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw) #define REG_S __REG_SEL(sd, sw)
#define SZREG __REG_SEL(8, 4) #define SZREG __REG_SEL(8, 4)
#define LGREG __REG_SEL(3, 2) #define LGREG __REG_SEL(3, 2)
#if __SIZEOF_POINTER__ == 8 #if __SIZEOF_POINTER__ == 8
#ifdef __ASSEMBLER__ #define BITS_PER_LONG 64
#ifdef __ASSEMBLY__
#define RISCV_PTR .dword #define RISCV_PTR .dword
#define RISCV_SZPTR 8 #define RISCV_SZPTR 8
#define RISCV_LGPTR 3 #define RISCV_LGPTR 3
@ -48,7 +43,8 @@
#define RISCV_LGPTR "3" #define RISCV_LGPTR "3"
#endif #endif
#elif __SIZEOF_POINTER__ == 4 #elif __SIZEOF_POINTER__ == 4
#ifdef __ASSEMBLER__ #define BITS_PER_LONG 32
#ifdef __ASSEMBLY__
#define RISCV_PTR .word #define RISCV_PTR .word
#define RISCV_SZPTR 4 #define RISCV_SZPTR 4
#define RISCV_LGPTR 2 #define RISCV_LGPTR 2
@ -77,150 +73,107 @@
#error "Unexpected __SIZEOF_SHORT__" #error "Unexpected __SIZEOF_SHORT__"
#endif #endif
/* clang-format on */ #ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__ #define csr_swap(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\
: "=r" (__v) : "rK" (__v) \
: "memory"); \
__v; \
})
#define csr_swap(csr, val) \ #define csr_read(csr) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ register unsigned long __v; \
__asm__ __volatile__("csrrw %0, " __ASM_STR(csr) ", %1" \ __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \
: "=r"(__v) \ : "=r" (__v) : \
: "rK"(__v) \ : "memory"); \
: "memory"); \ __v; \
__v; \ })
})
#define csr_read(csr) \ #define csr_write(csr, val) \
({ \ ({ \
register unsigned long __v; \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrr %0, " __ASM_STR(csr) \ __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \
: "=r"(__v) \ : : "rK" (__v) \
: \ : "memory"); \
: "memory"); \ })
__v; \
})
/* Variant of csr_read() that allows the compiler to cache the value. */ #define csr_read_set(csr, val) \
#define csr_read_relaxed(csr) \ ({ \
({ \ unsigned long __v = (unsigned long)(val); \
register unsigned long __v; \ __asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\
__asm__ ("csrr %0, " __ASM_STR(csr) : "=r"(__v)); \ : "=r" (__v) : "rK" (__v) \
__v; \ : "memory"); \
}) __v; \
})
#define csr_write(csr, val) \ #define csr_set(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrw " __ASM_STR(csr) ", %0" \ __asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \
: \ : : "rK" (__v) \
: "rK"(__v) \ : "memory"); \
: "memory"); \ })
})
#define csr_read_set(csr, val) \ #define csr_read_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrrs %0, " __ASM_STR(csr) ", %1" \ __asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\
: "=r"(__v) \ : "=r" (__v) : "rK" (__v) \
: "rK"(__v) \ : "memory"); \
: "memory"); \ __v; \
__v; \ })
})
#define csr_set(csr, val) \ #define csr_clear(csr, val) \
({ \ ({ \
unsigned long __v = (unsigned long)(val); \ unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrs " __ASM_STR(csr) ", %0" \ __asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \
: \ : : "rK" (__v) \
: "rK"(__v) \ : "memory"); \
: "memory"); \ })
})
#define csr_read_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrrc %0, " __ASM_STR(csr) ", %1" \
: "=r"(__v) \
: "rK"(__v) \
: "memory"); \
__v; \
})
#define csr_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__("csrc " __ASM_STR(csr) ", %0" \
: \
: "rK"(__v) \
: "memory"); \
})
#if __riscv_xlen == 64
#define __csrrw64(op, csr, csrh, val) (true ? op(csr, val) : (uint64_t)csrh)
#define __csrr64( op, csr, csrh) (true ? op(csr) : (uint64_t)csrh)
#define __csrw64( op, csr, csrh, val) (true ? op(csr, val) : (uint64_t)csrh)
#elif __riscv_xlen == 32
#define __csrrw64(op, csr, csrh, val) ( op(csr, val) | (uint64_t)op(csrh, val >> 32) << 32)
#define __csrr64( op, csr, csrh) ( op(csr) | (uint64_t)op(csrh) << 32)
#define __csrw64( op, csr, csrh, val) ({ op(csr, val); op(csrh, val >> 32); })
#endif
#define csr_swap64( csr, val) __csrrw64(csr_swap, csr, csr ## H, val)
#define csr_read64( csr) __csrr64 (csr_read, csr, csr ## H)
#define csr_read_relaxed64(csr) __csrr64 (csr_read_relaxed, csr, csr ## H)
#define csr_write64( csr, val) __csrw64 (csr_write, csr, csr ## H, val)
#define csr_read_set64( csr, val) __csrrw64(csr_read_set, csr, csr ## H, val)
#define csr_set64( csr, val) __csrw64 (csr_set, csr, csr ## H, val)
#define csr_clear64( csr, val) __csrw64 (csr_clear, csr, csr ## H, val)
#define csr_read_clear64( csr, val) __csrrw64(csr_read_clear, csr, csr ## H, val)
#define csr_clear64( csr, val) __csrw64 (csr_clear, csr, csr ## H, val)
unsigned long csr_read_num(int csr_num); unsigned long csr_read_num(int csr_num);
void csr_write_num(int csr_num, unsigned long val); void csr_write_num(int csr_num, unsigned long val);
#define wfi() \ #define wfi() \
do { \ do { \
__asm__ __volatile__("wfi" ::: "memory"); \ __asm__ __volatile__ ("wfi" ::: "memory"); \
} while (0) } while (0)
#define ebreak() \ static inline int misa_extension(char ext)
do { \ {
__asm__ __volatile__("ebreak" ::: "memory"); \ return csr_read(CSR_MISA) & (1 << (ext - 'A'));
} while (0) }
/* Get current HART id */ static inline int misa_xlen(void)
#define current_hartid() ((unsigned int)csr_read_relaxed(CSR_MHARTID)) {
return ((long)csr_read(CSR_MISA) < 0) ? 64 : 32;
}
/* determine CPU extension, return non-zero support */ static inline void misa_string(char *out, unsigned int out_sz)
int misa_extension_imp(char ext); {
unsigned long i, val = csr_read(CSR_MISA);
#define misa_extension(c)\ for (i = 0; i < 26; i++) {
({\ if (val & (1 << i)) {
_Static_assert(((c >= 'A') && (c <= 'Z')),\ *out = 'A' + i;
"The parameter of misa_extension must be [A-Z]");\ out++;
misa_extension_imp(c);\ }
}) }
*out = '\0';
out++;
}
/* Get MXL field of misa, return -1 on error */ int pmp_set(unsigned int n, unsigned long prot,
int misa_xlen(void); unsigned long addr, unsigned long log2len);
/* Get RISC-V ISA string representation */ int pmp_get(unsigned int n, unsigned long *prot_out,
void misa_string(int xlen, char *out, unsigned int out_sz); unsigned long *addr_out, unsigned long *log2len_out);
/* Disable pmp entry at a given index */ #endif /* !__ASSEMBLY__ */
int pmp_disable(unsigned int n);
/* Check if the matching field is set */
int is_pmp_entry_mapped(unsigned long entry);
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);
#endif /* !__ASSEMBLER__ */
#endif #endif

View File

@ -14,12 +14,11 @@ typedef struct {
volatile long counter; volatile long counter;
} atomic_t; } atomic_t;
#define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val) #define ATOMIC_INIT(_lptr, val) \
(_lptr)->counter = (val)
#define ATOMIC_INITIALIZER(val) \ #define ATOMIC_INITIALIZER(val) \
{ \ { .counter = (val), }
.counter = (val), \
}
long atomic_read(atomic_t *atom); long atomic_read(atomic_t *atom);
@ -29,24 +28,21 @@ long atomic_add_return(atomic_t *atom, long value);
long atomic_sub_return(atomic_t *atom, long value); long atomic_sub_return(atomic_t *atom, long value);
long atomic_cmpxchg(atomic_t *atom, long oldval, long newval); long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
long atomic_xchg(atomic_t *atom, long newval); long arch_atomic_xchg(atomic_t *atom, long newval);
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr, unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval); unsigned int newval);
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval);
/** /**
* Set a bit in an atomic variable and return the value of bit before modify. * Set a bit in an atomic variable and return the new value.
* @nr : Bit to set. * @nr : Bit to set.
* @atom: atomic variable to modify * @atom: atomic variable to modify
*/ */
int atomic_set_bit(int nr, atomic_t *atom); int atomic_set_bit(int nr, atomic_t *atom);
/** /**
* Clear a bit in an atomic variable and return the value of bit before modify. * Clear a bit in an atomic variable and return the new value.
* @nr : Bit to set. * @nr : Bit to set.
* @atom: atomic variable to modify * @atom: atomic variable to modify
*/ */
@ -54,14 +50,14 @@ int atomic_set_bit(int nr, atomic_t *atom);
int atomic_clear_bit(int nr, atomic_t *atom); int atomic_clear_bit(int nr, atomic_t *atom);
/** /**
* Set a bit in any address and return the value of bit before modify. * Set a bit in any address and return the new value .
* @nr : Bit to set. * @nr : Bit to set.
* @addr: Address to modify * @addr: Address to modify
*/ */
int atomic_raw_set_bit(int nr, volatile unsigned long *addr); int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
/** /**
* Clear a bit in any address and return the value of bit before modify. * Clear a bit in any address and return the new value .
* @nr : Bit to set. * @nr : Bit to set.
* @addr: Address to modify * @addr: Address to modify
*/ */

View File

@ -10,17 +10,12 @@
#ifndef __RISCV_BARRIER_H__ #ifndef __RISCV_BARRIER_H__
#define __RISCV_BARRIER_H__ #define __RISCV_BARRIER_H__
/* clang-format off */
#define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n" #define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n"
#define RISCV_RELEASE_BARRIER "\tfence rw, w\n" #define RISCV_RELEASE_BARRIER "\tfence rw, w\n"
#define RISCV_FENCE(p, s) \ #define RISCV_FENCE(p, s) \
__asm__ __volatile__ ("fence " #p "," #s : : : "memory") __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
#define RISCV_FENCE_I \
__asm__ __volatile__ ("fence.i" : : : "memory")
/* Read & Write Memory barrier */ /* Read & Write Memory barrier */
#define mb() RISCV_FENCE(iorw,iorw) #define mb() RISCV_FENCE(iorw,iorw)
@ -40,25 +35,19 @@
#define smp_wmb() RISCV_FENCE(w,w) #define smp_wmb() RISCV_FENCE(w,w)
/* CPU relax for busy loop */ /* CPU relax for busy loop */
#define cpu_relax() \ #define cpu_relax() asm volatile ("" : : : "memory")
#define __smp_store_release(p, v) \
do { \ do { \
unsigned long __t; \ RISCV_FENCE(rw,w); \
__asm__ __volatile__ ("div %0, %0, zero" : "=r" (__t)); \ *(p) = (v); \
} while (0) } while (0)
/* clang-format on */ #define __smp_load_acquire(p) \
({ \
#define __smp_store_release(p, v) \ typeof(*p) ___p1 = *(p); \
do { \ RISCV_FENCE(r,rw); \
RISCV_FENCE(rw, w); \ ___p1; \
*(p) = (v); \ })
} while (0)
#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = *(p); \
RISCV_FENCE(r, rw); \
___p1; \
})
#endif #endif

View File

@ -1,293 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro System, Inc.
*
* Authors:
* Himanshu Chauhan <hchauhan@ventanamicro.com>
*/
#ifndef __RISCV_DBTR_H__
#define __RISCV_DBTR_H__
#define RV_MAX_TRIGGERS 32
enum {
RISCV_DBTR_TRIG_NONE = 0,
RISCV_DBTR_TRIG_LEGACY,
RISCV_DBTR_TRIG_MCONTROL,
RISCV_DBTR_TRIG_ICOUNT,
RISCV_DBTR_TRIG_ITRIGGER,
RISCV_DBTR_TRIG_ETRIGGER,
RISCV_DBTR_TRIG_MCONTROL6,
};
#define RV_DBTR_BIT(_prefix, _name) \
RV_DBTR_##_prefix##_##_name##_BIT
#define RV_DBTR_BIT_MASK(_prefix, _name) \
RV_DBTR_##_prefix##_name##_BIT_MASK
#define RV_DBTR_DECLARE_BIT(_prefix, _name, _val) \
RV_DBTR_BIT(_prefix, _name) = _val
#define RV_DBTR_DECLARE_BIT_MASK(_prefix, _name, _width) \
RV_DBTR_BIT_MASK(_prefix, _name) = \
(((1UL << _width) - 1) << RV_DBTR_BIT(_prefix, _name))
#define CLEAR_DBTR_BIT(_target, _prefix, _bit_name) \
__clear_bit(RV_DBTR_BIT(_prefix, _bit_name), &_target)
#define SET_DBTR_BIT(_target, _prefix, _bit_name) \
__set_bit(RV_DBTR_BIT(_prefix, _bit_name), &_target)
/* Trigger Data 1 */
enum {
RV_DBTR_DECLARE_BIT(TDATA1, DATA, 0),
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT(TDATA1, DMODE, 59),
RV_DBTR_DECLARE_BIT(TDATA1, TYPE, 60),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT(TDATA1, DMODE, 27),
RV_DBTR_DECLARE_BIT(TDATA1, TYPE, 28),
#else
#error "Unknown __riscv_xlen"
#endif
};
enum {
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT_MASK(TDATA1, DATA, 59),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT_MASK(TDATA1, DATA, 27),
#else
#error "Unknown __riscv_xlen"
#endif
RV_DBTR_DECLARE_BIT_MASK(TDATA1, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(TDATA1, TYPE, 4),
};
/* MC - Match Control Type Register */
enum {
RV_DBTR_DECLARE_BIT(MC, LOAD, 0),
RV_DBTR_DECLARE_BIT(MC, STORE, 1),
RV_DBTR_DECLARE_BIT(MC, EXEC, 2),
RV_DBTR_DECLARE_BIT(MC, U, 3),
RV_DBTR_DECLARE_BIT(MC, S, 4),
RV_DBTR_DECLARE_BIT(MC, RES2, 5),
RV_DBTR_DECLARE_BIT(MC, M, 6),
RV_DBTR_DECLARE_BIT(MC, MATCH, 7),
RV_DBTR_DECLARE_BIT(MC, CHAIN, 11),
RV_DBTR_DECLARE_BIT(MC, ACTION, 12),
RV_DBTR_DECLARE_BIT(MC, SIZELO, 16),
RV_DBTR_DECLARE_BIT(MC, TIMING, 18),
RV_DBTR_DECLARE_BIT(MC, SELECT, 19),
RV_DBTR_DECLARE_BIT(MC, HIT, 20),
#if __riscv_xlen >= 64
RV_DBTR_DECLARE_BIT(MC, SIZEHI, 21),
#endif
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT(MC, MASKMAX, 53),
RV_DBTR_DECLARE_BIT(MC, DMODE, 59),
RV_DBTR_DECLARE_BIT(MC, TYPE, 60),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT(MC, MASKMAX, 21),
RV_DBTR_DECLARE_BIT(MC, DMODE, 27),
RV_DBTR_DECLARE_BIT(MC, TYPE, 28),
#else
#error "Unknown __riscv_xlen"
#endif
};
enum {
RV_DBTR_DECLARE_BIT_MASK(MC, LOAD, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, STORE, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, EXEC, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, U, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, S, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, RES2, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, M, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, MATCH, 4),
RV_DBTR_DECLARE_BIT_MASK(MC, CHAIN, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, ACTION, 4),
RV_DBTR_DECLARE_BIT_MASK(MC, SIZELO, 2),
RV_DBTR_DECLARE_BIT_MASK(MC, TIMING, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, SELECT, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, HIT, 1),
#if __riscv_xlen >= 64
RV_DBTR_DECLARE_BIT_MASK(MC, SIZEHI, 2),
#endif
RV_DBTR_DECLARE_BIT_MASK(MC, MASKMAX, 6),
RV_DBTR_DECLARE_BIT_MASK(MC, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(MC, TYPE, 4),
};
/* ICOUNT - Match Control Type Register */
enum {
RV_DBTR_DECLARE_BIT(ICOUNT, ACTION, 0),
RV_DBTR_DECLARE_BIT(ICOUNT, U, 6),
RV_DBTR_DECLARE_BIT(ICOUNT, S, 7),
RV_DBTR_DECLARE_BIT(ICOUNT, PENDING, 8),
RV_DBTR_DECLARE_BIT(ICOUNT, M, 9),
RV_DBTR_DECLARE_BIT(ICOUNT, COUNT, 10),
RV_DBTR_DECLARE_BIT(ICOUNT, HIT, 24),
RV_DBTR_DECLARE_BIT(ICOUNT, VU, 25),
RV_DBTR_DECLARE_BIT(ICOUNT, VS, 26),
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT(ICOUNT, DMODE, 59),
RV_DBTR_DECLARE_BIT(ICOUNT, TYPE, 60),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT(ICOUNT, DMODE, 27),
RV_DBTR_DECLARE_BIT(ICOUNT, TYPE, 28),
#else
#error "Unknown __riscv_xlen"
#endif
};
enum {
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, ACTION, 6),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, U, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, S, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, PENDING, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, M, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, COUNT, 14),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, HIT, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VU, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VS, 1),
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE, 4),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE, 4),
#else
#error "Unknown __riscv_xlen"
#endif
};
/* MC6 - Match Control 6 Type Register */
enum {
RV_DBTR_DECLARE_BIT(MC6, LOAD, 0),
RV_DBTR_DECLARE_BIT(MC6, STORE, 1),
RV_DBTR_DECLARE_BIT(MC6, EXEC, 2),
RV_DBTR_DECLARE_BIT(MC6, U, 3),
RV_DBTR_DECLARE_BIT(MC6, S, 4),
RV_DBTR_DECLARE_BIT(MC6, RES2, 5),
RV_DBTR_DECLARE_BIT(MC6, M, 6),
RV_DBTR_DECLARE_BIT(MC6, MATCH, 7),
RV_DBTR_DECLARE_BIT(MC6, CHAIN, 11),
RV_DBTR_DECLARE_BIT(MC6, ACTION, 12),
RV_DBTR_DECLARE_BIT(MC6, SIZE, 16),
RV_DBTR_DECLARE_BIT(MC6, TIMING, 20),
RV_DBTR_DECLARE_BIT(MC6, SELECT, 21),
RV_DBTR_DECLARE_BIT(MC6, HIT, 22),
RV_DBTR_DECLARE_BIT(MC6, VU, 23),
RV_DBTR_DECLARE_BIT(MC6, VS, 24),
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT(MC6, DMODE, 59),
RV_DBTR_DECLARE_BIT(MC6, TYPE, 60),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT(MC6, DMODE, 27),
RV_DBTR_DECLARE_BIT(MC6, TYPE, 28),
#else
#error "Unknown __riscv_xlen"
#endif
};
enum {
RV_DBTR_DECLARE_BIT_MASK(MC6, LOAD, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, STORE, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, EXEC, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, U, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, S, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, RES2, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, M, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, MATCH, 4),
RV_DBTR_DECLARE_BIT_MASK(MC6, CHAIN, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, ACTION, 4),
RV_DBTR_DECLARE_BIT_MASK(MC6, SIZE, 4),
RV_DBTR_DECLARE_BIT_MASK(MC6, TIMING, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, SELECT, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, HIT, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, VU, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, VS, 1),
#if __riscv_xlen == 64
RV_DBTR_DECLARE_BIT_MASK(MC6, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, TYPE, 4),
#elif __riscv_xlen == 32
RV_DBTR_DECLARE_BIT_MASK(MC6, DMODE, 1),
RV_DBTR_DECLARE_BIT_MASK(MC6, TYPE, 4),
#else
#error "Unknown __riscv_xlen"
#endif
};
#define RV_DBTR_SET_TDATA1_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(TDATA1, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(TDATA1, TYPE)) \
& RV_DBTR_BIT_MASK(TDATA1, TYPE)); \
}while (0);
#define RV_DBTR_SET_MC_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(MC, TYPE)) \
& RV_DBTR_BIT_MASK(MC, TYPE)); \
}while (0);
#define RV_DBTR_SET_MC6_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC6, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(MC6, TYPE)) \
& RV_DBTR_BIT_MASK(MC6, TYPE)); \
}while (0);
#define RV_DBTR_SET_MC_EXEC(_t1) \
SET_DBTR_BIT(_t1, MC, EXEC)
#define RV_DBTR_SET_MC_LOAD(_t1) \
SET_DBTR_BIT(_t1, MC, LOAD)
#define RV_DBTR_SET_MC_STORE(_t1) \
SET_DBTR_BIT(_t1, MC, STORE)
#define RV_DBTR_SET_MC_SIZELO(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, SIZELO); \
_t1 |= ((_val << RV_DBTR_BIT(MC, SIZELO)) \
& RV_DBTR_BIT_MASK(MC, SIZELO)); \
} while(0);
#define RV_DBTR_SET_MC_SIZEHI(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, SIZEHI); \
_t1 |= ((_val << RV_DBTR_BIT(MC, SIZEHI)) \
& RV_DBTR_BIT_MASK(MC, SIZEHI)); \
} while(0);
#define RV_DBTR_SET_MC6_EXEC(_t1) \
SET_DBTR_BIT(_t1, MC6, EXEC)
#define RV_DBTR_SET_MC6_LOAD(_t1) \
SET_DBTR_BIT(_t1, MC6, LOAD)
#define RV_DBTR_SET_MC6_STORE(_t1) \
SET_DBTR_BIT(_t1, MC6, STORE)
#define RV_DBTR_SET_MC6_SIZE(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC6, SIZE); \
_t1 |= ((_val << RV_DBTR_BIT(MC6, SIZE)) \
& RV_DBTR_BIT_MASK(MC6, SIZE)); \
} while(0);
typedef unsigned long riscv_dbtr_tdata1_mcontrol_t;
typedef unsigned long riscv_dbtr_tdata1_mcontrol6_t;
typedef unsigned long riscv_dbtr_tdata1_t;
#endif /* __RISCV_DBTR_H__ */

View File

@ -1,6 +0,0 @@
#ifndef __RISCV_ELF_H__
#define __RISCV_ELF_H__
#define R_RISCV_RELATIVE 3
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,67 +15,34 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#define GET_PRECISION(insn) (((insn) >> 25) & 3) #define GET_PRECISION(insn) (((insn) >> 25) & 3)
#define GET_RM(insn) (((insn) >> 12) & 7)
#define PRECISION_S 0 #define PRECISION_S 0
#define PRECISION_D 1 #define PRECISION_D 1
#ifdef __riscv_flen #ifdef __riscv_flen
#define GET_F32_REG(insn, pos, regs) \ #define GET_F32_REG(insn, pos, regs) ({ \
({ \ register s32 value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register s32 value asm("a0") = \ ulong tmp; \
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
ulong tmp; \ value; })
asm("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \ #define SET_F32_REG(insn, pos, regs, val) ({ \
: "=&r"(tmp), "+&r"(value)::"t0"); \ register u32 value asm("a0") = (val); \
value; \ ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
}) ulong tmp; \
#define SET_F32_REG(insn, pos, regs, val) \ asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); })
({ \
register u32 value asm("a0") = (val); \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0) #define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
#define GET_F64_REG(insn, pos, regs) ({ \
#if __riscv_xlen == 64 register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
#define GET_F64_REG(insn, pos, regs) \ ulong tmp; \
({ \ asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \ sizeof(ulong) == 4 ? *(int64_t*)value : (int64_t)value; })
ulong tmp; \ #define SET_F64_REG(insn, pos, regs, val) ({ \
asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \ uint64_t __val = (val); \
: "=&r"(tmp), "+&r"(value)::"t0"); \ register ulong value asm("a0") = sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \
value; \ ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
}) ulong tmp; \
#else asm volatile ("1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); })
#define GET_F64_REG(insn, pos, regs) \
({ \
u64 value; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register ulong ptr asm("a0") = (ulong)&value; \
asm ("1: auipc t1, %%pcrel_hi(get_f64_reg); add t1, t1, %2; jalr t0, t1, %%pcrel_lo(1b)" \
: "=m"(value) : "r"(ptr), "r"(offset) : "t0", "t1"); \
value; \
})
#endif
#define SET_F64_REG(insn, pos, regs, val) \
({ \
uint64_t __val = (val); \
register ulong value asm("a0") = \
sizeof(ulong) == 4 ? (ulong)&__val : (ulong)__val; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm volatile( \
"1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp) \
: "r"(value), "r"(offset) \
: "t0"); \
})
#define GET_FCSR() csr_read(CSR_FCSR) #define GET_FCSR() csr_read(CSR_FCSR)
#define SET_FCSR(value) csr_write(CSR_FCSR, (value)) #define SET_FCSR(value) csr_write(CSR_FCSR, (value))
#define GET_FRM() csr_read(CSR_FRM) #define GET_FRM() csr_read(CSR_FRM)
@ -83,7 +50,11 @@
#define GET_FFLAGS() csr_read(CSR_FFLAGS) #define GET_FFLAGS() csr_read(CSR_FFLAGS)
#define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value)) #define SET_FFLAGS(value) csr_write(CSR_FFLAGS, (value))
#define SET_FS_DIRTY(regs) (regs->mstatus |= MSTATUS_FS) #define SET_FS_DIRTY() ((void) 0)
#else
#error "Floating point emulation not supported.\n"
#endif
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs)) #define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs)) #define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
@ -91,10 +62,8 @@
#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs)) #define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs)) #define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs)) #define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
#define SET_F32_RD(insn, regs, val) \ #define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
(SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY(regs)) #define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
#define SET_F64_RD(insn, regs, val) \
(SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY(regs))
#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs)) #define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs)) #define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
@ -102,5 +71,3 @@
#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs)) #define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
#endif #endif
#endif

View File

@ -15,23 +15,23 @@
static inline void __raw_writeb(u8 val, volatile void *addr) static inline void __raw_writeb(u8 val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr));
} }
static inline void __raw_writew(u16 val, volatile void *addr) static inline void __raw_writew(u16 val, volatile void *addr)
{ {
asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr));
} }
static inline void __raw_writel(u32 val, volatile void *addr) static inline void __raw_writel(u32 val, volatile void *addr)
{ {
asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr));
} }
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static inline void __raw_writeq(u64 val, volatile void *addr) static inline void __raw_writeq(u64 val, volatile void *addr)
{ {
asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr));
} }
#endif #endif
@ -39,7 +39,7 @@ static inline u8 __raw_readb(const volatile void *addr)
{ {
u8 val; u8 val;
asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr));
return val; return val;
} }
@ -47,7 +47,7 @@ static inline u16 __raw_readw(const volatile void *addr)
{ {
u16 val; u16 val;
asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr));
return val; return val;
} }
@ -55,7 +55,7 @@ static inline u32 __raw_readl(const volatile void *addr)
{ {
u32 val; u32 val;
asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr));
return val; return val;
} }
@ -64,15 +64,12 @@ static inline u64 __raw_readq(const volatile void *addr)
{ {
u64 val; u64 val;
asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr)); asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr));
return val; return val;
} }
#endif #endif
/* FIXME: These are now the same as asm-generic */ /* FIXME: These are now the same as asm-generic */
/* clang-format off */
#define __io_rbr() do {} while (0) #define __io_rbr() do {} while (0)
#define __io_rar() do {} while (0) #define __io_rar() do {} while (0)
#define __io_rbw() do {} while (0) #define __io_rbw() do {} while (0)
@ -109,6 +106,4 @@ static inline u64 __raw_readq(const volatile void *addr)
#define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); }) #define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
#endif #endif
/* clang-format on */
#endif #endif

View File

@ -2,41 +2,29 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
* *
* Copyright (c) 2019 Western Digital Corporation or its affiliates. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com> *
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/ */
#ifndef __RISCV_LOCKS_H__ #ifndef __RISCV_LOCKS_H__
#define __RISCV_LOCKS_H__ #define __RISCV_LOCKS_H__
#include <sbi/sbi_types.h>
#define TICKET_SHIFT 16
typedef struct { typedef struct {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ volatile long lock;
u16 next; } spinlock_t;
u16 owner;
#else
u16 owner;
u16 next;
#endif
} __aligned(4) spinlock_t;
#define __SPIN_LOCK_UNLOCKED \ #define __RISCV_SPIN_UNLOCKED 0
(spinlock_t) { 0, 0 }
#define SPIN_LOCK_INIT(x) \ #define SPIN_LOCK_INIT(_lptr) \
x = __SPIN_LOCK_UNLOCKED (_lptr)->lock = __RISCV_SPIN_UNLOCKED
#define SPIN_LOCK_INITIALIZER \ #define SPIN_LOCK_INITIALIZER \
__SPIN_LOCK_UNLOCKED { .lock = __RISCV_SPIN_UNLOCKED, }
#define DEFINE_SPIN_LOCK(x) \ int spin_lock_check(spinlock_t *lock);
spinlock_t SPIN_LOCK_INIT(x)
bool spin_lock_check(spinlock_t *lock); int spin_trylock(spinlock_t *lock);
bool spin_trylock(spinlock_t *lock);
void spin_lock(spinlock_t *lock); void spin_lock(spinlock_t *lock);

View File

@ -1,146 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_BITMAP_H__
#define __SBI_BITMAP_H__
#include <sbi/sbi_bitops.h>
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
#define BITMAP_LAST_WORD_MASK(nbits) \
( \
((nbits) % BITS_PER_LONG) ? \
((1UL << ((nbits) % BITS_PER_LONG)) - 1) : ~0UL \
)
#define small_const_nbits(nbits) \
(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
#define DECLARE_BITMAP(name, nbits) unsigned long name[BITS_TO_LONGS(nbits)]
#define DEFINE_BITMAP(name) extern unsigned long name[]
static inline unsigned long bitmap_estimate_size(int nbits)
{
return (BITS_TO_LONGS(nbits) * sizeof(unsigned long));
}
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
static inline void bitmap_set(unsigned long *bmap, int start, int len)
{
int bit;
for (bit = start; bit < (start + len); bit++)
bmap[BIT_WORD(bit)] |= (0x1UL << BIT_WORD_OFFSET(bit));
}
static inline void bitmap_clear(unsigned long *bmap, int start, int len)
{
int bit;
for (bit = start; bit < (start + len); bit++)
bmap[BIT_WORD(bit)] &= ~(0x1UL << BIT_WORD_OFFSET(bit));
}
static inline void bitmap_zero(unsigned long *dst, int nbits)
{
if (small_const_nbits(nbits))
*dst = 0UL;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = 0;
}
}
static inline int bitmap_test(unsigned long *bmap, int bit)
{
return __test_bit(bit, bmap);
}
static inline void bitmap_zero_except(unsigned long *dst,
int exception, int nbits)
{
if (small_const_nbits(nbits))
*dst = 0UL;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = 0;
}
if (exception < nbits)
__set_bit(exception, dst);
}
static inline void bitmap_fill(unsigned long *dst, int nbits)
{
size_t i, nlongs = BITS_TO_LONGS(nbits);
if (!small_const_nbits(nbits)) {
for (i = 0; i < (nlongs - 1); i++)
dst[i] = -1UL;
}
dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
}
static inline void bitmap_copy(unsigned long *dst,
const unsigned long *src, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src;
else {
size_t i, len = BITS_TO_LONGS(nbits);
for (i = 0; i < len; i++)
dst[i] = src[i];
}
}
static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 & *src2;
else
__bitmap_and(dst, src1, src2, nbits);
}
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 | *src2;
else
__bitmap_or(dst, src1, src2, nbits);
}
static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, int nbits)
{
if (small_const_nbits(nbits))
*dst = *src1 ^ *src2;
else
__bitmap_xor(dst, src1, src2, nbits);
}
static inline int bitmap_weight(const unsigned long *src, int nbits)
{
int i, res = 0;
for (i = 0; i < nbits / BITS_PER_LONG; i++)
res += sbi_popcount(src[i]);
if (nbits % BITS_PER_LONG)
res += sbi_popcount(src[i] & BITMAP_LAST_WORD_MASK(nbits));
return res;
}
#endif

View File

@ -4,46 +4,59 @@
* Copyright (c) 2019 Western Digital Corporation or its affiliates. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
* *
* Authors: * Authors:
* Atish Patra <atish.patra@wdc.com> * Atish Patra<atish.patra@wdc.com>
*/ */
#ifndef __SBI_BITOPS_H__ #ifndef __SBI_BITOPS_H__
#define __SBI_BITOPS_H__ #define __SBI_BITOPS_H__
#include <sbi/sbi_types.h> #include <sbi/sbi_bits.h>
#include <sbi/riscv_asm.h>
#define BITS_PER_LONG (8 * __SIZEOF_LONG__)
#define BITS_PER_LONG_LONG 64
#define EXTRACT_FIELD(val, which) \
(((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) \
(((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define BITS_TO_LONGS(nbits) (((nbits) + BITS_PER_LONG - 1) / \
BITS_PER_LONG)
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(bit) ((bit) / BITS_PER_LONG)
#define BIT_WORD_OFFSET(bit) ((bit) & (BITS_PER_LONG - 1))
#define BIT_ALIGN(bit, align) (((bit) + ((align) - 1)) & ~((align) - 1))
#define BIT_ULL(nr) (1ULL << (nr))
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
#define GENMASK_ULL(h, l) \
(((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
/** /**
* sbi_ffs - find first (less-significant) set bit in a long word. * ffs - Find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1)) {
x >>= 1;
r += 1;
}
return r;
}
/**
* __ffs - find first bit in word.
* @word: The word to search * @word: The word to search
* *
* Undefined if no bit exists, so code should check against 0 first. * Undefined if no bit exists, so code should check against 0 first.
*/ */
static inline int sbi_ffs(unsigned long word) static inline int __ffs(unsigned long word)
{ {
int num = 0; int num = 0;
@ -75,201 +88,11 @@ static inline int sbi_ffs(unsigned long word)
} }
/* /*
* sbi_ffz - find first zero in word. * ffz - find first zero in word.
* @word: The word to search * @word: The word to search
* *
* Undefined if no zero exists, so code should check against ~0UL first. * Undefined if no zero exists, so code should check against ~0UL first.
*/ */
#define sbi_ffz(x) sbi_ffs(~(x)) #define ffz(x) __ffs(~(x))
/**
* sbi_fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long sbi_fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;
#if BITS_PER_LONG == 64
if (!(word & (~0ul << 32))) {
num -= 32;
word <<= 32;
}
#endif
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
num -= 16;
word <<= 16;
}
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
num -= 8;
word <<= 8;
}
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
num -= 4;
word <<= 4;
}
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
num -= 2;
word <<= 2;
}
if (!(word & (~0ul << (BITS_PER_LONG-1))))
num -= 1;
return num;
}
/**
* sbi_popcount - find the number of set bit in a long word
* @word: the word to search
*/
static inline unsigned long sbi_popcount(unsigned long word)
{
unsigned long count;
#if BITS_PER_LONG == 64
count = word - ((word >> 1) & 0x5555555555555555ul);
count = (count & 0x3333333333333333ul) + ((count >> 2) & 0x3333333333333333ul);
count = (count + (count >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
count = count + (count >> 8);
count = count + (count >> 16);
return (count + (count >> 32)) & 0x00000000000000FFul;
#else
count = word - ((word >> 1) & 0x55555555);
count = (count & 0x33333333) + ((count >> 2) & 0x33333333);
count = (count + (count >> 4)) & 0x0F0F0F0F;
count = count + (count >> 8);
return (count + (count >> 16)) & 0x000000FF;
#endif
}
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
/* same as for_each_set_bit() but use bit as value to start with */
#define for_each_set_bit_from(bit, addr, size) \
for ((bit) = find_next_bit((addr), (size), (bit)); \
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
#define for_each_clear_bit(bit, addr, size) \
for ((bit) = find_first_zero_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
/* same as for_each_clear_bit() but use bit as value to start with */
#define for_each_clear_bit_from(bit, addr, size) \
for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
unsigned long find_first_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_first_zero_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_last_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset);
unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset);
/**
* __set_bit - Set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
/**
* __clear_bit - Clear a bit in memory
* @nr: the bit to clear
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p &= ~mask;
}
/**
* __change_bit - Toggle a bit in memory
* @nr: the bit to change
* @addr: the address to start counting from
*
* This function is non-atomic and may be reordered.
*/
static inline void __change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p ^= mask;
}
/**
* __test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old = *p;
*p = old | mask;
return (old & mask) != 0;
}
/**
* __test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to clear
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old = *p;
*p = old & ~mask;
return (old & mask) != 0;
}
/**
* __test_bit - Determine whether a bit is set
* @nr: bit number to test
* @addr: Address to start counting from
*
* This operation is non-atomic and can be reordered.
*/
static inline int __test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
#endif #endif

31
include/sbi/sbi_bits.h Normal file
View File

@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#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
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#endif

View File

@ -1,80 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*/
#ifndef __SBI_BYTEORDER_H__
#define __SBI_BYTEORDER_H__
#ifdef __ASSEMBLER__
# define _conv_cast(type, val) (val)
#else
# include <sbi/sbi_types.h>
# define _conv_cast(type, val) ((type)(val))
#endif
#define __BSWAP16(x) ((((x) & 0x00ff) << 8) | \
(((x) & 0xff00) >> 8))
#define __BSWAP32(x) ((((x) & 0x000000ff) << 24) | \
(((x) & 0x0000ff00) << 8) | \
(((x) & 0x00ff0000) >> 8) | \
(((x) & 0xff000000) >> 24))
#define __BSWAP64(x) ((((x) & 0x00000000000000ffULL) << 56) | \
(((x) & 0x000000000000ff00ULL) << 40) | \
(((x) & 0x0000000000ff0000ULL) << 24) | \
(((x) & 0x00000000ff000000ULL) << 8) | \
(((x) & 0x000000ff00000000ULL) >> 8) | \
(((x) & 0x0000ff0000000000ULL) >> 24) | \
(((x) & 0x00ff000000000000ULL) >> 40) | \
(((x) & 0xff00000000000000ULL) >> 56))
#define BSWAP64(x) ({ uint64_t _sv = (x); __BSWAP64(_sv); })
#define BSWAP32(x) ({ uint32_t _sv = (x); __BSWAP32(_sv); })
#define BSWAP16(x) ({ uint16_t _sv = (x); __BSWAP16(_sv); })
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ /* CPU(little-endian) */
#define cpu_to_be16(x) _conv_cast(uint16_t, BSWAP16(x))
#define cpu_to_be32(x) _conv_cast(uint32_t, BSWAP32(x))
#define cpu_to_be64(x) _conv_cast(uint64_t, BSWAP64(x))
#define be16_to_cpu(x) _conv_cast(uint16_t, BSWAP16(x))
#define be32_to_cpu(x) _conv_cast(uint32_t, BSWAP32(x))
#define be64_to_cpu(x) _conv_cast(uint64_t, BSWAP64(x))
#define cpu_to_le16(x) _conv_cast(uint16_t, (x))
#define cpu_to_le32(x) _conv_cast(uint32_t, (x))
#define cpu_to_le64(x) _conv_cast(uint64_t, (x))
#define le16_to_cpu(x) _conv_cast(uint16_t, (x))
#define le32_to_cpu(x) _conv_cast(uint32_t, (x))
#define le64_to_cpu(x) _conv_cast(uint64_t, (x))
#else /* CPU(big-endian) */
#define cpu_to_be16(x) _conv_cast(uint16_t, (x))
#define cpu_to_be32(x) _conv_cast(uint32_t, (x))
#define cpu_to_be64(x) _conv_cast(uint64_t, (x))
#define be16_to_cpu(x) _conv_cast(uint16_t, (x))
#define be32_to_cpu(x) _conv_cast(uint32_t, (x))
#define be64_to_cpu(x) _conv_cast(uint64_t, (x))
#define cpu_to_le16(x) _conv_cast(uint16_t, BSWAP16(x))
#define cpu_to_le32(x) _conv_cast(uint32_t, BSWAP32(x))
#define cpu_to_le64(x) _conv_cast(uint64_t, BSWAP64(x))
#define le16_to_cpu(x) _conv_cast(uint16_t, BSWAP16(x))
#define le32_to_cpu(x) _conv_cast(uint32_t, BSWAP32(x))
#define le64_to_cpu(x) _conv_cast(uint64_t, BSWAP64(x))
#endif
#if __riscv_xlen == 64
#define cpu_to_lle cpu_to_le64
#define lle_to_cpu le64_to_cpu
#elif __riscv_xlen == 32
#define cpu_to_lle cpu_to_le32
#define lle_to_cpu le32_to_cpu
#else
#error "Unknown __riscv_xlen"
#endif
#endif /* __SBI_BYTEORDER_H__ */

View File

@ -12,55 +12,26 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
struct sbi_console_device { #define __printf(a, b) __attribute__((format(printf, a, b)))
/** Name of the console device */
char name[32];
/** Write a character to the console output */
void (*console_putc)(char ch);
/** Write a character string to the console output */
unsigned long (*console_puts)(const char *str, unsigned long len);
/** Read a character from the console input */
int (*console_getc)(void);
};
#define __printf(a, b) __attribute__((format(printf, a, b)))
bool sbi_isprintable(char ch); bool sbi_isprintable(char ch);
int sbi_getc(void); char sbi_getc(void);
void sbi_putc(char ch); void sbi_putc(char ch);
void sbi_puts(const char *str); void sbi_puts(const char *str);
unsigned long sbi_nputs(const char *str, unsigned long len);
void sbi_gets(char *s, int maxwidth, char endchar); void sbi_gets(char *s, int maxwidth, char endchar);
unsigned long sbi_ngets(char *str, unsigned long len);
int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...); 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(3, 4) sbi_snprintf(char *out, u32 out_sz,
const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...); int __printf(1, 2) sbi_printf(const char *format, ...);
int __printf(1, 2) sbi_dprintf(const char *format, ...);
void __printf(1, 2) __attribute__((noreturn)) sbi_panic(const char *format, ...);
const struct sbi_console_device *sbi_console_get_device(void);
void sbi_console_set_device(const struct sbi_console_device *dev);
struct sbi_scratch; struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);
#define SBI_ASSERT(cond, args) do { \
if (unlikely(!(cond))) \
sbi_panic args; \
} while (0)
#endif #endif

View File

@ -10,8 +10,7 @@
#ifndef __SBI_CONST_H__ #ifndef __SBI_CONST_H__
#define __SBI_CONST_H__ #define __SBI_CONST_H__
/* /* Some constant macros are used in both assembler and
* Some constant macros are used in both assembler and
* C code. Therefore we cannot annotate them always with * C code. Therefore we cannot annotate them always with
* 'UL' and other type specifiers unilaterally. We * 'UL' and other type specifiers unilaterally. We
* use the following macros to deal with this. * use the following macros to deal with this.
@ -20,9 +19,7 @@
* leave it unchanged in asm. * leave it unchanged in asm.
*/ */
/* clang-format off */ #ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define _AC(X,Y) X #define _AC(X,Y) X
#define _AT(T,X) X #define _AT(T,X) X
#else #else
@ -40,9 +37,7 @@
#define UL(x) (_UL(x)) #define UL(x) (_UL(x))
#define ULL(x) (_ULL(x)) #define ULL(x) (_ULL(x))
#define __STR(s) #s #define __STR(s) #s
#define STRINGIFY(s) __STR(s) #define STRINGIFY(s) __STR(s)
/* clang-format on */
#endif #endif

View File

@ -1,35 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#ifndef __SBI_CPPC_H__
#define __SBI_CPPC_H__
#include <sbi/sbi_types.h>
/** CPPC device */
struct sbi_cppc_device {
/** Name of the CPPC device */
char name[32];
/** probe - returns register width if implemented, 0 otherwise */
int (*cppc_probe)(unsigned long reg);
/** read the cppc register*/
int (*cppc_read)(unsigned long reg, uint64_t *val);
/** write to the cppc register*/
int (*cppc_write)(unsigned long reg, uint64_t val);
};
int sbi_cppc_probe(unsigned long reg);
int sbi_cppc_read(unsigned long reg, uint64_t *val);
int sbi_cppc_write(unsigned long reg, uint64_t val);
const struct sbi_cppc_device *sbi_cppc_get_device(void);
void sbi_cppc_set_device(const struct sbi_cppc_device *dev);
#endif

View File

@ -1,53 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_CSR_DETECT__H
#define __SBI_CSR_DETECT__H
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#define csr_read_allowed(csr_num, trap) \
({ \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = (ulong)sbi_hart_expected_trap; \
register ulong ret = 0; \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrr %[ret], %[csr]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
[ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
: [csr] "i" (csr_num) \
: "memory"); \
ret; \
}) \
#define csr_write_allowed(csr_num, trap, value) \
({ \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = (ulong)sbi_hart_expected_trap; \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrw %[csr], %[val]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
: [csr] "i" (csr_num), [val] "r" (value) \
: "memory"); \
}) \
#endif

View File

@ -1,124 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems, Inc.
*
* Authors:
* Himanshu Chauhan <hchauhan@ventanamicro.com>
*/
#ifndef __SBI_DBTR_H__
#define __SBI_DBTR_H__
#include <sbi/riscv_dbtr.h>
#include <sbi/sbi_types.h>
struct sbi_domain;
enum {
RV_DBTR_DECLARE_BIT(TS, MAPPED, 0), /* trigger mapped to hw trigger */
RV_DBTR_DECLARE_BIT(TS, U, 1),
RV_DBTR_DECLARE_BIT(TS, S, 2),
RV_DBTR_DECLARE_BIT(TS, VU, 3),
RV_DBTR_DECLARE_BIT(TS, VS, 4),
RV_DBTR_DECLARE_BIT(TS, HAVE_TRIG, 5), /* H/w dbtr details available */
RV_DBTR_DECLARE_BIT(TS, HW_IDX, 8), /* Hardware index of trigger */
};
enum {
RV_DBTR_DECLARE_BIT_MASK(TS, MAPPED, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, U, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, S, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, VU, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, VS, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, HAVE_TRIG, 1),
RV_DBTR_DECLARE_BIT_MASK(TS, HW_IDX, (__riscv_xlen-9)),
};
#if __riscv_xlen == 64
#define SBI_DBTR_SHMEM_INVALID_ADDR 0xFFFFFFFFFFFFFFFFUL
#elif __riscv_xlen == 32
#define SBI_DBTR_SHMEM_INVALID_ADDR 0xFFFFFFFFUL
#else
#error "Unexpected __riscv_xlen"
#endif
struct sbi_dbtr_shmem {
unsigned long phys_lo;
unsigned long phys_hi;
};
struct sbi_dbtr_trigger {
unsigned long index;
unsigned long type_mask;
unsigned long state;
unsigned long tdata1;
unsigned long tdata2;
unsigned long tdata3;
};
struct sbi_dbtr_data_msg {
unsigned long tstate;
unsigned long tdata1;
unsigned long tdata2;
unsigned long tdata3;
};
struct sbi_dbtr_id_msg {
unsigned long idx;
};
struct sbi_dbtr_hart_triggers_state {
struct sbi_dbtr_trigger triggers[RV_MAX_TRIGGERS];
struct sbi_dbtr_shmem shmem;
u32 total_trigs;
u32 available_trigs;
u32 hartid;
u32 probed;
};
#define TDATA1_GET_TYPE(_t1) \
EXTRACT_FIELD(_t1, RV_DBTR_BIT_MASK(TDATA1, TYPE))
/* Set the hardware index of trigger in logical trigger state */
#define SET_TRIG_HW_INDEX(_state, _idx) \
do { \
_state &= ~RV_DBTR_BIT_MASK(TS, HW_IDX); \
_state |= (((unsigned long)_idx \
<< RV_DBTR_BIT(TS, HW_IDX)) \
& RV_DBTR_BIT_MASK(TS, HW_IDX)); \
}while (0);
/** SBI shared mem messages layout */
union sbi_dbtr_shmem_entry {
struct sbi_dbtr_data_msg data;
struct sbi_dbtr_id_msg id;
};
#define SBI_DBTR_SHMEM_ALIGN_MASK ((__riscv_xlen / 8) - 1)
/** Initialize debug triggers */
int sbi_dbtr_init(struct sbi_scratch *scratch, bool coldboot);
/** SBI DBTR extension functions */
int sbi_dbtr_supported(void);
int sbi_dbtr_setup_shmem(const struct sbi_domain *dom, unsigned long smode,
unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi);
int sbi_dbtr_num_trig(unsigned long trig_tdata1, unsigned long *out);
int sbi_dbtr_read_trig(unsigned long smode,
unsigned long trig_idx_base, unsigned long trig_count);
int sbi_dbtr_install_trig(unsigned long smode,
unsigned long trig_count, unsigned long *out);
int sbi_dbtr_uninstall_trig(unsigned long trig_idx_base,
unsigned long trig_idx_mask);
int sbi_dbtr_enable_trig(unsigned long trig_idx_base,
unsigned long trig_idx_mask);
int sbi_dbtr_update_trig(unsigned long smode,
unsigned long trig_count);
int sbi_dbtr_disable_trig(unsigned long trig_idx_base,
unsigned long trig_idx_mask);
int sbi_dbtr_get_total_triggers(void);
#endif

View File

@ -1,319 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_DOMAIN_H__
#define __SBI_DOMAIN_H__
#include <sbi/riscv_locks.h>
#include <sbi/sbi_list.h>
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_domain_context.h>
#include <sbi/sbi_domain_data.h>
struct sbi_scratch;
/** Domain access types */
enum sbi_domain_access {
SBI_DOMAIN_READ = (1UL << 0),
SBI_DOMAIN_WRITE = (1UL << 1),
SBI_DOMAIN_EXECUTE = (1UL << 2),
SBI_DOMAIN_MMIO = (1UL << 3)
};
/** Representation of OpenSBI domain memory region */
struct sbi_domain_memregion {
/**
* Size of memory region as power of 2
* It has to be minimum 3 and maximum __riscv_xlen
*/
unsigned long order;
/**
* Base address of memory region
* It must be 2^order aligned address
*/
unsigned long base;
/** Flags representing memory region attributes */
#define SBI_DOMAIN_MEMREGION_M_READABLE (1UL << 0)
#define SBI_DOMAIN_MEMREGION_M_WRITABLE (1UL << 1)
#define SBI_DOMAIN_MEMREGION_M_EXECUTABLE (1UL << 2)
#define SBI_DOMAIN_MEMREGION_SU_READABLE (1UL << 3)
#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4)
#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5)
#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL)
#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL)
#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3)
#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \
(SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE| \
SBI_DOMAIN_MEMREGION_SU_WRITABLE)
#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_READABLE)
/* Shared read-only region between M and SU mode */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_RDONLY)
/* Shared region: SU execute-only and M read/execute */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX)
/* Shared region: SU and M execute-only */
#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUX_MX)
/* Shared region: SU and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW)
/* Shared region: SU read-only and M read/write */
#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \
SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW)
/*
* Check if region flags match with any of the above
* mentioned shared region type
*/
#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \
(SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \
SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \
SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags))
#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK))
#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
/** Bit to control if permissions are enforced on all modes */
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
#define SBI_DOMAIN_MEMREGION_M_RWX \
(SBI_DOMAIN_MEMREGION_M_READABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_SU_RWX \
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
/* Unrestricted M-mode accesses but enfoced on SU-mode */
#define SBI_DOMAIN_MEMREGION_READABLE \
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
SBI_DOMAIN_MEMREGION_M_RWX)
#define SBI_DOMAIN_MEMREGION_WRITEABLE \
(SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
SBI_DOMAIN_MEMREGION_M_RWX)
#define SBI_DOMAIN_MEMREGION_EXECUTABLE \
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_M_RWX)
/* Enforced accesses across all modes */
#define SBI_DOMAIN_MEMREGION_ENF_READABLE \
(SBI_DOMAIN_MEMREGION_SU_READABLE | \
SBI_DOMAIN_MEMREGION_M_READABLE)
#define SBI_DOMAIN_MEMREGION_ENF_WRITABLE \
(SBI_DOMAIN_MEMREGION_SU_WRITABLE | \
SBI_DOMAIN_MEMREGION_M_WRITABLE)
#define SBI_DOMAIN_MEMREGION_ENF_EXECUTABLE \
(SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
unsigned long flags;
};
/** Representation of OpenSBI domain */
struct sbi_domain {
/** Node in linked list of domains */
struct sbi_dlist node;
/** Internal state of per-domain data */
struct sbi_domain_data_priv data_priv;
/** Logical index of this domain */
u32 index;
/** HARTs assigned to this domain */
struct sbi_hartmask assigned_harts;
/** Spinlock for accessing assigned_harts */
spinlock_t assigned_harts_lock;
/** Name of this domain */
char name[64];
/** Possible HARTs in this domain */
const struct sbi_hartmask *possible_harts;
/** Array of memory regions terminated by a region with order zero */
struct sbi_domain_memregion *regions;
/** HART id of the HART booting this domain */
u32 boot_hartid;
/** Arg1 (or 'a1' register) of next booting stage for this domain */
unsigned long next_arg1;
/** Address of next booting stage for this domain */
unsigned long next_addr;
/** Privilege mode of next booting stage for this domain */
unsigned long next_mode;
/** Is domain allowed to reset the system */
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
/** Identifies whether to include the firmware region */
bool fw_region_inited;
};
/** The root domain instance */
extern struct sbi_domain root;
/** Get pointer to sbi_domain from HART index */
struct sbi_domain *sbi_hartindex_to_domain(u32 hartindex);
/** Update HART local pointer to point to specified domain */
void sbi_update_hartindex_to_domain(u32 hartindex, struct sbi_domain *dom);
/** Get pointer to sbi_domain for current HART */
#define sbi_domain_thishart_ptr() \
sbi_hartindex_to_domain(current_hartindex())
/** Head of linked list of domains */
extern struct sbi_dlist domain_list;
/** Iterate over each domain */
#define sbi_domain_for_each(__d) \
sbi_list_for_each_entry(__d, &domain_list, node)
/** Iterate over each memory region of a domain */
#define sbi_domain_for_each_memregion(__d, __r) \
for ((__r) = (__d)->regions; (__r)->order; (__r)++)
/**
* Check whether given HART is assigned to specified domain
* @param dom pointer to domain
* @param hartindex the HART index
* @return true if HART is assigned to domain otherwise false
*/
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartindex);
/**
* Get the assigned HART mask for given domain
* @param dom pointer to domain
* @param mask the output hartmask to fill
* @return 0 on success and SBI_Exxx (< 0) on failure
*/
int sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
struct sbi_hartmask *mask);
/**
* Initialize a domain memory region based on it's physical
* address and size.
*
* @param addr start physical address of memory region
* @param size physical size of memory region
* @param flags memory region flags
* @param reg pointer to memory region being initialized
*/
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
struct sbi_domain_memregion *reg);
/**
* Check whether we can access specified address for given mode and
* memory region flags under a domain
* @param dom pointer to domain
* @param addr the address to be checked
* @param mode the privilege mode of access
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
* @return true if access allowed otherwise false
*/
bool sbi_domain_check_addr(const struct sbi_domain *dom,
unsigned long addr, unsigned long mode,
unsigned long access_flags);
/**
* Check whether we can access specified address range for given mode and
* memory region flags under a domain
* @param dom pointer to domain
* @param addr the start of the address range to be checked
* @param size the size of the address range to be checked
* @param mode the privilege mode of access
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
* @return TRUE if access allowed otherwise FALSE
*/
bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
unsigned long addr, unsigned long size,
unsigned long mode,
unsigned long access_flags);
/** Dump domain details on the console */
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
/** Dump all domain details on the console */
void sbi_domain_dump_all(const char *suffix);
/**
* Register a new domain
* @param dom pointer to domain
* @param assign_mask pointer to HART mask of HARTs assigned to the domain
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_register(struct sbi_domain *dom,
const struct sbi_hartmask *assign_mask);
/**
* Add a memory range with its flags to the root domain
* @param addr start physical address of memory range
* @param size physical size of memory range
* @param align alignment of memory region
* @param region_flags memory range flags
*
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with the existing one
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags);
/** Startup non-root domains */
int sbi_domain_startup(struct sbi_scratch *scratch, u32 cold_hartid);
/** Finalize domain tables */
int sbi_domain_finalize(struct sbi_scratch *scratch);
/** Initialize domains */
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid);
#endif

View File

@ -1,41 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) IPADS@SJTU 2023. All rights reserved.
*/
#ifndef __SBI_DOMAIN_CONTEXT_H__
#define __SBI_DOMAIN_CONTEXT_H__
#include <sbi/sbi_types.h>
struct sbi_domain;
/**
* Enter a specific domain context synchronously
* @param dom pointer to domain
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_context_enter(struct sbi_domain *dom);
/**
* Exit the current domain context, and then return to the caller
* of sbi_domain_context_enter or attempt to start the next domain
* context to be initialized
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_context_exit(void);
/**
* Initialize domain context support
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_context_init(void);
/* Deinitialize domain context support */
void sbi_domain_context_deinit(void);
#endif // __SBI_DOMAIN_CONTEXT_H__

View File

@ -1,93 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*/
#ifndef __SBI_DOMAIN_DATA_H__
#define __SBI_DOMAIN_DATA_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
struct sbi_domain;
/** Maximum domain data per-domain */
#define SBI_DOMAIN_MAX_DATA_PTRS 32
/** Representation of per-domain data */
struct sbi_domain_data_priv {
/** Array of domain data pointers indexed by domain data identifier */
void *idx_to_data_ptr[SBI_DOMAIN_MAX_DATA_PTRS];
};
/** Representation of a domain data */
struct sbi_domain_data {
/**
* Head is used for maintaining data list
*
* Note: initialized by domain framework
*/
struct sbi_dlist head;
/**
* Identifier which used to locate per-domain data
*
* Note: initialized by domain framework
*/
unsigned long data_idx;
/** Size of per-domain data */
unsigned long data_size;
/** Optional callback to setup domain data */
int (*data_setup)(struct sbi_domain *dom,
struct sbi_domain_data *data, void *data_ptr);
/** Optional callback to cleanup domain data */
void (*data_cleanup)(struct sbi_domain *dom,
struct sbi_domain_data *data, void *data_ptr);
};
/**
* Get per-domain data pointer for a given domain
* @param dom pointer to domain
* @param data pointer to domain data
*
* @return per-domain data pointer
*/
void *sbi_domain_data_ptr(struct sbi_domain *dom, struct sbi_domain_data *data);
/**
* Setup all domain data for a domain
* @param dom pointer to domain
*
* @return 0 on success and negative error code on failure
*
* Note: This function is used internally within domain framework.
*/
int sbi_domain_setup_data(struct sbi_domain *dom);
/**
* Cleanup all domain data for a domain
* @param dom pointer to domain
*
* Note: This function is used internally within domain framework.
*/
void sbi_domain_cleanup_data(struct sbi_domain *dom);
/**
* Register a domain data
* @param hndl pointer to domain data
*
* @return 0 on success and negative error code on failure
*
* Note: This function must be used only in cold boot path.
*/
int sbi_domain_register_data(struct sbi_domain_data *data);
/**
* Unregister a domain data
* @param hndl pointer to domain data
*
* Note: This function must be used only in cold boot path.
*/
void sbi_domain_unregister_data(struct sbi_domain_data *data);
#endif

View File

@ -1,20 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Rivos Inc.
*
* Authors:
* Clément Léger <cleger@rivosinc.com>
*/
#ifndef __SBI_DOUBLE_TRAP_H__
#define __SBI_DOUBLE_TRAP_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_trap.h>
int sbi_double_trap_handler(struct sbi_trap_context *tcntx);
void sbi_double_trap_init(struct sbi_scratch *scratch);
#endif

View File

@ -11,90 +11,16 @@
#define __SBI_ECALL_H__ #define __SBI_ECALL_H__
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 3
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs; struct sbi_trap_regs;
struct sbi_trap_context; struct sbi_scratch;
struct sbi_ecall_return {
/* Return flag to skip register update */
bool skip_regs_update;
/* Return value */
unsigned long value;
};
struct sbi_ecall_extension {
/* head is used by the extension list */
struct sbi_dlist head;
/* short name of the extension */
char name[8];
/*
* extid_start and extid_end specify the range for this extension. As
* the initial range may be wider than the valid runtime range, the
* register_extensions callback is responsible for narrowing the range
* before other callbacks may be invoked.
*/
unsigned long extid_start;
unsigned long extid_end;
/* flag showing whether given extension is experimental or not */
bool experimental;
/*
* register_extensions
*
* Calls sbi_ecall_register_extension() one or more times to register
* extension ID range(s) which should be handled by this extension.
* More than one sbi_ecall_extension struct and
* sbi_ecall_register_extension() call is necessary when the supported
* extension ID ranges have gaps. Additionally, extension availability
* must be checked before registering, which means, when this callback
* returns, only valid extension IDs from the initial range, which are
* also available, have been registered.
*/
int (* register_extensions)(void);
/*
* probe
*
* Implements the Base extension's probe function for the extension. As
* the register_extensions callback ensures that no other extension
* callbacks will be invoked when the extension is not available, then
* probe can never fail. However, an extension may choose to set
* out_val to a nonzero value other than one. In those cases, it should
* implement this callback.
*/
int (* probe)(unsigned long extid, unsigned long *out_val);
/*
* handle
*
* This is the extension handler. register_extensions ensures it is
* never invoked with an invalid or unavailable extension ID.
*/
int (* handle)(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
};
u16 sbi_ecall_version_major(void); u16 sbi_ecall_version_major(void);
u16 sbi_ecall_version_minor(void); u16 sbi_ecall_version_minor(void);
unsigned long sbi_ecall_get_impid(void); int sbi_ecall_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
void sbi_ecall_set_impid(unsigned long impid); struct sbi_scratch *scratch);
struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid);
void sbi_ecall_get_extensions_str(char *exts_str, int exts_str_size, bool experimental);
int sbi_ecall_register_extension(struct sbi_ecall_extension *ext);
void sbi_ecall_unregister_extension(struct sbi_ecall_extension *ext);
int sbi_ecall_handler(struct sbi_trap_context *tcntx);
int sbi_ecall_init(void);
#endif #endif

View File

@ -10,486 +10,39 @@
#ifndef __SBI_ECALL_INTERFACE_H__ #ifndef __SBI_ECALL_INTERFACE_H__
#define __SBI_ECALL_INTERFACE_H__ #define __SBI_ECALL_INTERFACE_H__
/* clang-format off */ #define SBI_ECALL_SET_TIMER 0
#define SBI_ECALL_CONSOLE_PUTCHAR 1
#include <sbi/sbi_types.h> #define SBI_ECALL_CONSOLE_GETCHAR 2
#define SBI_ECALL_CLEAR_IPI 3
/* SBI Extension IDs */ #define SBI_ECALL_SEND_IPI 4
#define SBI_EXT_0_1_SET_TIMER 0x0 #define SBI_ECALL_REMOTE_FENCE_I 5
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1 #define SBI_ECALL_REMOTE_SFENCE_VMA 6
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2 #define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
#define SBI_EXT_0_1_CLEAR_IPI 0x3 #define SBI_ECALL_SHUTDOWN 8
#define SBI_EXT_0_1_SEND_IPI 0x4
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5 #define SBI_ECALL(__num, __a0, __a1, __a2) ({ \
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6 register unsigned long a0 asm ("a0") = (unsigned long)(__a0); \
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7 register unsigned long a1 asm ("a1") = (unsigned long)(__a1); \
#define SBI_EXT_0_1_SHUTDOWN 0x8 register unsigned long a2 asm ("a2") = (unsigned long)(__a2); \
#define SBI_EXT_BASE 0x10 register unsigned long a7 asm ("a7") = (unsigned long)(__num); \
#define SBI_EXT_TIME 0x54494D45 asm volatile ("ecall" \
#define SBI_EXT_IPI 0x735049 : "+r" (a0) \
#define SBI_EXT_RFENCE 0x52464E43 : "r" (a1), "r" (a2), "r" (a7) \
#define SBI_EXT_HSM 0x48534D : "memory"); \
#define SBI_EXT_SRST 0x53525354 a0; \
#define SBI_EXT_PMU 0x504D55 })
#define SBI_EXT_DBCN 0x4442434E
#define SBI_EXT_SUSP 0x53555350 #define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
#define SBI_EXT_CPPC 0x43505043 #define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_EXT_DBTR 0x44425452 #define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define SBI_EXT_SSE 0x535345
#define SBI_EXT_FWFT 0x46574654 #define sbi_ecall_console_putc(c) \
#define SBI_EXT_MPXY 0x4D505859 SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
/* SBI function IDs for BASE extension*/ static inline void sbi_ecall_console_puts(const char *str)
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 {
#define SBI_EXT_BASE_GET_IMP_ID 0x1 while (str && *str)
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2 sbi_ecall_console_putc(*str++);
#define SBI_EXT_BASE_PROBE_EXT 0x3 }
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
/* SBI function IDs for IPI extension*/
#define SBI_EXT_IPI_SEND_IPI 0x0
/* SBI function IDs for RFENCE extension*/
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x6
/* SBI function IDs for HSM extension */
#define SBI_EXT_HSM_HART_START 0x0
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
#define SBI_EXT_HSM_HART_SUSPEND 0x3
#define SBI_HSM_STATE_STARTED 0x0
#define SBI_HSM_STATE_STOPPED 0x1
#define SBI_HSM_STATE_START_PENDING 0x2
#define SBI_HSM_STATE_STOP_PENDING 0x3
#define SBI_HSM_STATE_SUSPENDED 0x4
#define SBI_HSM_STATE_SUSPEND_PENDING 0x5
#define SBI_HSM_STATE_RESUME_PENDING 0x6
#define SBI_HSM_SUSP_BASE_MASK 0x7fffffff
#define SBI_HSM_SUSP_NON_RET_BIT 0x80000000
#define SBI_HSM_SUSP_PLAT_BASE 0x10000000
#define SBI_HSM_SUSPEND_RET_DEFAULT 0x00000000
#define SBI_HSM_SUSPEND_RET_PLATFORM SBI_HSM_SUSP_PLAT_BASE
#define SBI_HSM_SUSPEND_RET_LAST SBI_HSM_SUSP_BASE_MASK
#define SBI_HSM_SUSPEND_NON_RET_DEFAULT SBI_HSM_SUSP_NON_RET_BIT
#define SBI_HSM_SUSPEND_NON_RET_PLATFORM (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_PLAT_BASE)
#define SBI_HSM_SUSPEND_NON_RET_LAST (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_BASE_MASK)
/* SBI function IDs for SRST extension */
#define SBI_EXT_SRST_RESET 0x0
#define SBI_SRST_RESET_TYPE_SHUTDOWN 0x0
#define SBI_SRST_RESET_TYPE_COLD_REBOOT 0x1
#define SBI_SRST_RESET_TYPE_WARM_REBOOT 0x2
#define SBI_SRST_RESET_TYPE_LAST SBI_SRST_RESET_TYPE_WARM_REBOOT
#define SBI_SRST_RESET_REASON_NONE 0x0
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
/* SBI function IDs for PMU extension */
#define SBI_EXT_PMU_NUM_COUNTERS 0x0
#define SBI_EXT_PMU_COUNTER_GET_INFO 0x1
#define SBI_EXT_PMU_COUNTER_CFG_MATCH 0x2
#define SBI_EXT_PMU_COUNTER_START 0x3
#define SBI_EXT_PMU_COUNTER_STOP 0x4
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
#define SBI_EXT_PMU_COUNTER_FW_READ_HI 0x6
#define SBI_EXT_PMU_SNAPSHOT_SET_SHMEM 0x7
#define SBI_EXT_PMU_EVENT_GET_INFO 0x8
/* SBI function IDs for DBTR extension */
#define SBI_EXT_DBTR_NUM_TRIGGERS 0x0
#define SBI_EXT_DBTR_SETUP_SHMEM 0x1
#define SBI_EXT_DBTR_TRIGGER_READ 0x2
#define SBI_EXT_DBTR_TRIGGER_INSTALL 0x3
#define SBI_EXT_DBTR_TRIGGER_UPDATE 0x4
#define SBI_EXT_DBTR_TRIGGER_UNINSTALL 0x5
#define SBI_EXT_DBTR_TRIGGER_ENABLE 0x6
#define SBI_EXT_DBTR_TRIGGER_DISABLE 0x7
/* SBI function IDs for FW feature extension */
#define SBI_EXT_FWFT_SET 0x0
#define SBI_EXT_FWFT_GET 0x1
enum sbi_fwft_feature_t {
SBI_FWFT_MISALIGNED_EXC_DELEG = 0x0,
SBI_FWFT_LANDING_PAD = 0x1,
SBI_FWFT_SHADOW_STACK = 0x2,
SBI_FWFT_DOUBLE_TRAP = 0x3,
SBI_FWFT_PTE_AD_HW_UPDATING = 0x4,
SBI_FWFT_POINTER_MASKING_PMLEN = 0x5,
SBI_FWFT_LOCAL_RESERVED_START = 0x6,
SBI_FWFT_LOCAL_RESERVED_END = 0x3fffffff,
SBI_FWFT_LOCAL_PLATFORM_START = 0x40000000,
SBI_FWFT_LOCAL_PLATFORM_END = 0x7fffffff,
SBI_FWFT_GLOBAL_RESERVED_START = 0x80000000,
SBI_FWFT_GLOBAL_RESERVED_END = 0xbfffffff,
SBI_FWFT_GLOBAL_PLATFORM_START = 0xc0000000,
SBI_FWFT_GLOBAL_PLATFORM_END = 0xffffffff,
};
#define SBI_FWFT_GLOBAL_FEATURE_BIT (1 << 31)
#define SBI_FWFT_PLATFORM_FEATURE_BIT (1 << 30)
#define SBI_FWFT_SET_FLAG_LOCK (1 << 0)
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
SBI_PMU_HW_NO_EVENT = 0,
SBI_PMU_HW_CPU_CYCLES = 1,
SBI_PMU_HW_INSTRUCTIONS = 2,
SBI_PMU_HW_CACHE_REFERENCES = 3,
SBI_PMU_HW_CACHE_MISSES = 4,
SBI_PMU_HW_BRANCH_INSTRUCTIONS = 5,
SBI_PMU_HW_BRANCH_MISSES = 6,
SBI_PMU_HW_BUS_CYCLES = 7,
SBI_PMU_HW_STALLED_CYCLES_FRONTEND = 8,
SBI_PMU_HW_STALLED_CYCLES_BACKEND = 9,
SBI_PMU_HW_REF_CPU_CYCLES = 10,
SBI_PMU_HW_GENERAL_MAX,
};
/**
* Generalized hardware cache events:
*
* { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
* { read, write, prefetch } x
* { accesses, misses }
*/
enum sbi_pmu_hw_cache_id {
SBI_PMU_HW_CACHE_L1D = 0,
SBI_PMU_HW_CACHE_L1I = 1,
SBI_PMU_HW_CACHE_LL = 2,
SBI_PMU_HW_CACHE_DTLB = 3,
SBI_PMU_HW_CACHE_ITLB = 4,
SBI_PMU_HW_CACHE_BPU = 5,
SBI_PMU_HW_CACHE_NODE = 6,
SBI_PMU_HW_CACHE_MAX,
};
enum sbi_pmu_hw_cache_op_id {
SBI_PMU_HW_CACHE_OP_READ = 0,
SBI_PMU_HW_CACHE_OP_WRITE = 1,
SBI_PMU_HW_CACHE_OP_PREFETCH = 2,
SBI_PMU_HW_CACHE_OP_MAX,
};
enum sbi_pmu_hw_cache_op_result_id {
SBI_PMU_HW_CACHE_RESULT_ACCESS = 0,
SBI_PMU_HW_CACHE_RESULT_MISS = 1,
SBI_PMU_HW_CACHE_RESULT_MAX,
};
/**
* Special "firmware" events provided by the OpenSBI, even if the hardware
* does not support performance events. These events are encoded as a raw
* event type in Linux kernel perf framework.
*/
enum sbi_pmu_fw_event_code_id {
SBI_PMU_FW_MISALIGNED_LOAD = 0,
SBI_PMU_FW_MISALIGNED_STORE = 1,
SBI_PMU_FW_ACCESS_LOAD = 2,
SBI_PMU_FW_ACCESS_STORE = 3,
SBI_PMU_FW_ILLEGAL_INSN = 4,
SBI_PMU_FW_SET_TIMER = 5,
SBI_PMU_FW_IPI_SENT = 6,
SBI_PMU_FW_IPI_RECVD = 7,
SBI_PMU_FW_FENCE_I_SENT = 8,
SBI_PMU_FW_FENCE_I_RECVD = 9,
SBI_PMU_FW_SFENCE_VMA_SENT = 10,
SBI_PMU_FW_SFENCE_VMA_RCVD = 11,
SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12,
SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13,
SBI_PMU_FW_HFENCE_GVMA_SENT = 14,
SBI_PMU_FW_HFENCE_GVMA_RCVD = 15,
SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16,
SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17,
SBI_PMU_FW_HFENCE_VVMA_SENT = 18,
SBI_PMU_FW_HFENCE_VVMA_RCVD = 19,
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
SBI_PMU_FW_MAX,
/*
* Event codes 22 to 255 are reserved for future use.
* Event codes 256 to 65534 are reserved for SBI implementation
* specific custom firmware events.
*/
SBI_PMU_FW_RESERVED_MAX = 0xFFFE,
/*
* Event code 0xFFFF is used for platform specific firmware
* events where the event data contains any event specific information.
*/
SBI_PMU_FW_PLATFORM = 0xFFFF,
};
/** SBI PMU event idx type */
enum sbi_pmu_event_type_id {
SBI_PMU_EVENT_TYPE_HW = 0x0,
SBI_PMU_EVENT_TYPE_HW_CACHE = 0x1,
SBI_PMU_EVENT_TYPE_HW_RAW = 0x2,
SBI_PMU_EVENT_TYPE_HW_RAW_V2 = 0x3,
SBI_PMU_EVENT_TYPE_FW = 0xf,
SBI_PMU_EVENT_TYPE_MAX,
};
/** SBI PMU counter type */
enum sbi_pmu_ctr_type {
SBI_PMU_CTR_TYPE_HW = 0,
SBI_PMU_CTR_TYPE_FW,
};
struct sbi_pmu_event_info {
uint32_t event_idx;
uint32_t output;
uint64_t event_data;
};
/* Helper macros to decode event idx */
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
#define SBI_PMU_EVENT_IDX_TYPE_OFFSET 16
#define SBI_PMU_EVENT_IDX_TYPE_MASK (0xF << SBI_PMU_EVENT_IDX_TYPE_OFFSET)
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
#define SBI_PMU_EVENT_RAW_IDX 0x20000
#define SBI_PMU_EVENT_RAW_V2_IDX 0x30000
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
#define SBI_PMU_EVENT_HW_CACHE_OPS_RESULT 0x1
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK 0x6
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET 1
#define SBI_PMU_EVENT_HW_CACHE_ID_MASK 0xfff8
#define SBI_PMU_EVENT_HW_CACHE_ID_OFFSET 3
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2)
#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3)
#define SBI_PMU_CFG_FLAG_SET_VSINH (1 << 4)
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
/* Flags defined for counter start function */
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
#define SBI_PMU_START_FLAG_INIT_FROM_SNAPSHOT (1 << 1)
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
#define SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT (1 << 1)
/* SBI function IDs for DBCN extension */
#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0
#define SBI_EXT_DBCN_CONSOLE_READ 0x1
#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2
/* SBI function IDs for SUSP extension */
#define SBI_EXT_SUSP_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
/* SBI function IDs for CPPC extension */
#define SBI_EXT_CPPC_PROBE 0x0
#define SBI_EXT_CPPC_READ 0x1
#define SBI_EXT_CPPC_READ_HI 0x2
#define SBI_EXT_CPPC_WRITE 0x3
enum sbi_cppc_reg_id {
SBI_CPPC_HIGHEST_PERF = 0x00000000,
SBI_CPPC_NOMINAL_PERF = 0x00000001,
SBI_CPPC_LOW_NON_LINEAR_PERF = 0x00000002,
SBI_CPPC_LOWEST_PERF = 0x00000003,
SBI_CPPC_GUARANTEED_PERF = 0x00000004,
SBI_CPPC_DESIRED_PERF = 0x00000005,
SBI_CPPC_MIN_PERF = 0x00000006,
SBI_CPPC_MAX_PERF = 0x00000007,
SBI_CPPC_PERF_REDUC_TOLERANCE = 0x00000008,
SBI_CPPC_TIME_WINDOW = 0x00000009,
SBI_CPPC_CTR_WRAP_TIME = 0x0000000A,
SBI_CPPC_REFERENCE_CTR = 0x0000000B,
SBI_CPPC_DELIVERED_CTR = 0x0000000C,
SBI_CPPC_PERF_LIMITED = 0x0000000D,
SBI_CPPC_ENABLE = 0x0000000E,
SBI_CPPC_AUTO_SEL_ENABLE = 0x0000000F,
SBI_CPPC_AUTO_ACT_WINDOW = 0x00000010,
SBI_CPPC_ENERGY_PERF_PREFERENCE = 0x00000011,
SBI_CPPC_REFERENCE_PERF = 0x00000012,
SBI_CPPC_LOWEST_FREQ = 0x00000013,
SBI_CPPC_NOMINAL_FREQ = 0x00000014,
SBI_CPPC_ACPI_LAST = SBI_CPPC_NOMINAL_FREQ,
SBI_CPPC_TRANSITION_LATENCY = 0x80000000,
SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY,
};
/* SBI Function IDs for SSE extension */
#define SBI_EXT_SSE_READ_ATTR 0x00000000
#define SBI_EXT_SSE_WRITE_ATTR 0x00000001
#define SBI_EXT_SSE_REGISTER 0x00000002
#define SBI_EXT_SSE_UNREGISTER 0x00000003
#define SBI_EXT_SSE_ENABLE 0x00000004
#define SBI_EXT_SSE_DISABLE 0x00000005
#define SBI_EXT_SSE_COMPLETE 0x00000006
#define SBI_EXT_SSE_INJECT 0x00000007
#define SBI_EXT_SSE_HART_UNMASK 0x00000008
#define SBI_EXT_SSE_HART_MASK 0x00000009
/* SBI SSE Event Attributes. */
enum sbi_sse_attr_id {
SBI_SSE_ATTR_STATUS = 0x00000000,
SBI_SSE_ATTR_PRIO = 0x00000001,
SBI_SSE_ATTR_CONFIG = 0x00000002,
SBI_SSE_ATTR_PREFERRED_HART = 0x00000003,
SBI_SSE_ATTR_ENTRY_PC = 0x00000004,
SBI_SSE_ATTR_ENTRY_ARG = 0x00000005,
SBI_SSE_ATTR_INTERRUPTED_SEPC = 0x00000006,
SBI_SSE_ATTR_INTERRUPTED_FLAGS = 0x00000007,
SBI_SSE_ATTR_INTERRUPTED_A6 = 0x00000008,
SBI_SSE_ATTR_INTERRUPTED_A7 = 0x00000009,
SBI_SSE_ATTR_MAX = 0x0000000A
};
#define SBI_SSE_ATTR_STATUS_STATE_OFFSET 0
#define SBI_SSE_ATTR_STATUS_STATE_MASK 0x3
#define SBI_SSE_ATTR_STATUS_PENDING_OFFSET 2
#define SBI_SSE_ATTR_STATUS_INJECT_OFFSET 3
#define SBI_SSE_ATTR_CONFIG_ONESHOT (1 << 0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP BIT(0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE BIT(1)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPV BIT(2)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP BIT(3)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPELP BIT(4)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SDT BIT(5)
enum sbi_sse_state {
SBI_SSE_STATE_UNUSED = 0,
SBI_SSE_STATE_REGISTERED = 1,
SBI_SSE_STATE_ENABLED = 2,
SBI_SSE_STATE_RUNNING = 3,
};
/* SBI SSE Event IDs. */
/* Range 0x00000000 - 0x0000ffff */
#define SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS 0x00000000
#define SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP 0x00000001
#define SBI_SSE_EVENT_LOCAL_RESERVED_0_START 0x00000002
#define SBI_SSE_EVENT_LOCAL_RESERVED_0_END 0x00003fff
#define SBI_SSE_EVENT_LOCAL_PLAT_0_START 0x00004000
#define SBI_SSE_EVENT_LOCAL_PLAT_0_END 0x00007fff
#define SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS 0x00008000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_0_START 0x00008001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_0_END 0x0000bfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_START 0x0000c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_END 0x0000ffff
/* Range 0x00010000 - 0x0001ffff */
#define SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW 0x00010000
#define SBI_SSE_EVENT_LOCAL_RESERVED_1_START 0x00010001
#define SBI_SSE_EVENT_LOCAL_RESERVED_1_END 0x00013fff
#define SBI_SSE_EVENT_LOCAL_PLAT_1_START 0x00014000
#define SBI_SSE_EVENT_LOCAL_PLAT_1_END 0x00017fff
#define SBI_SSE_EVENT_GLOBAL_RESERVED_1_START 0x00018000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_1_END 0x0001bfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_START 0x0001c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_END 0x0001ffff
/* Range 0x00100000 - 0x0010ffff */
#define SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS 0x00100000
#define SBI_SSE_EVENT_LOCAL_RESERVED_2_START 0x00100001
#define SBI_SSE_EVENT_LOCAL_RESERVED_2_END 0x00103fff
#define SBI_SSE_EVENT_LOCAL_PLAT_2_START 0x00104000
#define SBI_SSE_EVENT_LOCAL_PLAT_2_END 0x00107fff
#define SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS 0x00108000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_2_START 0x00108001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_2_END 0x0010bfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_START 0x0010c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_END 0x0010ffff
/* Range 0xffff0000 - 0xffffffff */
#define SBI_SSE_EVENT_LOCAL_SOFTWARE 0xffff0000
#define SBI_SSE_EVENT_LOCAL_RESERVED_3_START 0xffff0001
#define SBI_SSE_EVENT_LOCAL_RESERVED_3_END 0xffff3fff
#define SBI_SSE_EVENT_LOCAL_PLAT_3_START 0xffff4000
#define SBI_SSE_EVENT_LOCAL_PLAT_3_END 0xffff7fff
#define SBI_SSE_EVENT_GLOBAL_SOFTWARE 0xffff8000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_3_START 0xffff8001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_3_END 0xffffbfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_START 0xffffc000
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_END 0xffffffff
#define SBI_SSE_EVENT_GLOBAL_BIT BIT(15)
#define SBI_SSE_EVENT_PLATFORM_BIT BIT(14)
/* SBI function IDs for MPXY extension */
#define SBI_EXT_MPXY_GET_SHMEM_SIZE 0x0
#define SBI_EXT_MPXY_SET_SHMEM 0x1
#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x2
#define SBI_EXT_MPXY_READ_ATTRS 0x3
#define SBI_EXT_MPXY_WRITE_ATTRS 0x4
#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x5
#define SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP 0x6
#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x7
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_EXPERIMENTAL_START 0x08000000
#define SBI_EXT_EXPERIMENTAL_END 0x08FFFFFF
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
#define SBI_EXT_FIRMWARE_START 0x0A000000
#define SBI_EXT_FIRMWARE_END 0x0AFFFFFF
/* SBI return error codes */
#define SBI_SUCCESS 0
#define SBI_ERR_FAILED -1
#define SBI_ERR_NOT_SUPPORTED -2
#define SBI_ERR_INVALID_PARAM -3
#define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_ERR_NO_SHMEM -9
#define SBI_ERR_INVALID_STATE -10
#define SBI_ERR_BAD_RANGE -11
#define SBI_ERR_TIMEOUT -12
#define SBI_ERR_IO -13
#define SBI_ERR_DENIED_LOCKED -14
#define SBI_LAST_ERR SBI_ERR_DENIED_LOCKED
/* clang-format on */
#endif #endif

View File

@ -12,12 +12,16 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
struct sbi_trap_regs; struct sbi_scratch;
int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs, int sbi_emulate_csr_read(int csr_num,
u32 hartid, ulong mstatus,
struct sbi_scratch *scratch,
ulong *csr_val); ulong *csr_val);
int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs, int sbi_emulate_csr_write(int csr_num,
u32 hartid, ulong mstatus,
struct sbi_scratch *scratch,
ulong csr_val); ulong csr_val);
#endif #endif

View File

@ -10,35 +10,16 @@
#ifndef __SBI_ERROR_H__ #ifndef __SBI_ERROR_H__
#define __SBI_ERROR_H__ #define __SBI_ERROR_H__
#include <sbi/sbi_ecall_interface.h> #define SBI_OK 0
#define SBI_EUNKNOWN -1
/* clang-format off */ #define SBI_EFAIL -2
#define SBI_EINVAL -3
#define SBI_OK 0 #define SBI_ENOENT -4
#define SBI_EFAIL SBI_ERR_FAILED #define SBI_ENOTSUPP -5
#define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED #define SBI_ENODEV -6
#define SBI_EINVAL SBI_ERR_INVALID_PARAM #define SBI_ENOSYS -7
#define SBI_EDENIED SBI_ERR_DENIED #define SBI_ETIMEDOUT -8
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS #define SBI_EIO -9
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE #define SBI_EILL -10
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
#define SBI_ENO_SHMEM SBI_ERR_NO_SHMEM
#define SBI_EINVALID_STATE SBI_ERR_INVALID_STATE
#define SBI_EBAD_RANGE SBI_ERR_BAD_RANGE
#define SBI_ETIMEOUT SBI_ERR_TIMEOUT
#define SBI_ETIMEDOUT SBI_ERR_TIMEOUT
#define SBI_EIO SBI_ERR_IO
#define SBI_EDENIED_LOCKED SBI_ERR_DENIED_LOCKED
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001
#define SBI_EILL -1002
#define SBI_ENOSPC -1003
#define SBI_ENOMEM -1004
#define SBI_EUNKNOWN -1005
#define SBI_ENOENT -1006
/* clang-format on */
#endif #endif

View File

@ -1,54 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra<atish.patra@wdc.com>
*
*/
#ifndef __SBI_FIFO_H__
#define __SBI_FIFO_H__
#include <sbi/riscv_locks.h>
#include <sbi/sbi_types.h>
struct sbi_fifo {
void *queue;
spinlock_t qlock;
u16 entry_size;
u16 num_entries;
u16 avail;
u16 tail;
};
#define SBI_FIFO_INITIALIZER(__queue_mem, __entries, __entry_size) \
{ .queue = __queue_mem, \
.qlock = SPIN_LOCK_INITIALIZER, \
.num_entries = __entries, \
.entry_size = __entry_size, \
.avail = 0, \
.tail = 0, \
}
#define SBI_FIFO_DEFINE(__name, __queue_mem, __entries, __entry_size) \
struct sbi_fifo __name = SBI_FIFO_INITIALIZER(__queue_mem, __entries, __entry_size)
enum sbi_fifo_inplace_update_types {
SBI_FIFO_SKIP,
SBI_FIFO_UPDATED,
SBI_FIFO_UNCHANGED,
};
int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data, bool force);
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size);
int sbi_fifo_is_empty(struct sbi_fifo *fifo);
int sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data));
u16 sbi_fifo_avail(struct sbi_fifo *fifo);
#endif

View File

@ -1,23 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Rivos Inc.
*
* Authors:
* Clément Léger <cleger@rivosinc.com>
*/
#ifndef __SBI_FW_FEATURE_H__
#define __SBI_FW_FEATURE_H__
#include <sbi/sbi_ecall_interface.h>
struct sbi_scratch;
int sbi_fwft_set(enum sbi_fwft_feature_t feature, unsigned long value,
unsigned long flags);
int sbi_fwft_get(enum sbi_fwft_feature_t feature, unsigned long *out_val);
int sbi_fwft_init(struct sbi_scratch *scratch, bool cold_boot);
#endif

View File

@ -11,157 +11,33 @@
#define __SBI_HART_H__ #define __SBI_HART_H__
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
#include <sbi/sbi_bitops.h>
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
/** Unknown privileged specification */
SBI_HART_PRIV_VER_UNKNOWN = 0,
/** Privileged specification v1.10 */
SBI_HART_PRIV_VER_1_10 = 1,
/** Privileged specification v1.11 */
SBI_HART_PRIV_VER_1_11 = 2,
/** Privileged specification v1.12 */
SBI_HART_PRIV_VER_1_12 = 3,
};
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** HART has AIA M-mode CSRs */
SBI_HART_EXT_SMAIA = 0,
/** HART has Smepmp */
SBI_HART_EXT_SMEPMP,
/** HART has Smstateen extension **/
SBI_HART_EXT_SMSTATEEN,
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */
SBI_HART_EXT_ZICNTR,
/** HART has Zihpm extension */
SBI_HART_EXT_ZIHPM,
/** HART has Zkr extension */
SBI_HART_EXT_ZKR,
/** Hart has Smcntrpmf extension */
SBI_HART_EXT_SMCNTRPMF,
/** Hart has Xandespmu extension */
SBI_HART_EXT_XANDESPMU,
/** Hart has Zicboz extension */
SBI_HART_EXT_ZICBOZ,
/** Hart has Zicbom extension */
SBI_HART_EXT_ZICBOM,
/** Hart has Svpbmt extension */
SBI_HART_EXT_SVPBMT,
/** Hart has debug trigger extension */
SBI_HART_EXT_SDTRIG,
/** Hart has Smcsrind extension */
SBI_HART_EXT_SMCSRIND,
/** Hart has Smcdeleg extension */
SBI_HART_EXT_SMCDELEG,
/** Hart has Sscsrind extension */
SBI_HART_EXT_SSCSRIND,
/** Hart has Ssccfg extension */
SBI_HART_EXT_SSCCFG,
/** Hart has Svade extension */
SBI_HART_EXT_SVADE,
/** Hart has Svadu extension */
SBI_HART_EXT_SVADU,
/** Hart has Smnpm extension */
SBI_HART_EXT_SMNPM,
/** HART has zicfilp extension */
SBI_HART_EXT_ZICFILP,
/** HART has zicfiss extension */
SBI_HART_EXT_ZICFISS,
/** Hart has Ssdbltrp extension */
SBI_HART_EXT_SSDBLTRP,
/** HART has CTR M-mode CSRs */
SBI_HART_EXT_SMCTR,
/** HART has CTR S-mode CSRs */
SBI_HART_EXT_SSCTR,
/** HART has Ssstateen extension **/
SBI_HART_EXT_SSSTATEEN,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_hart_ext_data {
const unsigned int id;
const char *name;
};
extern const struct sbi_hart_ext_data sbi_hart_ext[];
/** CSRs should be detected by access and trapping */
enum sbi_hart_csrs {
SBI_HART_CSR_CYCLE = 0,
SBI_HART_CSR_TIME,
SBI_HART_CSR_INSTRET,
SBI_HART_CSR_MAX,
};
/*
* Smepmp enforces access boundaries between M-mode and
* S/U-mode. When it is enabled, the PMPs are programmed
* such that M-mode doesn't have access to S/U-mode memory.
*
* To give M-mode R/W access to the shared memory between M and
* S/U-mode, first entry is reserved. It is disabled at boot.
* When shared memory access is required, the physical address
* should be programmed into the first PMP entry with R/W
* permissions to the M-mode. Once the work is done, it should be
* unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
* pair should be used to map/unmap the shared memory.
*/
#define SBI_SMEPMP_RESV_ENTRY 0
struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)];
unsigned long csrs[BITS_TO_LONGS(SBI_HART_CSR_MAX)];
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned int pmp_log2gran;
unsigned int mhpm_mask;
unsigned int mhpm_bits;
};
struct sbi_scratch; struct sbi_scratch;
int sbi_hart_reinit(struct sbi_scratch *scratch); int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid);
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
extern void (*sbi_hart_expected_trap)(void); void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_mask(struct sbi_scratch *scratch);
void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
const char *prefix, const char *suffix);
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
int sbi_hart_unmap_saddr(void);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable);
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext);
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extension_str, int nestr);
bool sbi_hart_has_csr(struct sbi_scratch *scratch, enum sbi_hart_csrs csr);
void __attribute__((noreturn)) sbi_hart_hang(void); void __attribute__((noreturn)) sbi_hart_hang(void);
void __attribute__((noreturn)) void __attribute__((noreturn)) sbi_hart_switch_mode(unsigned long arg0,
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode, unsigned long next_addr,
bool next_virt); 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, u32 hartid);
u32 sbi_current_hartid(void);
#endif #endif

View File

@ -1,205 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_HARTMASK_H__
#define __SBI_HARTMASK_H__
#include <sbi/sbi_bitmap.h>
#include <sbi/sbi_scratch.h>
/**
* Maximum number of bits in a hartmask
*
* The hartmask is indexed using physical HART id so this define
* also represents the maximum number of HART ids generic OpenSBI
* can handle.
*/
#define SBI_HARTMASK_MAX_BITS 128
/** Representation of hartmask */
struct sbi_hartmask {
DECLARE_BITMAP(bits, SBI_HARTMASK_MAX_BITS);
};
/** Initialize hartmask to zero */
#define SBI_HARTMASK_INIT(__m) \
bitmap_zero(((__m)->bits), SBI_HARTMASK_MAX_BITS)
/** Initialize hartmask to zero except a particular HART id */
#define SBI_HARTMASK_INIT_EXCEPT(__m, __h) \
do { \
u32 __i = sbi_hartid_to_hartindex(__h); \
bitmap_zero_except(((__m)->bits), __i, SBI_HARTMASK_MAX_BITS); \
} while(0)
/**
* Get underlying bitmap of hartmask
* @param m the hartmask pointer
*/
#define sbi_hartmask_bits(__m) ((__m)->bits)
/**
* Set a HART index in hartmask
* @param i HART index to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__set_bit(i, m->bits);
}
/**
* Set a HART id in hartmask
* @param h HART id to set
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_set_hartid(u32 h, struct sbi_hartmask *m)
{
sbi_hartmask_set_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
* Clear a HART index in hartmask
* @param i HART index to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hartindex(u32 i, struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
__clear_bit(i, m->bits);
}
/**
* Clear a HART id in hartmask
* @param h HART id to clear
* @param m the hartmask pointer
*/
static inline void sbi_hartmask_clear_hartid(u32 h, struct sbi_hartmask *m)
{
sbi_hartmask_clear_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
* Test a HART index in hartmask
* @param i HART index to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hartindex(u32 i,
const struct sbi_hartmask *m)
{
if (i < SBI_HARTMASK_MAX_BITS)
return __test_bit(i, m->bits);
return 0;
}
/**
* Test a HART id in hartmask
* @param h HART id to test
* @param m the hartmask pointer
*/
static inline int sbi_hartmask_test_hartid(u32 h, const struct sbi_hartmask *m)
{
return sbi_hartmask_test_hartindex(sbi_hartid_to_hartindex(h), m);
}
/**
* Set all HARTs in a hartmask
* @param dstp the hartmask pointer
*/
static inline void sbi_hartmask_set_all(struct sbi_hartmask *dstp)
{
bitmap_fill(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
}
/**
* Clear all HARTs in a hartmask
* @param dstp the hartmask pointer
*/
static inline void sbi_hartmask_clear_all(struct sbi_hartmask *dstp)
{
bitmap_zero(sbi_hartmask_bits(dstp), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *srcp
* @param dstp the hartmask destination
* @param srcp the hartmask source
*/
static inline void sbi_hartmask_copy(struct sbi_hartmask *dstp,
const struct sbi_hartmask *srcp)
{
bitmap_copy(sbi_hartmask_bits(dstp), sbi_hartmask_bits(srcp),
SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p & *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_and(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_and(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p | *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_or(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_or(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* *dstp = *src1p ^ *src2p
* @param dstp the hartmask result
* @param src1p the first input
* @param src2p the second input
*/
static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
const struct sbi_hartmask *src1p,
const struct sbi_hartmask *src2p)
{
bitmap_xor(sbi_hartmask_bits(dstp), sbi_hartmask_bits(src1p),
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* Count of bits in *srcp
* @param srcp the hartmask to count bits in
*
* Return: count of bits set in *srcp
*/
static inline int sbi_hartmask_weight(const struct sbi_hartmask *srcp)
{
return bitmap_weight(sbi_hartmask_bits(srcp), SBI_HARTMASK_MAX_BITS);
}
/**
* Iterate over each HART index in hartmask
* __i hart index
* __m hartmask
*/
#define sbi_hartmask_for_each_hartindex(__i, __m) \
for((__i) = find_first_bit((__m)->bits, SBI_HARTMASK_MAX_BITS); \
(__i) < SBI_HARTMASK_MAX_BITS; \
(__i) = find_next_bit((__m)->bits, SBI_HARTMASK_MAX_BITS, (__i) + 1))
#endif

View File

@ -1,101 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#ifndef __SBI_HEAP_H__
#define __SBI_HEAP_H__
#include <sbi/sbi_types.h>
/* Opaque declaration of heap control struct */
struct sbi_heap_control;
/* Global heap control structure */
extern struct sbi_heap_control global_hpctrl;
/* Alignment of heap base address and size */
#define HEAP_BASE_ALIGN 1024
struct sbi_scratch;
/** Allocate from heap area */
void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size);
static inline void *sbi_malloc(size_t size)
{
return sbi_malloc_from(&global_hpctrl, size);
}
/** Allocate aligned from heap area */
void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
size_t alignment,size_t size);
static inline void *sbi_aligned_alloc(size_t alignment, size_t size)
{
return sbi_aligned_alloc_from(&global_hpctrl, alignment, size);
}
/** Zero allocate from heap area */
void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size);
static inline void *sbi_zalloc(size_t size)
{
return sbi_zalloc_from(&global_hpctrl, size);
}
/** Allocate array from heap area */
static inline void *sbi_calloc(size_t nitems, size_t size)
{
return sbi_zalloc(nitems * size);
}
static inline void *sbi_calloc_from(struct sbi_heap_control *hpctrl,
size_t nitems, size_t size)
{
return sbi_zalloc_from(hpctrl, nitems * size);
}
/** Free-up to heap area */
void sbi_free_from(struct sbi_heap_control *hpctrl, void *ptr);
static inline void sbi_free(void *ptr)
{
return sbi_free_from(&global_hpctrl, ptr);
}
/** Amount (in bytes) of free space in the heap area */
unsigned long sbi_heap_free_space_from(struct sbi_heap_control *hpctrl);
static inline unsigned long sbi_heap_free_space(void)
{
return sbi_heap_free_space_from(&global_hpctrl);
}
/** Amount (in bytes) of used space in the heap area */
unsigned long sbi_heap_used_space_from(struct sbi_heap_control *hpctrl);
static inline unsigned long sbi_heap_used_space(void)
{
return sbi_heap_used_space_from(&global_hpctrl);
}
/** Amount (in bytes) of reserved space in the heap area */
unsigned long sbi_heap_reserved_space_from(struct sbi_heap_control *hpctrl);
static inline unsigned long sbi_heap_reserved_space(void)
{
return sbi_heap_reserved_space_from(&global_hpctrl);
}
/** Initialize heap area */
int sbi_heap_init(struct sbi_scratch *scratch);
int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
unsigned long size);
int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl);
#endif

View File

@ -1,39 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_FENCE_H__
#define __SBI_FENCE_H__
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa_divby_4,
unsigned long vmid);
/** Invalidate Stage2 TLBs for given VMID */
void __sbi_hfence_gvma_vmid(unsigned long vmid);
/** Invalidate Stage2 TLBs for given guest physical address */
void __sbi_hfence_gvma_gpa(unsigned long gpa_divby_4);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_gvma_all(void);
/** Invalidate unified TLB entries for given asid and guest virtual address */
void __sbi_hfence_vvma_asid_va(unsigned long va, unsigned long asid);
/** Invalidate unified TLB entries for given ASID for a guest*/
void __sbi_hfence_vvma_asid(unsigned long asid);
/** Invalidate unified TLB entries for a given guest virtual address */
void __sbi_hfence_vvma_va(unsigned long va);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_vvma_all(void);
#endif

View File

@ -1,88 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_HSM_H__
#define __SBI_HSM_H__
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_types.h>
/** Hart state managment device */
struct sbi_hsm_device {
/** Name of the hart state managment device */
char name[32];
/** Start (or power-up) the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop (or power-down) the current hart from running.
*
* Return SBI_ENOTSUPP if the hart does not support platform-specific
* stop actions.
*
* For successful stop, the call won't return.
*/
int (*hart_stop)(void);
/**
* Put the current hart in platform specific suspend (or low-power)
* state.
*
* For successful retentive suspend, the call will return 0 when
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* the warm boot entry point.
*
* NOTE: mmode_resume_addr(resume address) is optional hence it
* may or may not be honored by the platform. If its not honored
* then platform must ensure to resume from the warmboot address.
*/
int (*hart_suspend)(u32 suspend_type, ulong mmode_resume_addr);
/**
* Perform platform-specific actions to resume from a suspended state.
*
* This includes restoring any platform state that was lost during
* non-retentive suspend.
*/
void (*hart_resume)(void);
};
struct sbi_domain;
struct sbi_scratch;
const struct sbi_hsm_device *sbi_hsm_get_device(void);
void sbi_hsm_set_device(const struct sbi_hsm_device *dev);
int sbi_hsm_init(struct sbi_scratch *scratch, bool cold_boot);
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong arg1);
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch,
u32 hartid);
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong arg1);
bool sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
long newstate);
int __sbi_hsm_hart_get_state(u32 hartindex);
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
struct sbi_hartmask *mask);
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
void __noreturn sbi_hsm_hart_start_finish(struct sbi_scratch *scratch,
u32 hartid);
#endif

View File

@ -1,17 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 MIPS
*
*/
#ifndef __SBI_ILLEGAL_ATOMIC_H__
#define __SBI_ILLEGAL_ATOMIC_H__
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
int sbi_illegal_atomic(ulong insn, struct sbi_trap_regs *regs);
#endif

View File

@ -12,12 +12,11 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
struct sbi_trap_context; struct sbi_trap_regs;
struct sbi_scratch;
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs); int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs); struct sbi_scratch *scratch);
int sbi_illegal_insn_handler(struct sbi_trap_context *tcntx);
#endif #endif

View File

@ -16,12 +16,4 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *scratch); void __noreturn sbi_init(struct sbi_scratch *scratch);
void sbi_revert_entry_count(struct sbi_scratch *scratch);
unsigned long sbi_entry_count(u32 hartindex);
unsigned long sbi_init_count(u32 hartindex);
void __noreturn sbi_exit(struct sbi_scratch *scratch);
#endif #endif

View File

@ -12,89 +12,20 @@
#include <sbi/sbi_types.h> #include <sbi/sbi_types.h>
/* clang-format off */ #define SBI_IPI_EVENT_SOFT 0x1
#define SBI_IPI_EVENT_FENCE_I 0x2
#define SBI_IPI_EVENT_MAX (8 * __SIZEOF_LONG__) #define SBI_IPI_EVENT_SFENCE_VMA 0x4
#define SBI_IPI_EVENT_HALT 0x8
/* clang-format on */
/** IPI hardware device */
struct sbi_ipi_device {
/** Name of the IPI device */
char name[32];
/** Send IPI to a target HART index */
void (*ipi_send)(u32 hart_index);
/** Clear IPI for the current hart */
void (*ipi_clear)(void);
};
enum sbi_ipi_update_type {
SBI_IPI_UPDATE_SUCCESS,
SBI_IPI_UPDATE_BREAK,
SBI_IPI_UPDATE_RETRY,
};
struct sbi_scratch; struct sbi_scratch;
/** IPI event operations or callbacks */ int sbi_ipi_send_many(struct sbi_scratch *scratch,
struct sbi_ipi_event_ops { ulong *pmask, u32 event);
/** Name of the IPI event operations */
char name[32];
/** void sbi_ipi_clear_smode(struct sbi_scratch *scratch);
* Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
* @return < 0, error or failure
* @return SBI_IPI_UPDATE_SUCCESS, success
* @return SBI_IPI_UPDATE_BREAK, break IPI, done on local hart
* @return SBI_IPI_UPDATE_RETRY, need retry
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartindex, void *data);
/** void sbi_ipi_process(struct sbi_scratch *scratch);
* Sync callback to wait for remote HART
* Note: This is an optional callback and it is called just after
* triggering IPI to remote HART.
*/
void (* sync)(struct sbi_scratch *scratch);
/**
* Process callback to handle IPI event
* Note: This is a mandatory callback and it is called on the
* remote HART after IPI is triggered.
*/
void (* process)(struct sbi_scratch *scratch);
};
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data);
int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops);
void sbi_ipi_event_destroy(u32 event);
int sbi_ipi_send_smode(ulong hmask, ulong hbase);
void sbi_ipi_clear_smode(void);
int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
int sbi_ipi_raw_send(u32 hartindex);
void sbi_ipi_raw_clear(void);
const struct sbi_ipi_device *sbi_ipi_get_device(void);
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot); int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_ipi_exit(struct sbi_scratch *scratch);
#endif #endif

View File

@ -1,49 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_list.h>
#include <sbi/sbi_types.h>
struct sbi_scratch;
/** irqchip hardware device */
struct sbi_irqchip_device {
/** Node in the list of irqchip devices */
struct sbi_dlist node;
/** Initialize per-hart state for the current hart */
int (*warm_init)(struct sbi_irqchip_device *dev);
/** Handle an IRQ from this irqchip */
int (*irq_handle)(void);
};
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(void);
/** Register an irqchip device to receive callbacks */
void sbi_irqchip_add_device(struct sbi_irqchip_device *dev);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif

View File

@ -1,187 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Simple doubly-linked list library.
*
* Adapted from Xvisor source file libs/include/libs/list.h
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_LIST_H__
#define __SBI_LIST_H__
#include <sbi/sbi_types.h>
#define SBI_LIST_POISON_PREV 0xDEADBEEF
#define SBI_LIST_POISON_NEXT 0xFADEBABE
struct sbi_dlist {
struct sbi_dlist *next, *prev;
};
#define SBI_LIST_HEAD_INIT(__lname) { &(__lname), &(__lname) }
#define SBI_LIST_HEAD(_lname) \
struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
#define SBI_INIT_LIST_HEAD(ptr) \
do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0)
static inline void __sbi_list_add(struct sbi_dlist *new,
struct sbi_dlist *prev,
struct sbi_dlist *next)
{
new->prev = prev;
new->next = next;
prev->next = new;
next->prev = new;
}
/**
* Checks if the list is empty or not.
* @param head List head
*
* Returns true if list is empty, false otherwise.
*/
static inline bool sbi_list_empty(struct sbi_dlist *head)
{
return head->next == head;
}
/**
* Adds the new node after the given head.
* @param new New node that needs to be added to list.
* @param head List head after which the "new" node should be added.
* Note: the new node is added after the head.
*/
static inline void sbi_list_add(struct sbi_dlist *new, struct sbi_dlist *head)
{
__sbi_list_add(new, head, head->next);
}
/**
* Adds a node at the tail where tnode points to tail node.
* @param new The new node to be added before tail.
* @param tnode The current tail node.
* Note: the new node is added before tail node.
*/
static inline void sbi_list_add_tail(struct sbi_dlist *new,
struct sbi_dlist *tnode)
{
__sbi_list_add(new, tnode->prev, tnode);
}
static inline void __sbi_list_del(struct sbi_dlist *prev,
struct sbi_dlist *next)
{
prev->next = next;
next->prev = prev;
}
static inline void __sbi_list_del_entry(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
}
/**
* Deletes a given entry from list.
* @param node Node to be deleted.
*/
static inline void sbi_list_del(struct sbi_dlist *entry)
{
__sbi_list_del(entry->prev, entry->next);
entry->next = (void *)SBI_LIST_POISON_NEXT;
entry->prev = (void *)SBI_LIST_POISON_PREV;
}
/**
* Deletes entry from list and reinitialize it.
* @param entry the element to delete from the list.
*/
static inline void sbi_list_del_init(struct sbi_dlist *entry)
{
__sbi_list_del_entry(entry);
SBI_INIT_LIST_HEAD(entry);
}
/**
* Get the struct for this entry
* @param ptr the &struct list_head pointer.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* Get the first element from a list
* @param ptr the list head to take the element from.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_struct within the struct.
*
* Note: that list is expected to be not empty.
*/
#define sbi_list_first_entry(ptr, type, member) \
sbi_list_entry((ptr)->next, type, member)
/**
* Get the last element from a list
* @param ptr the list head to take the element from.
* @param type the type of the struct this is embedded in.
* @param member the name of the list_head within the struct.
*
* Note: that list is expected to be not empty.
*/
#define sbi_list_last_entry(ptr, type, member) \
sbi_list_entry((ptr)->prev, type, member)
/**
* Iterate over a list
* @param pos the &struct list_head to use as a loop cursor.
* @param head the head for your list.
*/
#define sbi_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* Iterate over list of given type
* @param pos the type * to use as a loop cursor.
* @param head the head for your list.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_for_each_entry(pos, head, member) \
for (pos = sbi_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = sbi_list_entry(pos->member.next, typeof(*pos), member))
/**
* Iterate over list of given type safe against removal of list entry
* @param pos the type * to use as a loop cursor.
* @param n another type * to use as temporary storage.
* @param head the head for your list.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_for_each_entry_safe(pos, n, head, member) \
for (pos = sbi_list_entry((head)->next, typeof(*pos), member), \
n = sbi_list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = sbi_list_entry(pos->member.next, typeof(*pos), member))
/**
* Iterate over list of given type in reverse order
* @param pos the type * to use as a loop cursor.
* @param head the head for your list.
* @param member the name of the list_struct within the struct.
*/
#define sbi_list_for_each_entry_reverse(pos, head, member) \
for (pos = sbi_list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = sbi_list_entry(pos->member.prev, typeof(*pos), member))
#endif

View File

@ -1,15 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_MATH_H__
#define __SBI_MATH_H__
unsigned long log2roundup(unsigned long x);
#endif

View File

@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SBI_MISALIGNED_LDST_H__
#define __SBI_MISALIGNED_LDST_H__
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch;
int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch);
#endif

View File

@ -1,185 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Rahul Pathak <rpathak@ventanamicro.com>
*/
#ifndef __SBI_MPXY_H__
#define __SBI_MPXY_H__
#include <sbi/sbi_list.h>
struct sbi_scratch;
#define SBI_MPXY_MSGPROTO_VERSION(Major, Minor) ((Major << 16) | Minor)
enum sbi_mpxy_attr_id {
/* Standard channel attributes managed by MPXY framework */
SBI_MPXY_ATTR_MSG_PROT_ID = 0x00000000,
SBI_MPXY_ATTR_MSG_PROT_VER = 0x00000001,
SBI_MPXY_ATTR_MSG_MAX_LEN = 0x00000002,
SBI_MPXY_ATTR_MSG_SEND_TIMEOUT = 0x00000003,
SBI_MPXY_ATTR_MSG_COMPLETION_TIMEOUT = 0x00000004,
SBI_MPXY_ATTR_CHANNEL_CAPABILITY = 0x00000005,
SBI_MPXY_ATTR_SSE_EVENT_ID = 0x00000006,
SBI_MPXY_ATTR_MSI_CONTROL = 0x00000007,
SBI_MPXY_ATTR_MSI_ADDR_LO = 0x00000008,
SBI_MPXY_ATTR_MSI_ADDR_HI = 0x00000009,
SBI_MPXY_ATTR_MSI_DATA = 0x0000000A,
SBI_MPXY_ATTR_EVENTS_STATE_CONTROL = 0x0000000B,
SBI_MPXY_ATTR_STD_ATTR_MAX_IDX,
/* Message protocol specific attributes, managed by
* message protocol driver */
SBI_MPXY_ATTR_MSGPROTO_ATTR_START = 0x80000000,
SBI_MPXY_ATTR_MSGPROTO_ATTR_END = 0xffffffff
};
/**
* SBI MPXY Message Protocol IDs
*/
enum sbi_mpxy_msgproto_id {
SBI_MPXY_MSGPROTO_RPMI_ID = 0x00000000,
SBI_MPXY_MSGPROTO_MAX_IDX,
/** Vendor specific message protocol IDs */
SBI_MPXY_MSGPROTO_VENDOR_START = 0x80000000,
SBI_MPXY_MSGPROTO_VENDOR_END = 0xffffffff
};
enum SBI_EXT_MPXY_SHMEM_FLAGS {
SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE = 0b00,
SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE_RETURN = 0b01,
SBI_EXT_MPXY_SHMEM_FLAG_MAX_IDX
};
struct sbi_mpxy_msi_info {
/* MSI target address low 32-bit */
u32 msi_addr_lo;
/* MSI target address high 32-bit */
u32 msi_addr_hi;
/* MSI data */
u32 msi_data;
};
/**
* Channel attributes.
* NOTE: The sequence of attribute fields are as per the
* defined sequence in the attribute table in spec(or as
* per the enum sbi_mpxy_attr_id).
*/
struct sbi_mpxy_channel_attrs {
/* Message protocol ID */
u32 msg_proto_id;
/* Message protocol Version */
u32 msg_proto_version;
/* Message protocol maximum message data length(bytes) */
u32 msg_data_maxlen;
/* Message protocol message send timeout
* in microseconds */
u32 msg_send_timeout;
/* Message protocol message response timeout in
* microseconds. Its the aggregate of msg_send_timeout
* and the timeout in receiving the response */
u32 msg_completion_timeout;
/* Bit array for channel capabilities */
u32 capability;
u32 sse_event_id;
u32 msi_control;
struct sbi_mpxy_msi_info msi_info;
/* Events State Control */
u32 eventsstate_ctrl;
};
/** A Message proxy channel accessible through SBI interface */
struct sbi_mpxy_channel {
/** List head to a set of channels */
struct sbi_dlist head;
u32 channel_id;
struct sbi_mpxy_channel_attrs attrs;
/**
* Read message protocol attributes
* NOTE: inmem requires little-endian byte-ordering
*/
int (*read_attributes)(struct sbi_mpxy_channel *channel,
u32 *outmem,
u32 base_attr_id,
u32 attr_count);
/**
* Write message protocol attributes
* NOTE: outmem requires little-endian byte-ordering
*/
int (*write_attributes)(struct sbi_mpxy_channel *channel,
u32 *inmem,
u32 base_attr_id,
u32 attr_count);
/**
* Send a message and wait for response
* NOTE: msgbuf requires little-endian byte-ordering
*/
int (*send_message_with_response)(struct sbi_mpxy_channel *channel,
u32 msg_id, void *msgbuf, u32 msg_len,
void *respbuf, u32 resp_max_len,
unsigned long *resp_len);
/** Send message without response */
int (*send_message_without_response)(struct sbi_mpxy_channel *channel,
u32 msg_id, void *msgbuf, u32 msg_len);
/**
* Get notifications events if supported on a channel
* NOTE: eventsbuf requires little-endian byte-ordering
*/
int (*get_notification_events)(struct sbi_mpxy_channel *channel,
void *eventsbuf, u32 bufsize,
unsigned long *events_len);
/**
* Callback to enable the events state reporting
* in the message protocol implementation
*/
void (*switch_eventsstate)(u32 enable);
};
/** Register a Message proxy channel */
int sbi_mpxy_register_channel(struct sbi_mpxy_channel *channel);
/** Initialize Message proxy subsystem */
int sbi_mpxy_init(struct sbi_scratch *scratch);
/** Check if some Message proxy channel is available */
bool sbi_mpxy_channel_available(void);
/** Get message proxy shared memory size */
unsigned long sbi_mpxy_get_shmem_size(void);
/** Set message proxy shared memory on the calling HART */
int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi,
unsigned long flags);
/** Get channel IDs list */
int sbi_mpxy_get_channel_ids(u32 start_index);
/** Read MPXY channel attributes */
int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count);
/** Write MPXY channel attributes */
int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count);
/**
* Send a message over a MPXY channel.
* In case if response is not expected, resp_data_len will be NULL.
*/
int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
unsigned long msg_data_len,
unsigned long *resp_data_len);
/** Get Message proxy notification events */
int sbi_mpxy_get_notification_events(u32 channel_id,
unsigned long *events_len);
#endif

View File

@ -10,299 +10,157 @@
#ifndef __SBI_PLATFORM_H__ #ifndef __SBI_PLATFORM_H__
#define __SBI_PLATFORM_H__ #define __SBI_PLATFORM_H__
/**
* OpenSBI 32-bit platform version with:
* 1. upper 16-bits as major number
* 2. lower 16-bits as minor number
*/
#define SBI_PLATFORM_VERSION(Major, Minor) ((Major << 16) | Minor)
/** Offset of opensbi_version in struct sbi_platform */
#define SBI_PLATFORM_OPENSBI_VERSION_OFFSET (0x00)
/** Offset of platform_version in struct sbi_platform */
#define SBI_PLATFORM_VERSION_OFFSET (0x04)
/** Offset of name in struct sbi_platform */ /** Offset of name in struct sbi_platform */
#define SBI_PLATFORM_NAME_OFFSET (0x08) #define SBI_PLATFORM_NAME_OFFSET (0x0)
/** Offset of features in struct sbi_platform */ /** Offset of features in struct sbi_platform */
#define SBI_PLATFORM_FEATURES_OFFSET (0x48) #define SBI_PLATFORM_FEATURES_OFFSET (0x40)
/** Offset of hart_count in struct sbi_platform */ /** Offset of hart_count in struct sbi_platform */
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50) #define SBI_PLATFORM_HART_COUNT_OFFSET (0x48)
/** Offset of hart_stack_size in struct sbi_platform */ /** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54) #define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x4c)
/** Offset of heap_size in struct sbi_platform */
#define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58)
/** Offset of reserved in struct sbi_platform */
#define SBI_PLATFORM_RESERVED_OFFSET (0x5c)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
/** Offset of cbom_block_size in struct sbi_platform */
#define SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET (0x60 + (__SIZEOF_POINTER__ * 3))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12) #ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h> #include <sbi/sbi_scratch.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_trap_ldst.h>
struct sbi_domain_memregion;
struct sbi_ecall_return;
struct sbi_trap_regs;
struct sbi_hart_features;
union sbi_ldst_data;
/** Possible feature flags of a platform */ /** Possible feature flags of a platform */
enum sbi_platform_features { enum sbi_platform_features {
/** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has PMP support */
SBI_PLATFORM_HAS_PMP = (1 << 2),
/** Platform has S-mode counter enable */
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
/** Platform has M-mode counter enable */
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
/** Platform has fault delegation support */ /** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1), SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
/** Last index of Platform features*/
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_MFAULTS_DELEGATION,
}; };
/** Default feature set for a platform */ /** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \ #define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_MFAULTS_DELEGATION) (SBI_PLATFORM_HAS_TIMER_VALUE | \
SBI_PLATFORM_HAS_PMP | \
SBI_PLATFORM_HAS_SCOUNTEREN | \
SBI_PLATFORM_HAS_MCOUNTEREN | \
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */ /** Representation of a platform */
struct sbi_platform_operations { struct sbi_platform {
/* Check if specified HART is allowed to do cold boot */ /** Name of the platform */
bool (*cold_boot_allowed)(u32 hartid); char name[64];
/** Supported features */
/* Platform nascent initialization */ u64 features;
int (*nascent_init)(void); /** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/** Platform early initialization */ /** Platform early initialization */
int (*early_init)(bool cold_boot); int (*early_init)(bool cold_boot);
/** Platform final initialization */ /** Platform final initialization */
int (*final_init)(bool cold_boot); int (*final_init)(bool cold_boot);
/** Platform early exit */ /** Get number of PMP regions for given HART */
void (*early_exit)(void); u32 (*pmp_region_count)(u32 hartid);
/** Platform final exit */
void (*final_exit)(void);
/** /**
* For platforms that do not implement misa, non-standard * Get PMP regions details (namely: protection, base address,
* methods are needed to determine cpu extension. * and size) for given HART
*/ */
int (*misa_check_extension)(char ext); int (*pmp_region_info)(u32 hartid, u32 index,
ulong *prot, ulong *addr, ulong *log2size);
/** /** Write a character to the platform console output */
* For platforms that do not implement misa, non-standard void (*console_putc)(char ch);
* methods are needed to get MXL field of misa. /** Read a character from the platform console input */
*/ char (*console_getc)(void);
int (*misa_get_xlen)(void); /** Initialize the platform console */
int (*console_init)(void);
/** Initialize (or populate) HART extensions for the platform */ /** Initialize the platform interrupt controller for current HART */
int (*extensions_init)(struct sbi_hart_features *hfeatures); int (*irqchip_init)(bool cold_boot);
/** Initialize (or populate) domains for the platform */ /** Send IPI to a target HART */
int (*domains_init)(void); void (*ipi_send)(u32 target_hart);
/** Wait for target HART to acknowledge IPI */
void (*ipi_sync)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Initialize hw performance counters */ /** Get platform timer value */
int (*pmu_init)(void); u64 (*timer_value)(void);
/** Start platform timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop platform timer event for current HART */
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Get platform specific mhpmevent value */ /** Reboot the platform */
uint64_t (*pmu_xlate_to_mhpmevent)(uint32_t event_idx, uint64_t data); int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
/** Initialize the platform interrupt controller during cold boot */ int (*system_shutdown)(u32 type);
int (*irqchip_init)(void); } __packed;
/** Initialize IPI during cold boot */
int (*ipi_init)(void);
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get tlb fifo num entries*/
u32 (*get_tlb_num_entries)(void);
/** Initialize platform timer during cold boot */
int (*timer_init)(void);
/** Initialize the platform Message Proxy(MPXY) driver */
int (*mpxy_init)(void);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out);
/** platform specific handler to fixup load fault */
int (*emulate_load)(int rlen, unsigned long addr,
union sbi_ldst_data *out_val);
/** platform specific handler to fixup store fault */
int (*emulate_store)(int wlen, unsigned long addr,
union sbi_ldst_data in_val);
/** platform specific pmp setup on current HART */
void (*pmp_set)(unsigned int n, unsigned long flags,
unsigned long prot, unsigned long addr,
unsigned long log2len);
/** platform specific pmp disable on current HART */
void (*pmp_disable)(unsigned int n);
};
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
/** Platform default heap size */
#define SBI_PLATFORM_DEFAULT_HEAP_SIZE(__num_hart) \
(0x8000 + 0x1000 * (__num_hart))
/** Representation of a platform */
struct sbi_platform {
/**
* OpenSBI version this sbi_platform is based on.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 opensbi_version;
/**
* OpenSBI platform version released by vendor.
* It's a 32-bit value where upper 16-bits are major number
* and lower 16-bits are minor number
*/
u32 platform_version;
/** Name of the platform */
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs (at most SBI_HARTMASK_MAX_BITS) */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Size of heap shared by all HARTs */
u32 heap_size;
/** Reserved for future use */
u32 reserved;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
unsigned long firmware_context;
/**
* HART index to HART id table
*
* If hart_index2id != NULL then the table must contain a mapping
* for each HART index 0 <= <abc> < hart_count:
* hart_index2id[<abc>] = some HART id
*
* If hart_index2id == NULL then we assume identity mapping
* hart_index2id[<abc>] = <abc>
*/
const u32 *hart_index2id;
/** Allocation alignment for Scratch */
unsigned long cbom_block_size;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_OFFSET
*/
assert_member_offset(struct sbi_platform, opensbi_version, SBI_PLATFORM_OPENSBI_VERSION_OFFSET);
assert_member_offset(struct sbi_platform, platform_version, SBI_PLATFORM_VERSION_OFFSET);
assert_member_offset(struct sbi_platform, name, SBI_PLATFORM_NAME_OFFSET);
assert_member_offset(struct sbi_platform, features, SBI_PLATFORM_FEATURES_OFFSET);
assert_member_offset(struct sbi_platform, hart_count, SBI_PLATFORM_HART_COUNT_OFFSET);
assert_member_offset(struct sbi_platform, hart_stack_size, SBI_PLATFORM_HART_STACK_SIZE_OFFSET);
assert_member_offset(struct sbi_platform, heap_size, SBI_PLATFORM_HEAP_SIZE_OFFSET);
assert_member_offset(struct sbi_platform, reserved, SBI_PLATFORM_RESERVED_OFFSET);
assert_member_offset(struct sbi_platform, platform_ops_addr, SBI_PLATFORM_OPS_OFFSET);
assert_member_offset(struct sbi_platform, firmware_context, SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET);
assert_member_offset(struct sbi_platform, hart_index2id, SBI_PLATFORM_HART_INDEX2ID_OFFSET);
assert_member_offset(struct sbi_platform, cbom_block_size, SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET);
/** Get pointer to sbi_platform for sbi_scratch pointer */ /** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \ #define sbi_platform_ptr(__s) \
((const struct sbi_platform *)((__s)->platform_addr)) ((struct sbi_platform *)((__s)->platform_addr))
/** Get pointer to sbi_platform for current HART */ /** Get pointer to sbi_platform for current HART */
#define sbi_platform_thishart_ptr() ((const struct sbi_platform *) \ #define sbi_platform_thishart_ptr() \
(sbi_scratch_thishart_ptr()->platform_addr)) ((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr))
/** Get pointer to platform_ops_addr from platform pointer **/ /** Check whether the platform supports timer value */
#define sbi_platform_ops(__p) \ #define sbi_platform_has_timer_value(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr) ((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform has PMP support */
#define sbi_platform_has_pmp(__p) \
((__p)->features & SBI_PLATFORM_HAS_PMP)
/** Check whether the platform supports scounteren CSR */
#define sbi_platform_has_scounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
/** Check whether the platform supports mcounteren CSR */
#define sbi_platform_has_mcounteren(__p) \
((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN)
/** Check whether the platform supports fault delegation */ /** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \ #define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION) ((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/**
* Get the platform features in string format
*
* @param plat pointer to struct sbi_platform
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
*/
void sbi_platform_get_features_str(const struct sbi_platform *plat,
char *features_str, int nfstr);
/** /**
* Get name of the platform * Get name of the platform
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* *
* @return pointer to platform name on success and "Unknown" on failure * @return pointer to platform name on success and NULL on failure
*/ */
static inline const char *sbi_platform_name(const struct sbi_platform *plat) static inline const char *sbi_platform_name(struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->name; return plat->name;
return "Unknown"; return NULL;
} }
/** /**
* Get the platform features * Check whether the given HART is disabled
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param hartid HART ID
* *
* @return the features value currently set for the given platform * @return TRUE if HART is disabled and FALSE otherwise
*/ */
static inline unsigned long sbi_platform_get_features( static inline bool sbi_platform_hart_disabled(struct sbi_platform *plat,
const struct sbi_platform *plat) u32 hartid)
{ {
if (plat) if (plat && (plat->disabled_hart_mask & (1 << hartid)))
return plat->features; return TRUE;
return 0; return FALSE;
}
/**
* Get platform specific tlb range flush maximum value. Any request with size
* higher than this is upgraded to a full flush.
*
* @param plat pointer to struct sbi_platform
*
* @return tlb range flush limit value. Returns a default (page size) if not
* defined by platform.
*/
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->get_tlbr_flush_limit)
return sbi_platform_ops(plat)->get_tlbr_flush_limit();
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
/**
* Get platform specific tlb fifo num entries.
*
* @param plat pointer to struct sbi_platform
*
* @return number of tlb fifo entries
*/
static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->get_tlb_num_entries)
return sbi_platform_ops(plat)->get_tlb_num_entries();
return sbi_hart_count();
} }
/** /**
@ -312,7 +170,7 @@ static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *p
* *
* @return total number of HARTs * @return total number of HARTs
*/ */
static inline u32 sbi_platform_hart_count(const struct sbi_platform *plat) static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_count; return plat->hart_count;
@ -326,60 +184,26 @@ static inline u32 sbi_platform_hart_count(const struct sbi_platform *plat)
* *
* @return stack size in bytes * @return stack size in bytes
*/ */
static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat) static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
{ {
if (plat) if (plat)
return plat->hart_stack_size; return plat->hart_stack_size;
return 0; return 0;
} }
/**
* Check whether given HART is allowed to do cold boot
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
* @return true if HART is allowed to do cold boot and false otherwise
*/
static inline bool sbi_platform_cold_boot_allowed(
const struct sbi_platform *plat,
u32 hartid)
{
if (plat && sbi_platform_ops(plat)->cold_boot_allowed)
return sbi_platform_ops(plat)->cold_boot_allowed(hartid);
return true;
}
/**
* Nascent (very early) initialization for current HART
*
* NOTE: This function can be used to do very early initialization of
* platform specific per-HART CSRs and devices.
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->nascent_init)
return sbi_platform_ops(plat)->nascent_init();
return 0;
}
/** /**
* Early initialization for current HART * Early initialization for current HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (true) or warm_boot (false) * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_early_init(const struct sbi_platform *plat, static inline int sbi_platform_early_init(struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && sbi_platform_ops(plat)->early_init) if (plat && plat->early_init)
return sbi_platform_ops(plat)->early_init(cold_boot); return plat->early_init(cold_boot);
return 0; return 0;
} }
@ -387,302 +211,256 @@ static inline int sbi_platform_early_init(const struct sbi_platform *plat,
* Final initialization for current HART * Final initialization for current HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (true) or warm_boot (false) * @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_final_init(const struct sbi_platform *plat, static inline int sbi_platform_final_init(struct sbi_platform *plat,
bool cold_boot) bool cold_boot)
{ {
if (plat && sbi_platform_ops(plat)->final_init) if (plat && plat->final_init)
return sbi_platform_ops(plat)->final_init(cold_boot); return plat->final_init(cold_boot);
return 0; return 0;
} }
/** /**
* Early exit for current HART * Get the number of PMP regions of a HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
*/ * @param hartid HART ID
static inline void sbi_platform_early_exit(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->early_exit)
sbi_platform_ops(plat)->early_exit();
}
/**
* Final exit for current HART
* *
* @param plat pointer to struct sbi_platform * @return number of PMP regions
*/ */
static inline void sbi_platform_final_exit(const struct sbi_platform *plat) static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
u32 hartid)
{ {
if (plat && sbi_platform_ops(plat)->final_exit) if (plat && plat->pmp_region_count)
sbi_platform_ops(plat)->final_exit(); return plat->pmp_region_count(hartid);
}
/**
* Check CPU extension in MISA
*
* @param plat pointer to struct sbi_platform
* @param ext shorthand letter for CPU extensions
*
* @return zero for not-supported and non-zero for supported
*/
static inline int sbi_platform_misa_extension(const struct sbi_platform *plat,
char ext)
{
if (plat && sbi_platform_ops(plat)->misa_check_extension)
return sbi_platform_ops(plat)->misa_check_extension(ext);
return 0; return 0;
} }
/** /**
* Get MXL field of MISA * Get PMP regions details (namely: protection, base address,
* and size) of a HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param hartid HART ID
* @param index index of PMP region for which we want details
* @param prot output pointer for PMP region protection
* @param addr output pointer for PMP region base address
* @param log2size output pointer for log-of-2 PMP region size
* *
* @return 1/2/3 on success and error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat) static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
u32 hartid, u32 index,
ulong *prot, ulong *addr,
ulong *log2size)
{ {
if (plat && sbi_platform_ops(plat)->misa_get_xlen) if (plat && plat->pmp_region_info)
return sbi_platform_ops(plat)->misa_get_xlen(); return plat->pmp_region_info(hartid, index,
return -1; prot, addr, log2size);
return 0;
} }
/** /**
* Initialize (or populate) HART extensions for the platform * Write a character to the platform console output
*
* @param plat pointer to struct sbi_platform
* @param ch character to write
*/
static inline void sbi_platform_console_putc(struct sbi_platform *plat,
char ch)
{
if (plat && plat->console_putc)
plat->console_putc(ch);
}
/**
* Read a character from the platform console input
*
* @param plat pointer to struct sbi_platform
*
* @return character read from console input
*/
static inline char sbi_platform_console_getc(struct sbi_platform *plat)
{
if (plat && plat->console_getc)
return plat->console_getc();
return 0;
}
/**
* Initialize the platform console
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_extensions_init( static inline int sbi_platform_console_init(struct sbi_platform *plat)
const struct sbi_platform *plat,
struct sbi_hart_features *hfeatures)
{ {
if (plat && sbi_platform_ops(plat)->extensions_init) if (plat && plat->console_init)
return sbi_platform_ops(plat)->extensions_init(hfeatures); return plat->console_init();
return 0; return 0;
} }
/** /**
* Initialize (or populate) domains for the platform * Initialize the platform interrupt controller for current HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_domains_init(const struct sbi_platform *plat) static inline int sbi_platform_irqchip_init(struct sbi_platform *plat,
bool cold_boot)
{ {
if (plat && sbi_platform_ops(plat)->domains_init) if (plat && plat->irqchip_init)
return sbi_platform_ops(plat)->domains_init(); return plat->irqchip_init(cold_boot);
return 0; return 0;
} }
/** /**
* Setup hw PMU events for the platform * Send IPI to a target HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_send(struct sbi_platform *plat,
u32 target_hart)
{
if (plat && plat->ipi_send)
plat->ipi_send(target_hart);
}
/**
* Wait for target HART to acknowledge IPI
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
u32 target_hart)
{
if (plat && plat->ipi_sync)
plat->ipi_sync(target_hart);
}
/**
* Clear IPI for a target HART
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
u32 target_hart)
{
if (plat && plat->ipi_clear)
plat->ipi_clear(target_hart);
}
/**
* Initialize the platform IPI support for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_pmu_init(const struct sbi_platform *plat) static inline int sbi_platform_ipi_init(struct sbi_platform *plat,
bool cold_boot)
{ {
if (plat && sbi_platform_ops(plat)->pmu_init) if (plat && plat->ipi_init)
return sbi_platform_ops(plat)->pmu_init(); return plat->ipi_init(cold_boot);
return 0; return 0;
} }
/** /**
* Get the value to be written in mhpmeventx for event_idx * Get platform timer value
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param event_idx ID of the PMU event
* @param data Additional configuration data passed from supervisor software
* *
* @return expected value by the platform or 0 if platform doesn't know about * @return 64bit timer value
* the event
*/ */
static inline uint64_t sbi_platform_pmu_xlate_to_mhpmevent(const struct sbi_platform *plat, static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
uint32_t event_idx, uint64_t data)
{ {
if (plat && sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent) if (plat && plat->timer_value)
return sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent(event_idx, return plat->timer_value();
data);
return 0; return 0;
} }
/** /**
* Initialize the platform interrupt controller during cold boot * Start platform timer event for current HART
*
* @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen
*/
static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
u64 next_event)
{
if (plat && plat->timer_event_start)
plat->timer_event_start(next_event);
}
/**
* Stop platform timer event for current HART
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
*/
static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat)
{
if (plat && plat->timer_event_stop)
plat->timer_event_stop();
}
/**
* Initialize the platform timer for current HART
*
* @param plat pointer to struct sbi_platform
* @param cold_boot whether cold boot (TRUE) or warm_boot (FALSE)
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat) static inline int sbi_platform_timer_init(struct sbi_platform *plat,
bool cold_boot)
{ {
if (plat && sbi_platform_ops(plat)->irqchip_init) if (plat && plat->timer_init)
return sbi_platform_ops(plat)->irqchip_init(); return plat->timer_init(cold_boot);
return 0; return 0;
} }
/** /**
* Initialize the platform IPI support during cold boot * Reboot the platform
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param type type of reboot
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_ipi_init(const struct sbi_platform *plat) static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
u32 type)
{ {
if (plat && sbi_platform_ops(plat)->ipi_init) if (plat && plat->system_reboot)
return sbi_platform_ops(plat)->ipi_init(); return plat->system_reboot(type);
return 0; return 0;
} }
/** /**
* Initialize the platform timer during cold boot * Shutdown or poweroff the platform
* *
* @param plat pointer to struct sbi_platform * @param plat pointer to struct sbi_platform
* @param type type of shutdown or poweroff
* *
* @return 0 on success and negative error code on failure * @return 0 on success and negative error code on failure
*/ */
static inline int sbi_platform_timer_init(const struct sbi_platform *plat) static inline int sbi_platform_system_shutdown(struct sbi_platform *plat,
u32 type)
{ {
if (plat && sbi_platform_ops(plat)->timer_init) if (plat && plat->system_shutdown)
return sbi_platform_ops(plat)->timer_init(); return plat->system_shutdown(type);
return 0; return 0;
} }
/**
* Initialize the platform Message Proxy drivers
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_mpxy_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->mpxy_init)
return sbi_platform_ops(plat)->mpxy_init();
return 0;
}
/**
* Check if SBI vendor extension is implemented or not.
*
* @param plat pointer to struct sbi_platform
*
* @return false if not implemented and true if implemented
*/
static inline bool sbi_platform_vendor_ext_check(
const struct sbi_platform *plat)
{
return plat && sbi_platform_ops(plat)->vendor_ext_provider;
}
/**
* Invoke platform specific vendor SBI extension implementation.
*
* @param plat pointer to struct sbi_platform
* @param funcid SBI function id within the extension id
* @param regs pointer to trap registers passed by the caller
* @param out_value output value that can be filled by the callee
* @param out_trap trap info that can be filled by the callee
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_vendor_ext_provider(
const struct sbi_platform *plat,
long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider)
return sbi_platform_ops(plat)->vendor_ext_provider(funcid,
regs, out);
return SBI_ENOTSUPP;
}
/**
* Ask platform to emulate the trapped load
*
* @param plat pointer to struct sbi_platform
* @param rlen length of the load: 1/2/4/8...
* @param addr virtual address of the load. Platform needs to page-walk and
* find the physical address if necessary
* @param out_val value loaded
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_emulate_load(const struct sbi_platform *plat,
int rlen, unsigned long addr,
union sbi_ldst_data *out_val)
{
if (plat && sbi_platform_ops(plat)->emulate_load) {
return sbi_platform_ops(plat)->emulate_load(rlen, addr,
out_val);
}
return SBI_ENOTSUPP;
}
/**
* Ask platform to emulate the trapped store
*
* @param plat pointer to struct sbi_platform
* @param wlen length of the store: 1/2/4/8...
* @param addr virtual address of the store. Platform needs to page-walk and
* find the physical address if necessary
* @param in_val value to store
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_emulate_store(const struct sbi_platform *plat,
int wlen, unsigned long addr,
union sbi_ldst_data in_val)
{
if (plat && sbi_platform_ops(plat)->emulate_store) {
return sbi_platform_ops(plat)->emulate_store(wlen, addr,
in_val);
}
return SBI_ENOTSUPP;
}
/**
* Platform specific PMP setup on current HART
*
* @param plat pointer to struct sbi_platform
* @param n index of the pmp entry
* @param flags domain memregion flags
* @param prot attribute of the pmp entry
* @param addr address of the pmp entry
* @param log2len size of the pmp entry as power-of-2
*/
static inline void sbi_platform_pmp_set(const struct sbi_platform *plat,
unsigned int n, unsigned long flags,
unsigned long prot, unsigned long addr,
unsigned long log2len)
{
if (plat && sbi_platform_ops(plat)->pmp_set)
sbi_platform_ops(plat)->pmp_set(n, flags, prot, addr, log2len);
}
/**
* Platform specific PMP disable on current HART
*
* @param plat pointer to struct sbi_platform
* @param n index of the pmp entry
*/
static inline void sbi_platform_pmp_disable(const struct sbi_platform *plat,
unsigned int n)
{
if (plat && sbi_platform_ops(plat)->pmp_disable)
sbi_platform_ops(plat)->pmp_disable(n);
}
#endif #endif
#endif #endif

View File

@ -1,161 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_PMU_H__
#define __SBI_PMU_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_trap.h>
struct sbi_scratch;
/* Event related macros */
/* Maximum number of hardware events that can mapped by OpenSBI */
#define SBI_PMU_HW_EVENT_MAX 256
/* Counter related macros */
#define SBI_PMU_FW_CTR_MAX 16
#define SBI_PMU_HW_CTR_MAX 32
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
#define SBI_PMU_FIXED_CTR_MASK 0x07
#define SBI_PMU_CY_IR_MASK 0x05
struct sbi_pmu_device {
/** Name of the PMU platform device */
char name[32];
/**
* Validate event code of custom firmware event
*/
int (*fw_event_validate_encoding)(uint32_t hartid, uint64_t event_data);
/**
* Match custom firmware counter with custom firmware event
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
bool (*fw_counter_match_encoding)(uint32_t hartid,
uint32_t counter_index,
uint64_t event_data);
/**
* Fetch the max width of this counter in number of bits.
*/
int (*fw_counter_width)(void);
/**
* Read value of custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
uint64_t (*fw_counter_read_value)(uint32_t hartid,
uint32_t counter_index);
/**
* Write value to custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
void (*fw_counter_write_value)(uint32_t hartid, uint32_t counter_index,
uint64_t value);
/**
* Start custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
int (*fw_counter_start)(uint32_t hartid, uint32_t counter_index,
uint64_t event_data);
/**
* Stop custom firmware counter
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
*/
int (*fw_counter_stop)(uint32_t hartid, uint32_t counter_index);
/**
* Custom enable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_enable_irq)(uint32_t counter_index);
/**
* Custom disable irq for hardware counter
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
*/
void (*hw_counter_disable_irq)(uint32_t counter_index);
/**
* Custom function returning the machine-specific irq-bit.
*/
int (*hw_counter_irq_bit)(void);
/**
* Custom function to inhibit counting of events while in
* specified mode.
*/
void (*hw_counter_filter_mode)(unsigned long flags, int counter_index);
};
/** Get the PMU platform device */
const struct sbi_pmu_device *sbi_pmu_get_device(void);
/** Set the PMU platform device */
void sbi_pmu_set_device(const struct sbi_pmu_device *dev);
/** Initialize PMU */
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
/** Reset PMU during hart exit */
void sbi_pmu_exit(struct sbi_scratch *scratch);
/** Return the pmu irq bit depending on extension existence */
int sbi_pmu_irq_bit(void);
/** Return the pmu irq mask or 0 if the pmu overflow irq is not supported */
unsigned long sbi_pmu_irq_mask(void);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.
* @param eidx_start Start of the event idx range for supported counters
* @param eidx_end End of the event idx range for supported counters
* @param cmap A bitmap representing counters supporting the event range
* @return 0 on success, error otherwise.
*/
int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
/**
* Add the raw hardware event selector and supported counter information. This
* should be called from the platform code to update the mapping table.
* @param info a pointer to the hardware event info
* @return 0 on success, error otherwise.
*/
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval);
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flag);
int sbi_pmu_ctr_start(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, uint64_t ival);
int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info);
int sbi_pmu_event_get_info(unsigned long shmem_lo, unsigned long shmem_high,
unsigned long num_events, unsigned long flags);
unsigned long sbi_pmu_num_ctr(void);
int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, unsigned long event_idx,
uint64_t event_data);
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id);
void sbi_pmu_ovf_irq();
#endif

Some files were not shown because too many files have changed in this diff Show More