mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
updating riscv-isa-sim vendored repo
This commit is contained in:
parent
4c2a406590
commit
8626131ca6
2326 changed files with 331161 additions and 6 deletions
2
vendor/riscv-isa-sim/.github/workflows/apt-packages.txt
vendored
Normal file
2
vendor/riscv-isa-sim/.github/workflows/apt-packages.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
build-essential
|
||||
device-tree-compiler
|
28
vendor/riscv-isa-sim/.github/workflows/continuous-integration.yml
vendored
Normal file
28
vendor/riscv-isa-sim/.github/workflows/continuous-integration.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# This file describes the GitHub Actions workflow for continuous integration of Spike.
|
||||
#
|
||||
# See
|
||||
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
|
||||
# for API reference documentation on this file format.
|
||||
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Spike build
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo xargs apt-get install -y < .github/workflows/apt-packages.txt
|
||||
|
||||
- run: ci-tests/test-spike
|
7
vendor/riscv-isa-sim/.gitignore
vendored
Normal file
7
vendor/riscv-isa-sim/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
build/
|
||||
*.gch
|
||||
autom4te.cache/
|
||||
.*.swp
|
||||
*.o
|
||||
*.d
|
||||
.gdb_history
|
36
vendor/riscv-isa-sim/ChangeLog.md
vendored
Normal file
36
vendor/riscv-isa-sim/ChangeLog.md
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
Version 1.1.0
|
||||
-------------
|
||||
- Zbkb, Zbkc, Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh scalar cryptography extensions (Zk, Zkn, and Zks groups), v1.0
|
||||
- Zkr virtual entropy source emulation, v1.0
|
||||
- V extension, v1.0
|
||||
- P extension, v0.9.2
|
||||
- Zba extension, v1.0
|
||||
- Zbb extension, v1.0
|
||||
- Zbc extension, v1.0
|
||||
- Zbs extension, v1.0
|
||||
- Hypervisor extension, v1.0
|
||||
- Svnapot extension, v1.0
|
||||
- Svpbmt extension, v1.0
|
||||
- Svinval extension, v1.0
|
||||
|
||||
Version 1.0.1-dev
|
||||
-----------------
|
||||
- Preliminary support for a subset of the Vector Extension, v0.7.1.
|
||||
- Support S-mode vectored interrupts (i.e. `stvec[0]` is now writable).
|
||||
- Added support for dynamic linking of libraries containing MMIO devices.
|
||||
- Added `--priv` flag to control which privilege modes are available.
|
||||
- When the commit log is enabled at configure time (`--enable-commitlog`),
|
||||
it must also be enabled at runtime with the `--log-commits` option.
|
||||
- Several debug-related additions and changes:
|
||||
- Added `hasel` debug feature.
|
||||
- Added `--dm-no-abstract-csr` command-line option.
|
||||
- Added `--dm-no-halt-groups` command line option.
|
||||
- Renamed `--progsize` to `--dm-progsize`.
|
||||
- Renamed `--debug-sba` to `--dm-sba`.
|
||||
- Renamed `--debug-auth` to `--dm-auth`.
|
||||
- Renamed `--abstract-rti` to `--dm-abstract-rti`.
|
||||
- Renamed `--without-hasel` to `--dm-no-hasel`.
|
||||
|
||||
Version 1.0.0 (2019-03-30)
|
||||
--------------------------
|
||||
- First versioned release.
|
24
vendor/riscv-isa-sim/LICENSE
vendored
Normal file
24
vendor/riscv-isa-sim/LICENSE
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2010-2017, The Regents of the University of California
|
||||
(Regents). All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the Regents nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
524
vendor/riscv-isa-sim/Makefile.in
vendored
Normal file
524
vendor/riscv-isa-sim/Makefile.in
vendored
Normal file
|
@ -0,0 +1,524 @@
|
|||
#=========================================================================
|
||||
# Toplevel Makefile for the Modular C++ Build System
|
||||
#=========================================================================
|
||||
# Please read the documenation in 'mcppbs-doc.txt' for more details on
|
||||
# how the Modular C++ Build System works. For most projects, a developer
|
||||
# will not need to make any changes to this makefile. The key targets
|
||||
# are as follows:
|
||||
#
|
||||
# - default : build all libraries and programs
|
||||
# - check : build and run all unit tests
|
||||
# - install : install headers, project library, and some programs
|
||||
# - clean : remove all generated content (except autoconf files)
|
||||
# - dist : make a source tarball
|
||||
# - distcheck : make a source tarball, untar it, check it, clean it
|
||||
# - distclean : remove everything
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Basic setup
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# Remove all default implicit rules since they can cause subtle bugs
|
||||
# and they just make things run slower
|
||||
.SUFFIXES:
|
||||
% : %,v
|
||||
% : RCS/%,v
|
||||
% : RCS/%
|
||||
% : s.%
|
||||
% : SCCS/s.%
|
||||
|
||||
# Default is to build the prereqs of the all target (defined at bottom)
|
||||
default : all
|
||||
.PHONY : default
|
||||
|
||||
project_name := @PACKAGE_TARNAME@
|
||||
src_dir := @srcdir@
|
||||
scripts_dir := $(src_dir)/scripts
|
||||
|
||||
HAVE_INT128 := @HAVE_INT128@
|
||||
HAVE_DLOPEN := @HAVE_DLOPEN@
|
||||
HAVE_CLANG_PCH := @HAVE_CLANG_PCH@
|
||||
|
||||
# If the version information is not in the configure script, then we
|
||||
# assume that we are in a working directory. We use the vcs-version.sh
|
||||
# script in the scripts directory to generate an appropriate version
|
||||
# string. Currently the way things are setup we have to run this script
|
||||
# everytime we run make so the script needs to be as fast as possible.
|
||||
|
||||
ifeq (@PACKAGE_VERSION@,?)
|
||||
project_ver:=$(shell $(scripts_dir)/vcs-version.sh $(src_dir))
|
||||
else
|
||||
project_ver:=@PACKAGE_VERSION@
|
||||
endif
|
||||
|
||||
# Installation directories
|
||||
|
||||
prefix ?= @prefix@
|
||||
|
||||
INSTALLDIR ?= $(DESTDIR)$(prefix)
|
||||
|
||||
install_hdrs_dir := $(INSTALLDIR)/include
|
||||
install_libs_dir := $(INSTALLDIR)/lib
|
||||
install_exes_dir := $(INSTALLDIR)/bin
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# List of subprojects
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
sprojs := @subprojects@
|
||||
sprojs_enabled := @subprojects_enabled@
|
||||
|
||||
sprojs_include := -I. -I$(src_dir) $(addprefix -I$(src_dir)/, $(sprojs_enabled))
|
||||
VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled))
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Programs and flags
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# C++ compiler
|
||||
# - CPPFLAGS : flags for the preprocessor (eg. -I,-D)
|
||||
# - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3)
|
||||
#
|
||||
# To allow a user to specify CFLAGS or similar as part of the Make
|
||||
# command, we also have mcpps-CFLAGS etc. with stuff that shouldn't be
|
||||
# lost in such a case.
|
||||
#
|
||||
# The order of precedence (highest to lowest) is then:
|
||||
#
|
||||
# - Specified as part of Make command line
|
||||
# - Specified as part of running configure
|
||||
# - Specified here (default-CFLAGS)
|
||||
#
|
||||
# These all appear on the command line, from lowest precedence to
|
||||
# highest.
|
||||
|
||||
default-CFLAGS := -DPREFIX=\"$(prefix)\" -Wall -Wno-unused -Wno-nonportable-include-path -g -O2 -fPIC
|
||||
default-CXXFLAGS := $(default-CFLAGS) -std=c++17
|
||||
|
||||
mcppbs-CPPFLAGS := @CPPFLAGS@
|
||||
mcppbs-CFLAGS := $(default-CFLAGS) @CFLAGS@
|
||||
mcppbs-CXXFLAGS := $(default-CXXFLAGS) @CXXFLAGS@
|
||||
|
||||
CC := @CC@
|
||||
CXX := @CXX@
|
||||
|
||||
# These are the flags actually used for a C++ compile or a C compile.
|
||||
# The language-specific flags come after the preprocessor flags, but
|
||||
# user-supplied flags always take precedence.
|
||||
all-cxx-flags := \
|
||||
$(mcppbs-CPPFLAGS) $(mcppbs-CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
|
||||
all-c-flags := \
|
||||
$(mcppbs-CPPFLAGS) $(mcppbs-CFLAGS) $(CPPFLAGS) $(CFLAGS)
|
||||
|
||||
COMPILE := $(CXX) -MMD -MP $(all-cxx-flags) $(sprojs_include) @BOOST_CPPFLAGS@
|
||||
COMPILE_C := $(CC) -MMD -MP $(all-c-flags) $(sprojs_include)
|
||||
|
||||
# Linker
|
||||
# - LDFLAGS : Flags for the linker (eg. -L)
|
||||
# - LIBS : Library flags (eg. -l)
|
||||
|
||||
mcppbs-LDFLAGS := @LDFLAGS@ @BOOST_LDFLAGS@
|
||||
all-link-flags := $(mcppbs-LDFLAGS) $(LDFLAGS)
|
||||
|
||||
comma := ,
|
||||
LD := $(CXX)
|
||||
LIBS := @LIBS@ @BOOST_ASIO_LIB@ @BOOST_REGEX_LIB@
|
||||
LINK := $(LD) -L. $(all-link-flags) -Wl,-rpath,$(install_libs_dir) $(patsubst -L%,-Wl$(comma)-rpath$(comma)%,$(filter -L%,$(LDFLAGS)))
|
||||
|
||||
# Library creation
|
||||
|
||||
AR := @AR@
|
||||
RANLIB := @RANLIB@
|
||||
|
||||
# Host simulator
|
||||
|
||||
RUN := @RUN@
|
||||
RUNFLAGS := @RUNFLAGS@
|
||||
|
||||
# Installation
|
||||
|
||||
MKINSTALLDIRS := $(scripts_dir)/mk-install-dirs.sh
|
||||
INSTALL := @INSTALL@
|
||||
INSTALL_HDR := $(INSTALL) -m 644
|
||||
INSTALL_LIB := $(INSTALL) -m 644
|
||||
INSTALL_EXE := $(INSTALL) -m 755
|
||||
STOW := @stow@
|
||||
|
||||
# Tests
|
||||
bintests = $(src_dir)/tests/ebreak.py
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Include subproject makefile fragments
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
sprojs_mk = $(addsuffix .mk, $(sprojs_enabled))
|
||||
|
||||
-include $(sprojs_mk)
|
||||
|
||||
dist_junk += $(sprojs_mk)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Reverse list helper function
|
||||
#-------------------------------------------------------------------------
|
||||
# This function is used by the subproject template to reverse the list
|
||||
# of dependencies. It uses recursion to perform the reversal.
|
||||
#
|
||||
# Arguments:
|
||||
# $(1) : space separated input list
|
||||
# retval : input list in reverse order
|
||||
#
|
||||
|
||||
reverse_list = $(call reverse_list_h,$(1),)
|
||||
define reverse_list_h
|
||||
$(if $(strip $(1)), \
|
||||
$(call reverse_list_h, \
|
||||
$(wordlist 2,$(words $(1)),$(1)), \
|
||||
$(firstword $(1)) $(2)), \
|
||||
$(2))
|
||||
endef
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Template for per subproject rules
|
||||
#-------------------------------------------------------------------------
|
||||
# The template is instantiated for each of the subprojects. It relies on
|
||||
# subprojects defining a certain set of make variables which are all
|
||||
# prefixed with the subproject name. Since subproject names can have
|
||||
# dashes in them (and the make variables are assumed to only use
|
||||
# underscores) the template takes two arguments - one with the regular
|
||||
# subproject name and one with dashes replaced with underscores.
|
||||
#
|
||||
# Arguments:
|
||||
# $(1) : real subproject name (ie with dashes)
|
||||
# $(2) : normalized subproject name (ie dashes replaced with underscores)
|
||||
#
|
||||
|
||||
define subproject_template
|
||||
|
||||
# In some (rare) cases, a subproject might not have any actual object
|
||||
# files. It might only include header files or program sources. To keep
|
||||
# things consistent we still want a library for this subproject, so in
|
||||
# this spectial case we create a dummy source file and thus the build
|
||||
# system will create a library for this subproject with just the
|
||||
# corresponding dummy object file.
|
||||
|
||||
ifeq ($$(strip $$($(2)_srcs) $$($(2)_c_srcs)),)
|
||||
$(2)_srcs += _$(1).cc
|
||||
$(2)_junk += _$(1).cc
|
||||
endif
|
||||
|
||||
_$(1).cc :
|
||||
echo "int _$(2)( int arg ) { return arg; }" > $$@
|
||||
|
||||
# Build the object files for this subproject
|
||||
|
||||
$(2)_pch := $$(patsubst %.h, %.h.gch, $$($(2)_precompiled_hdrs))
|
||||
$(2)_objs := $$(patsubst %.cc, %.o, $$($(2)_srcs))
|
||||
$(2)_c_objs := $$(patsubst %.c, %.o, $$($(2)_c_srcs))
|
||||
$(2)_deps := $$(patsubst %.o, %.d, $$($(2)_objs))
|
||||
$(2)_deps += $$(patsubst %.o, %.d, $$($(2)_c_objs))
|
||||
$(2)_deps += $$(patsubst %.h, %.h.d, $$($(2)_precompiled_hdrs))
|
||||
$$($(2)_pch) : %.h.gch : %.h
|
||||
$(COMPILE) -x c++-header $$< -o $$@
|
||||
$$($(2)_objs) : %.o : %.cc $$($(2)_gen_hdrs) $$($(2)_pch)
|
||||
$(COMPILE) $(if $(HAVE_CLANG_PCH), $$(if $$($(2)_pch), -include-pch $$($(2)_pch))) $$($(2)_CFLAGS) -c $$<
|
||||
$$($(2)_c_objs) : %.o : %.c $$($(2)_gen_hdrs)
|
||||
$(COMPILE_C) $$($(2)_CFLAGS) -c $$<
|
||||
|
||||
$(2)_junk += $$($(2)_pch) $$($(2)_objs) $$($(2)_c_objs) $$($(2)_deps) \
|
||||
$$($(2)_gen_hdrs)
|
||||
|
||||
# Reverse the dependency list so that a given subproject only depends on
|
||||
# subprojects listed to its right. This is the correct order for linking
|
||||
# the list of subproject libraries.
|
||||
|
||||
$(2)_reverse_deps := $$(call reverse_list,$$($(2)_subproject_deps))
|
||||
|
||||
# Build a library for this subproject
|
||||
|
||||
$(2)_lib_libs := $$($(2)_reverse_deps)
|
||||
$(2)_lib_libnames := $$(patsubst %, lib%.a, $$($(2)_lib_libs))
|
||||
$(2)_lib_libarg := $$(patsubst %, -l%, $$($(2)_lib_libs))
|
||||
$(2)_lib_libnames_shared := $$(if $$($(2)_install_shared_lib),lib$(1).so,)
|
||||
|
||||
lib$(1).a : $$($(2)_objs) $$($(2)_c_objs) $$($(2)_lib_libnames)
|
||||
$(AR) rcs $$@ $$^
|
||||
lib$(1).so : $$($(2)_objs) $$($(2)_c_objs) $$($(2)_lib_libnames_shared) $$($(2)_lib_libnames)
|
||||
$(LINK) -shared -o $$@ $(if $(filter Darwin,$(shell uname -s)),-install_name $(install_libs_dir)/$$@) $$^ $$($(2)_lib_libnames) $(LIBS)
|
||||
|
||||
$(2)_junk += lib$(1).a
|
||||
$(2)_junk += $$(if $$($(2)_install_shared_lib),lib$(1).so,)
|
||||
|
||||
# Build unit tests
|
||||
|
||||
$(2)_test_objs := $$(patsubst %.cc, %.o, $$($(2)_test_srcs))
|
||||
$(2)_test_deps := $$(patsubst %.o, %.d, $$($(2)_test_objs))
|
||||
$(2)_test_exes := $$(patsubst %.t.cc, %-utst, $$($(2)_test_srcs))
|
||||
$(2)_test_outs := $$(patsubst %, %.out, $$($(2)_test_exes))
|
||||
$(2)_test_libs := $(1) $$($(2)_reverse_deps) utst
|
||||
$(2)_test_libnames := $$(patsubst %, lib%.a, $$($(2)_test_libs))
|
||||
$(2)_test_libarg := $$(patsubst %, -l%, $$($(2)_test_libs))
|
||||
|
||||
$$($(2)_test_objs) : %.o : %.cc
|
||||
$(COMPILE) -c $$<
|
||||
|
||||
$$($(2)_test_exes) : %-utst : %.t.o $$($(2)_test_libnames)
|
||||
$(LINK) -o $$@ $$< $$($(2)_test_libnames) $(LIBS)
|
||||
|
||||
$(2)_deps += $$($(2)_test_deps)
|
||||
$(2)_junk += \
|
||||
$$($(2)_test_objs) $$($(2)_test_deps) \
|
||||
$$($(2)_test_exes) *.junk-dat
|
||||
|
||||
# Run unit tests
|
||||
|
||||
$$($(2)_test_outs) : %.out : %
|
||||
$(RUN) $(RUNFLAGS) ./$$< default | tee $$@
|
||||
|
||||
$(2)_junk += $$($(2)_test_outs)
|
||||
|
||||
# Build programs
|
||||
|
||||
$(2)_prog_objs := $$(patsubst %.cc, %.o, $$($(2)_prog_srcs))
|
||||
$(2)_prog_deps := $$(patsubst %.o, %.d, $$($(2)_prog_objs))
|
||||
$(2)_prog_exes := $$(patsubst %.cc, %, $$($(2)_prog_srcs))
|
||||
$(2)_prog_libs := $(1) $$($(2)_reverse_deps)
|
||||
$(2)_prog_libnames := $$(patsubst %, lib%.a, $$($(2)_prog_libs))
|
||||
$(2)_prog_libarg := $$(patsubst %, -l%, $$($(2)_prog_libs))
|
||||
|
||||
$$($(2)_prog_objs) : %.o : %.cc
|
||||
$(COMPILE) -c $$<
|
||||
|
||||
$$($(2)_prog_exes) : % : %.o $$($(2)_prog_libnames)
|
||||
$(LINK) -o $$@ $$< $$($(2)_prog_libnames) $(LIBS)
|
||||
|
||||
$(2)_deps += $$($(2)_prog_deps)
|
||||
$(2)_junk += $$($(2)_prog_objs) $$($(2)_prog_deps) $$($(2)_prog_exes)
|
||||
|
||||
# Build programs which will be installed
|
||||
|
||||
$(2)_install_prog_objs := $$(patsubst %.cc, %.o, $$($(2)_install_prog_srcs))
|
||||
$(2)_install_prog_deps := $$(patsubst %.o, %.d, $$($(2)_install_prog_objs))
|
||||
$(2)_install_prog_exes := $$(patsubst %.cc, %, $$($(2)_install_prog_srcs))
|
||||
|
||||
$$($(2)_install_prog_objs) : %.o : %.cc $$($(2)_gen_hdrs)
|
||||
$(COMPILE) -c $$<
|
||||
|
||||
$$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames)
|
||||
$(LINK) -o $$@ $$< $$($(2)_prog_libnames) $(LIBS)
|
||||
|
||||
$(2)_deps += $$($(2)_install_prog_deps)
|
||||
$(2)_junk += \
|
||||
$$($(2)_install_prog_objs) $$($(2)_install_prog_deps) \
|
||||
$$($(2)_install_prog_exes)
|
||||
|
||||
# Subproject specific targets
|
||||
|
||||
all-$(1) : lib$(1).a $$($(2)_install_prog_exes)
|
||||
|
||||
check-$(1) : $$($(2)_test_outs)
|
||||
echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $$^; echo
|
||||
|
||||
clean-$(1) :
|
||||
rm -rf $$($(2)_junk)
|
||||
|
||||
.PHONY : all-$(1) check-$(1) clean-$(1)
|
||||
|
||||
# Update running variables
|
||||
|
||||
libs += lib$(1).a
|
||||
objs += $$($(2)_objs)
|
||||
srcs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_srcs))
|
||||
hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs)) $$($(2)_gen_hdrs)
|
||||
junk += $$($(2)_junk)
|
||||
deps += $$($(2)_deps)
|
||||
|
||||
test_outs += $$($(2)_test_outs)
|
||||
|
||||
install_config_hdrs += $$(if $$($(2)_install_config_hdr),$(1),)
|
||||
install_hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_install_hdrs))
|
||||
install_libs += $$(if $$($(2)_install_lib),lib$(1).a,)
|
||||
install_libs += $$(if $$($(2)_install_shared_lib),lib$(1).so,)
|
||||
install_exes += $$($(2)_install_prog_exes)
|
||||
install_pcs += $$(if $$($(2)_install_lib),riscv-$(1).pc,)
|
||||
|
||||
endef
|
||||
|
||||
# Iterate over the subprojects and call the template for each one
|
||||
|
||||
$(foreach sproj,$(sprojs_enabled), \
|
||||
$(eval $(call subproject_template,$(sproj),$(subst -,_,$(sproj)))))
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Autodependency files
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
-include $(deps)
|
||||
|
||||
deps : $(deps)
|
||||
.PHONY : deps
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
bintest_outs = $(bintests:=.out)
|
||||
junk += $(bintest_outs)
|
||||
%.out: % all
|
||||
./$* < /dev/null 2>&1 | tee $@
|
||||
|
||||
check-cpp : $(test_outs)
|
||||
@echo
|
||||
! grep -h -e'Unit Tests' -e'FAILED' -e'Segmentation' $^ < /dev/null
|
||||
@echo
|
||||
|
||||
check-bin : $(bintest_outs)
|
||||
! tail -n 1 $^ < /dev/null 2>&1 | grep FAILED
|
||||
|
||||
check : check-cpp check-bin
|
||||
|
||||
.PHONY : check
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Installation
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
install-config-hdrs : config.h
|
||||
$(MKINSTALLDIRS) $(install_hdrs_dir)
|
||||
for dir in $(install_config_hdrs); \
|
||||
do \
|
||||
$(MKINSTALLDIRS) $(install_hdrs_dir)/$$dir; \
|
||||
$(INSTALL_HDR) $< $(install_hdrs_dir)/$$dir; \
|
||||
done
|
||||
|
||||
install-hdrs : $(install_hdrs)
|
||||
$(MKINSTALLDIRS) $(install_hdrs_dir)
|
||||
for file in $(subst $(src_dir)/,,$^); \
|
||||
do \
|
||||
$(MKINSTALLDIRS) $(install_hdrs_dir)/`dirname $$file`; \
|
||||
$(INSTALL_HDR) $(src_dir)/$$file $(install_hdrs_dir)/`dirname $$file`; \
|
||||
done
|
||||
|
||||
install-libs : $(install_libs)
|
||||
$(MKINSTALLDIRS) $(install_libs_dir)
|
||||
for file in $^; \
|
||||
do \
|
||||
$(INSTALL_LIB) $$file $(install_libs_dir); \
|
||||
done
|
||||
|
||||
install-exes : $(install_exes)
|
||||
$(MKINSTALLDIRS) $(install_exes_dir)
|
||||
for file in $^; \
|
||||
do \
|
||||
$(INSTALL_EXE) $$file $(install_exes_dir); \
|
||||
done
|
||||
|
||||
install-pc : $(install_pcs)
|
||||
$(MKINSTALLDIRS) $(install_libs_dir)/pkgconfig/
|
||||
for file in $^; \
|
||||
do \
|
||||
$(INSTALL_HDR) $$file $(install_libs_dir)/pkgconfig/; \
|
||||
done
|
||||
|
||||
install : install-hdrs install-config-hdrs install-libs install-exes install-pc
|
||||
|
||||
.PHONY : install install-hdrs install-config-hdrs install-libs install-exes
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Regenerate configure information
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
config.status : $(src_dir)/configure
|
||||
./config.status --recheck
|
||||
|
||||
sprojs_mk_in = \
|
||||
$(join $(addprefix $(src_dir)/, $(sprojs_enabled)), \
|
||||
$(patsubst %, /%.mk.in, $(sprojs_enabled)))
|
||||
|
||||
Makefile : $(src_dir)/Makefile.in $(sprojs_mk_in) config.status
|
||||
./config.status
|
||||
|
||||
dist_junk += config.status config.h Makefile config.log
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Distribution
|
||||
#-------------------------------------------------------------------------
|
||||
# The distribution tarball is named project-ver.tar.gz and it includes
|
||||
# both enabled and disabled subprojects.
|
||||
|
||||
dist_files = \
|
||||
$(sprojs) \
|
||||
README \
|
||||
style-guide.txt \
|
||||
mcppbs-uguide.txt \
|
||||
scripts \
|
||||
configure.ac \
|
||||
aclocal.m4 \
|
||||
configure \
|
||||
config.h.in \
|
||||
Makefile.in \
|
||||
|
||||
dist_dir := $(project_name)-$(project_ver)
|
||||
dist_tgz := $(project_name)-$(project_ver).tar.gz
|
||||
|
||||
# Notice that when we make the distribution we rewrite the configure.ac
|
||||
# script with the current version and we rerun autoconf in the new
|
||||
# source directory so that the distribution will have the proper version
|
||||
# information. We also rewrite the "Version : " line in the README.
|
||||
|
||||
dist :
|
||||
rm -rf $(dist_dir)
|
||||
mkdir $(dist_dir)
|
||||
tar -C $(src_dir) -cf - $(dist_files) | tar -C $(dist_dir) -xpf -
|
||||
sed -i.bak 's/^\(# Version :\).*/\1 $(project_ver)/' $(dist_dir)/README
|
||||
sed -i.bak 's/\( proj_version,\).*/\1 [$(project_ver)])/' $(dist_dir)/configure.ac
|
||||
cd $(dist_dir) && \
|
||||
autoconf && autoheader && \
|
||||
rm -rf autom4te.cache configure.ac.bak README.bak
|
||||
tar -czvf $(dist_tgz) $(dist_dir)
|
||||
rm -rf $(dist_dir)
|
||||
|
||||
# You can use the distcheck target to try untarring the distribution and
|
||||
# then running configure, make, make check, and make distclean. A
|
||||
# "directory is not empty" error means distclean is not removing
|
||||
# everything.
|
||||
|
||||
distcheck : dist
|
||||
rm -rf $(dist_dir)
|
||||
tar -xzvf $(dist_tgz)
|
||||
mkdir -p $(dist_dir)/build
|
||||
cd $(dist_dir)/build; ../configure; make; make check; make distclean
|
||||
rm -rf $(dist_dir)
|
||||
|
||||
junk += $(project_name)-*.tar.gz
|
||||
|
||||
.PHONY : dist distcheck
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Default
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
all : $(install_hdrs) $(install_libs) $(install_exes)
|
||||
.PHONY : all
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Makefile debugging
|
||||
#-------------------------------------------------------------------------
|
||||
# This handy rule will display the contents of any make variable by
|
||||
# using the target debug-<varname>. So for example, make debug-junk will
|
||||
# display the contents of the junk variable.
|
||||
|
||||
debug-% :
|
||||
@echo $* = $($*)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Clean up junk
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
clean :
|
||||
rm -rf *~ \#* $(junk)
|
||||
|
||||
distclean :
|
||||
rm -rf *~ \#* $(junk) $(dist_junk)
|
||||
|
||||
.PHONY : clean distclean
|
300
vendor/riscv-isa-sim/README.md
vendored
Normal file
300
vendor/riscv-isa-sim/README.md
vendored
Normal file
|
@ -0,0 +1,300 @@
|
|||
Spike RISC-V ISA Simulator
|
||||
============================
|
||||
|
||||
About
|
||||
-------------
|
||||
|
||||
Spike, the RISC-V ISA Simulator, implements a functional model of one or more
|
||||
RISC-V harts. It is named after the golden spike used to celebrate the
|
||||
completion of the US transcontinental railway.
|
||||
|
||||
Spike supports the following RISC-V ISA features:
|
||||
- RV32I and RV64I base ISAs, v2.1
|
||||
- RV32E and RV64E base ISAs, v1.9
|
||||
- Zifencei extension, v2.0
|
||||
- Zicsr extension, v2.0
|
||||
- M extension, v2.0
|
||||
- A extension, v2.1
|
||||
- F extension, v2.2
|
||||
- D extension, v2.2
|
||||
- Q extension, v2.2
|
||||
- C extension, v2.0
|
||||
- Zbkb, Zbkc, Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh scalar cryptography extensions (Zk, Zkn, and Zks groups), v1.0
|
||||
- Zkr virtual entropy source emulation, v1.0
|
||||
- V extension, v1.0 (_requires a 64-bit host_)
|
||||
- P extension, v0.9.2
|
||||
- Zba extension, v1.0
|
||||
- Zbb extension, v1.0
|
||||
- Zbc extension, v1.0
|
||||
- Zbs extension, v1.0
|
||||
- Conformance to both RVWMO and RVTSO (Spike is sequentially consistent)
|
||||
- Machine, Supervisor, and User modes, v1.11
|
||||
- Hypervisor extension, v1.0
|
||||
- Svnapot extension, v1.0
|
||||
- Svpbmt extension, v1.0
|
||||
- Svinval extension, v1.0
|
||||
- CMO extension, v1.0
|
||||
- Debug v0.14
|
||||
|
||||
As a Spike extension, the remainder of the proposed
|
||||
[Bit-Manipulation Extensions](https://github.com/riscv/riscv-bitmanip)
|
||||
is provided under the Spike-custom extension name _Xbitmanip_.
|
||||
These instructions (and, of course, the extension name) are not RISC-V
|
||||
standards.
|
||||
|
||||
These proposed bit-manipulation extensions can be split into further
|
||||
groups: Zbp, Zbs, Zbe, Zbf, Zbc, Zbm, Zbr, Zbt. Note that Zbc is
|
||||
ratified, but the original proposal contained some extra instructions
|
||||
(64-bit carryless multiplies) which are captured here.
|
||||
|
||||
To enable these extensions individually, use the Spike-custom
|
||||
extension names _XZbp_, _XZbs_, _XZbc_, and so on.
|
||||
|
||||
Versioning and APIs
|
||||
-------------------
|
||||
|
||||
Projects are versioned primarily to indicate when the API has been extended or
|
||||
rendered incompatible. In that spirit, Spike aims to follow the
|
||||
[SemVer](https://semver.org/spec/v2.0.0.html) versioning scheme, in which
|
||||
major version numbers are incremented when backwards-incompatible API changes
|
||||
are made; minor version numbers are incremented when new APIs are added; and
|
||||
patch version numbers are incremented when bugs are fixed in
|
||||
a backwards-compatible manner.
|
||||
|
||||
Spike's principal public API is the RISC-V ISA. _The C++ interface to Spike's
|
||||
internals is **not** considered a public API at this time_, and
|
||||
backwards-incompatible changes to this interface _will_ be made without
|
||||
incrementing the major version number.
|
||||
|
||||
Build Steps
|
||||
---------------
|
||||
|
||||
We assume that the RISCV environment variable is set to the RISC-V tools
|
||||
install path.
|
||||
|
||||
$ apt-get install device-tree-compiler
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../configure --prefix=$RISCV
|
||||
$ make
|
||||
$ [sudo] make install
|
||||
|
||||
If your system uses the `yum` package manager, you can substitute
|
||||
`yum install dtc` for the first step.
|
||||
|
||||
Build Steps on OpenBSD
|
||||
----------------------
|
||||
|
||||
Install bash, gmake, dtc, and use clang.
|
||||
|
||||
$ pkg_add bash gmake dtc
|
||||
$ exec bash
|
||||
$ export CC=cc; export CXX=c++
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../configure --prefix=$RISCV
|
||||
$ gmake
|
||||
$ [doas] make install
|
||||
|
||||
Compiling and Running a Simple C Program
|
||||
-------------------------------------------
|
||||
|
||||
Install spike (see Build Steps), riscv-gnu-toolchain, and riscv-pk.
|
||||
|
||||
Write a short C program and name it hello.c. Then, compile it into a RISC-V
|
||||
ELF binary named hello:
|
||||
|
||||
$ riscv64-unknown-elf-gcc -o hello hello.c
|
||||
|
||||
Now you can simulate the program atop the proxy kernel:
|
||||
|
||||
$ spike pk hello
|
||||
|
||||
Simulating a New Instruction
|
||||
------------------------------------
|
||||
|
||||
Adding an instruction to the simulator requires two steps:
|
||||
|
||||
1. Describe the instruction's functional behavior in the file
|
||||
riscv/insns/<new_instruction_name>.h. Examine other instructions
|
||||
in that directory as a starting point.
|
||||
|
||||
2. Add the opcode and opcode mask to riscv/opcodes.h. Alternatively,
|
||||
add it to the riscv-opcodes package, and it will do so for you:
|
||||
```
|
||||
$ cd ../riscv-opcodes
|
||||
$ vi opcodes // add a line for the new instruction
|
||||
$ make install
|
||||
```
|
||||
|
||||
3. Rebuild the simulator.
|
||||
|
||||
Interactive Debug Mode
|
||||
---------------------------
|
||||
|
||||
To invoke interactive debug mode, launch spike with -d:
|
||||
|
||||
$ spike -d pk hello
|
||||
|
||||
To see the contents of an integer register (0 is for core 0):
|
||||
|
||||
: reg 0 a0
|
||||
|
||||
To see the contents of a floating point register:
|
||||
|
||||
: fregs 0 ft0
|
||||
|
||||
or:
|
||||
|
||||
: fregd 0 ft0
|
||||
|
||||
depending upon whether you wish to print the register as single- or double-precision.
|
||||
|
||||
To see the contents of a memory location (physical address in hex):
|
||||
|
||||
: mem 2020
|
||||
|
||||
To see the contents of memory with a virtual address (0 for core 0):
|
||||
|
||||
: mem 0 2020
|
||||
|
||||
You can advance by one instruction by pressing the enter key. You can also
|
||||
execute until a desired equality is reached:
|
||||
|
||||
: until pc 0 2020 (stop when pc=2020)
|
||||
: until reg 0 mie a (stop when register mie=0xa)
|
||||
: until mem 2020 50a9907311096993 (stop when mem[2020]=50a9907311096993)
|
||||
|
||||
Alternatively, you can execute as long as an equality is true:
|
||||
|
||||
: while mem 2020 50a9907311096993
|
||||
|
||||
You can continue execution indefinitely by:
|
||||
|
||||
: r
|
||||
|
||||
At any point during execution (even without -d), you can enter the
|
||||
interactive debug mode with `<control>-<c>`.
|
||||
|
||||
To end the simulation from the debug prompt, press `<control>-<c>` or:
|
||||
|
||||
: q
|
||||
|
||||
Debugging With Gdb
|
||||
------------------
|
||||
|
||||
An alternative to interactive debug mode is to attach using gdb. Because spike
|
||||
tries to be like real hardware, you also need OpenOCD to do that. OpenOCD
|
||||
doesn't currently know about address translation, so it's not possible to
|
||||
easily debug programs that are run under `pk`. We'll use the following test
|
||||
program:
|
||||
```
|
||||
$ cat rot13.c
|
||||
char text[] = "Vafgehpgvba frgf jnag gb or serr!";
|
||||
|
||||
// Don't use the stack, because sp isn't set up.
|
||||
volatile int wait = 1;
|
||||
|
||||
int main()
|
||||
{
|
||||
while (wait)
|
||||
;
|
||||
|
||||
// Doesn't actually go on the stack, because there are lots of GPRs.
|
||||
int i = 0;
|
||||
while (text[i]) {
|
||||
char lower = text[i] | 32;
|
||||
if (lower >= 'a' && lower <= 'm')
|
||||
text[i] += 13;
|
||||
else if (lower > 'm' && lower <= 'z')
|
||||
text[i] -= 13;
|
||||
i++;
|
||||
}
|
||||
|
||||
done:
|
||||
while (!wait)
|
||||
;
|
||||
}
|
||||
$ cat spike.lds
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x10010000;
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
}
|
||||
$ riscv64-unknown-elf-gcc -g -Og -o rot13-64.o -c rot13.c
|
||||
$ riscv64-unknown-elf-gcc -g -Og -T spike.lds -nostartfiles -o rot13-64 rot13-64.o
|
||||
```
|
||||
|
||||
To debug this program, first run spike telling it to listen for OpenOCD:
|
||||
```
|
||||
$ spike --rbb-port=9824 -m0x10000000:0x20000 rot13-64
|
||||
Listening for remote bitbang connection on port 9824.
|
||||
```
|
||||
|
||||
In a separate shell run OpenOCD with the appropriate configuration file:
|
||||
```
|
||||
$ cat spike.cfg
|
||||
interface remote_bitbang
|
||||
remote_bitbang_host localhost
|
||||
remote_bitbang_port 9824
|
||||
|
||||
set _CHIPNAME riscv
|
||||
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
|
||||
|
||||
gdb_report_data_abort enable
|
||||
|
||||
init
|
||||
halt
|
||||
$ openocd -f spike.cfg
|
||||
Open On-Chip Debugger 0.10.0-dev-00002-gc3b344d (2017-06-08-12:14)
|
||||
...
|
||||
riscv.cpu: target state: halted
|
||||
```
|
||||
|
||||
In yet another shell, start your gdb debug session:
|
||||
```
|
||||
tnewsome@compy-vm:~/SiFive/spike-test$ riscv64-unknown-elf-gdb rot13-64
|
||||
GNU gdb (GDB) 8.0.50.20170724-git
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
|
||||
and "show warranty" for details.
|
||||
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
|
||||
Type "show configuration" for configuration details.
|
||||
For bug reporting instructions, please see:
|
||||
<http://www.gnu.org/software/gdb/bugs/>.
|
||||
Find the GDB manual and other documentation resources online at:
|
||||
<http://www.gnu.org/software/gdb/documentation/>.
|
||||
For help, type "help".
|
||||
Type "apropos word" to search for commands related to "word"...
|
||||
Reading symbols from rot13-64...done.
|
||||
(gdb) target remote localhost:3333
|
||||
Remote debugging using localhost:3333
|
||||
0x0000000010010004 in main () at rot13.c:8
|
||||
8 while (wait)
|
||||
(gdb) print wait
|
||||
$1 = 1
|
||||
(gdb) print wait=0
|
||||
$2 = 0
|
||||
(gdb) print text
|
||||
$3 = "Vafgehpgvba frgf jnag gb or serr!"
|
||||
(gdb) b done
|
||||
Breakpoint 1 at 0x10010064: file rot13.c, line 22.
|
||||
(gdb) c
|
||||
Continuing.
|
||||
Disabling abstract command writes to CSRs.
|
||||
|
||||
Breakpoint 1, main () at rot13.c:23
|
||||
23 while (!wait)
|
||||
(gdb) print wait
|
||||
$4 = 0
|
||||
(gdb) print text
|
||||
...
|
||||
```
|
1
vendor/riscv-isa-sim/VERSION
vendored
Normal file
1
vendor/riscv-isa-sim/VERSION
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#define SPIKE_VERSION "1.1.1-dev"
|
302
vendor/riscv-isa-sim/aclocal.m4
vendored
Normal file
302
vendor/riscv-isa-sim/aclocal.m4
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
#=========================================================================
|
||||
# Local Autoconf Macros
|
||||
#=========================================================================
|
||||
# This file contains the macros for the Modular C++ Build System and
|
||||
# additional autoconf macros which developers can use in their
|
||||
# configure.ac scripts. Please read the documentation in
|
||||
# 'mcppbs-doc.txt' for more details on how the Modular C++ Build System
|
||||
# works. The documenation for each macro should include information
|
||||
# about the author, date, and copyright.
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS_PROG_INSTALL
|
||||
#-------------------------------------------------------------------------
|
||||
# This macro will add an --enable-stow command line option to the
|
||||
# configure script. When enabled, this macro will first check to see if
|
||||
# the stow program is available and if so it will set the $stow shell
|
||||
# variable to the binary name and the $enable_stow shell variable to
|
||||
# "yes". These variables can be used in a makefile to conditionally use
|
||||
# stow for installation.
|
||||
#
|
||||
# This macro uses two environment variables to help setup default stow
|
||||
# locations. The $STOW_PREFIX is used for stowing native built packages.
|
||||
# The packages are staged in $STOW_PREFIX/pkgs and then symlinks are
|
||||
# created from within $STOW_PREFIX into the pkgs subdirectory. If you
|
||||
# only do native builds then this is all you need to set. If you don't
|
||||
# set $STOW_PREFIX then the default is just the normal default prefix
|
||||
# which is almost always /usr/local.
|
||||
#
|
||||
# For non-native builds we probably want to install the packages in a
|
||||
# different location which includes the host architecture name as part
|
||||
# of the prefix. For these kind of builds, we can specify the $STOW_ROOT
|
||||
# environment variable and the effective prefix will be
|
||||
# $STOW_ROOT/${host_alias} where ${host_alias} is specified on the
|
||||
# configure command line with "--host".
|
||||
#
|
||||
# Here is an example setup:
|
||||
#
|
||||
# STOW_ROOT="$HOME/install"
|
||||
# STOW_ARCH="i386-macosx10.4"
|
||||
# STOW_PREFIX="${STOW_ROOT}/${STOW_ARCH}"
|
||||
#
|
||||
|
||||
AC_DEFUN([MCPPBS_PROG_INSTALL],
|
||||
[
|
||||
|
||||
# Configure command line option
|
||||
|
||||
AC_ARG_ENABLE(stow,
|
||||
AS_HELP_STRING(--enable-stow,[Enable stow-based install]),
|
||||
[enable_stow="yes"],[enable_stow="no"])
|
||||
|
||||
AC_SUBST([enable_stow])
|
||||
|
||||
# Environment variables
|
||||
|
||||
AC_ARG_VAR([STOW_ROOT], [Root for non-native stow-based installs])
|
||||
AC_ARG_VAR([STOW_PREFIX], [Prefix for stow-based installs])
|
||||
|
||||
# Check for install script
|
||||
|
||||
AC_PROG_INSTALL
|
||||
])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS_PROG_RUN
|
||||
# -------------------------------------------------------------------------
|
||||
# If we are doing a non-native build then we look for an isa simulator
|
||||
# to use for running tests. We set the RUN substitution variable to be
|
||||
# empty for native builds or to the name of the isa simulator for
|
||||
# non-native builds. Thus a makefile can run compiled programs
|
||||
# regardless if we are doing a native or non-native build like this:
|
||||
#
|
||||
# $(RUN) $(RUNFLAGS) ./test-program
|
||||
#
|
||||
|
||||
AC_DEFUN([MCPPBS_PROG_RUN],
|
||||
[
|
||||
AS_IF([ test "${build}" != "${host}" ],
|
||||
[
|
||||
AC_CHECK_TOOLS([RUN],[isa-run run],[no])
|
||||
AS_IF([ test ${RUN} = "no" ],
|
||||
[
|
||||
AC_MSG_ERROR([Cannot find simulator for target ${target_alias}])
|
||||
])
|
||||
],[
|
||||
RUN=""
|
||||
])
|
||||
AC_SUBST([RUN])
|
||||
AC_SUBST([RUNFLAGS])
|
||||
])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS_SUBPROJECTS([ sproj1, sproj2, ... ])
|
||||
#-------------------------------------------------------------------------
|
||||
# The developer should call this macro with a list of the subprojects
|
||||
# which make up this project. One should order the list such that any
|
||||
# given subproject only depends on subprojects listed before it. The
|
||||
# subproject names can also include an * suffix which indicates that
|
||||
# this is an optional subproject. Optional subprojects are only included
|
||||
# as part of the project build if enabled on the configure command line
|
||||
# with a --enable-<subproject> flag. The user can also specify that all
|
||||
# optional subprojects should be included in the build with the
|
||||
# --enable-optional-subprojects flag.
|
||||
#
|
||||
# Subproject names can also include a ** suffix which indicates that it
|
||||
# is an optional subproject, but there is a group with the same name.
|
||||
# Thus the --enable-<sproj> command line option will enable not just the
|
||||
# subproject sproj but all of the subprojects which are in the group.
|
||||
# There is no error checking to make sure that if you use the ** suffix
|
||||
# you actually define a group so be careful.
|
||||
#
|
||||
# Both required and optional subprojects should have a 'subproject.ac'
|
||||
# file. The script's filename should be the abbreivated subproject name
|
||||
# (assuming the subproject name is sproj then we would use 'sproj.ac')
|
||||
# The MCPPBS_SUBPROJECTS macro includes the 'subproject.ac' files for
|
||||
# enabled subprojects. Whitespace and newlines are allowed within the
|
||||
# list.
|
||||
#
|
||||
# Author : Christopher Batten
|
||||
# Date : September 10, 2008
|
||||
|
||||
AC_DEFUN([MCPPBS_SUBPROJECTS],
|
||||
[
|
||||
|
||||
# Add command line argument to enable all optional subprojects
|
||||
|
||||
AC_ARG_ENABLE(optional-subprojects,
|
||||
AS_HELP_STRING([--enable-optional-subprojects],
|
||||
[Enable all optional subprojects]))
|
||||
|
||||
# Loop through the subprojects given in the macro argument
|
||||
|
||||
m4_foreach([MCPPBS_SPROJ],[$1],
|
||||
[
|
||||
|
||||
# Determine if this is a required or an optional subproject
|
||||
|
||||
m4_define([MCPPBS_IS_REQ],
|
||||
m4_bmatch(MCPPBS_SPROJ,[\*+],[false],[true]))
|
||||
|
||||
# Determine if there is a group with the same name
|
||||
|
||||
m4_define([MCPPBS_IS_GROUP],
|
||||
m4_bmatch(MCPPBS_SPROJ,[\*\*],[true],[false]))
|
||||
|
||||
# Create variations of the subproject name suitable for use as a CPP
|
||||
# enabled define, a shell enabled variable, and a shell function
|
||||
|
||||
m4_define([MCPPBS_SPROJ_NORM],
|
||||
m4_normalize(m4_bpatsubsts(MCPPBS_SPROJ,[*],[])))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_DEFINE],
|
||||
m4_toupper(m4_bpatsubst(MCPPBS_SPROJ_NORM[]_ENABLED,[-],[_])))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_FUNC],
|
||||
m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_]))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_UNDERSCORES],
|
||||
m4_bpatsubsts(MCPPBS_SPROJ,[-],[_]))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_SHVAR],
|
||||
m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_]))
|
||||
|
||||
# Add subproject to our running list
|
||||
|
||||
subprojects="$subprojects MCPPBS_SPROJ_NORM"
|
||||
|
||||
# Process the subproject appropriately. If enabled add it to the
|
||||
# $enabled_subprojects running shell variable, set a
|
||||
# SUBPROJECT_ENABLED C define, and include the appropriate
|
||||
# 'subproject.ac'.
|
||||
|
||||
m4_if(MCPPBS_IS_REQ,[true],
|
||||
[
|
||||
AC_MSG_NOTICE([configuring default subproject : MCPPBS_SPROJ_NORM])
|
||||
AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in)
|
||||
MCPPBS_SPROJ_SHVAR="yes"
|
||||
subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM"
|
||||
AC_DEFINE(MCPPBS_SPROJ_DEFINE,,
|
||||
[Define if subproject MCPPBS_SPROJ_NORM is enabled])
|
||||
m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac)
|
||||
],[
|
||||
|
||||
# For optional subprojects we capture the 'subproject.ac' as a
|
||||
# shell function so that in the MCPPBS_GROUP macro we can just
|
||||
# call this shell function instead of reading in 'subproject.ac'
|
||||
# again.
|
||||
|
||||
MCPPBS_SPROJ_FUNC ()
|
||||
{
|
||||
AC_MSG_NOTICE([configuring optional subproject : MCPPBS_SPROJ_NORM])
|
||||
AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in)
|
||||
MCPPBS_SPROJ_SHVAR="yes"
|
||||
subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM"
|
||||
AC_DEFINE(MCPPBS_SPROJ_DEFINE,,
|
||||
[Define if subproject MCPPBS_SPROJ_NORM is enabled])
|
||||
m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac)
|
||||
};
|
||||
|
||||
# Optional subprojects add --enable-subproject command line
|
||||
# options, _if_ the subproject name is not also a group name.
|
||||
|
||||
m4_if(MCPPBS_IS_GROUP,[false],
|
||||
[
|
||||
AC_ARG_ENABLE(MCPPBS_SPROJ_NORM,
|
||||
AS_HELP_STRING(--enable-MCPPBS_SPROJ_NORM,
|
||||
[Subproject MCPPBS_SPROJ_NORM]),
|
||||
[MCPPBS_SPROJ_SHVAR="yes"],[MCPPBS_SPROJ_SHVAR="no"])
|
||||
|
||||
AS_IF([test "$MCPPBS_SPROJ_SHVAR" = "yes"],
|
||||
[
|
||||
eval "MCPPBS_SPROJ_FUNC"
|
||||
],[
|
||||
AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM])
|
||||
])
|
||||
|
||||
],[
|
||||
|
||||
# If the subproject name is also a group name then we need to
|
||||
# make sure that we set the shell variable for that subproject to
|
||||
# no so that the group code knows we haven't run it yet.
|
||||
|
||||
AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM])
|
||||
MCPPBS_SPROJ_SHVAR="no"
|
||||
|
||||
])
|
||||
|
||||
# Always execute the subproject configure code if we are enabling
|
||||
# all subprojects.
|
||||
|
||||
AS_IF([ test "$enable_optional_subprojects" = "yes" \
|
||||
&& test "$MCPPBS_SPROJ_SHVAR" = "no" ],
|
||||
[
|
||||
eval "MCPPBS_SPROJ_FUNC"
|
||||
])
|
||||
|
||||
])
|
||||
|
||||
])
|
||||
|
||||
# Output make variables
|
||||
|
||||
AC_SUBST([subprojects])
|
||||
AC_SUBST([subprojects_enabled])
|
||||
|
||||
])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS_GROUP( [group-name], [ sproj1, sproj2, ... ] )
|
||||
#-------------------------------------------------------------------------
|
||||
# This macro creates a subproject group with the given group-name. When
|
||||
# a user specifies --enable-<group-name> the listed subprojects will be
|
||||
# enabled. Groups can have the same name as a subproject and in that
|
||||
# case whenever a user specifies --enable-<subproject> the subprojects
|
||||
# listed in the corresponding group will also be enabled. Groups are
|
||||
# useful for specifying related subprojects which are usually enabled
|
||||
# together, as well as for specifying that a specific optional
|
||||
# subproject has dependencies on other optional subprojects.
|
||||
#
|
||||
# Author : Christopher Batten
|
||||
# Date : September 10, 2008
|
||||
|
||||
AC_DEFUN([MCPPBS_GROUP],
|
||||
[
|
||||
|
||||
m4_define([MCPPBS_GROUP_NORM],
|
||||
m4_normalize([$1]))
|
||||
|
||||
m4_define([MCPPBS_GROUP_SHVAR],
|
||||
m4_bpatsubst(enable_[]MCPPBS_GROUP_NORM[]_group,[-],[_]))
|
||||
|
||||
AC_ARG_ENABLE(MCPPBS_GROUP_NORM,
|
||||
AS_HELP_STRING(--enable-MCPPBS_GROUP_NORM,
|
||||
[Group MCPPBS_GROUP_NORM: $2]),
|
||||
[MCPPBS_GROUP_SHVAR="yes"],[MCPPBS_GROUP_SHVAR="no"])
|
||||
|
||||
AS_IF([test "$MCPPBS_GROUP_SHVAR" = "yes" ],
|
||||
[
|
||||
AC_MSG_NOTICE([configuring optional group : MCPPBS_GROUP_NORM])
|
||||
])
|
||||
|
||||
m4_foreach([MCPPBS_SPROJ],[$2],
|
||||
[
|
||||
|
||||
m4_define([MCPPBS_SPROJ_NORM],
|
||||
m4_normalize(MCPPBS_SPROJ))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_SHVAR],
|
||||
m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_]))
|
||||
|
||||
m4_define([MCPPBS_SPROJ_FUNC],
|
||||
m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_]))
|
||||
|
||||
AS_IF([ test "$MCPPBS_GROUP_SHVAR" = "yes" \
|
||||
&& test "$MCPPBS_SPROJ_SHVAR" = "no" ],
|
||||
[
|
||||
eval "MCPPBS_SPROJ_FUNC"
|
||||
])
|
||||
|
||||
])
|
||||
|
||||
])
|
25
vendor/riscv-isa-sim/arch_test_target/spike/Makefile.include
vendored
Normal file
25
vendor/riscv-isa-sim/arch_test_target/spike/Makefile.include
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# set TARGETDIR to point to the directory which contains a sub-folder in the same name as the target
|
||||
export TARGETDIR ?= /scratch/git-repo/github/neel/riscv-isa-sim/arch_test_target
|
||||
|
||||
# set XLEN to max supported XLEN. Allowed values are 32 and 64
|
||||
export XLEN ?= 64
|
||||
|
||||
# name of the target. Note a folder of the same name must exist in the TARGETDIR directory
|
||||
export RISCV_TARGET ?= spike
|
||||
|
||||
# set the RISCV_DEVICE environment to a single extension you want to compile, simulate and/or verify.
|
||||
# Leave this blank if you want to iterate through all the supported extensions available in the target
|
||||
export RISCV_DEVICE ?=
|
||||
|
||||
# set this to a string which needs to be passed to your target Makefile.include files
|
||||
export RISCV_TARGET_FLAGS ?=
|
||||
|
||||
# set this if you want to enable assertions on the test-suites. Currently no tests support
|
||||
# assertions.
|
||||
export RISCV_ASSERT ?= 0
|
||||
|
||||
# set the number of parallel jobs (along with any other arguments) you would like to execute. Note that the target needs to ensure
|
||||
# that no common files across jobs are created/overwritten leading to unknown behavior
|
||||
JOBS= -j1
|
||||
|
||||
|
58
vendor/riscv-isa-sim/arch_test_target/spike/README.md
vendored
Normal file
58
vendor/riscv-isa-sim/arch_test_target/spike/README.md
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Using the Spike Simulator as an Architectural test model
|
||||
|
||||
This is a reference for running Spike as a target for the RISC-V Architectural Test framework.
|
||||
|
||||
## Getting Spike
|
||||
|
||||
The Spike repository should be cloned from [here](https://github.com/riscv/riscv-isa-sim/), preferably at the same directory level as the riscv-arch-test repository.
|
||||
|
||||
## Building Spike
|
||||
|
||||
The [README.md](../README.md) at the top level of the riscv-isa-sim directory gives details on building an executable spike model.
|
||||
|
||||
## Adding Spike as a target to the Architectural Test framework
|
||||
|
||||
Also at the top level is an ``arch_test_target directory``. This directory contains all the collaterals
|
||||
required to add Spike as a target to the architectural test framework.
|
||||
|
||||
The file ``arch_test_target/spike/Makefile.include`` contains various parameters which can be set by
|
||||
the user to modify the instance of spike on which the tests need to be run.
|
||||
The user can modify the ``XLEN`` variable based on whether 32-bit or 64-bit tests need to be run.
|
||||
If one would like to run tests of a single extension then set the `RISCV_DEVICE` to that extension
|
||||
name (eg. M, C, Zifencei, etc). Leaving the ``RISCV_DEVICE`` empty would indicate running all tests
|
||||
for all extensions available in the ``device/rv{XLEN}i_m`` directory No other variables should be modified.
|
||||
|
||||
Now clone the architectural test framework repo and copy the updated Makefile.include to it:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/riscv/riscv-arch-test.git
|
||||
$ cd riscv-arch-test
|
||||
$ cp <custom-path>/riscv-isa-sim/arch_test_target/spike/Makefile.include .
|
||||
```
|
||||
|
||||
The user will have to modify the ``TARGETDIR`` variable in ``riscv-arch-test/Makefile.include`` to point to the
|
||||
absolute location of the ``riscv-isa-sim/arch_test_target`` directory.
|
||||
|
||||
You can execute the tests from the root directory of the riscv-arch-test repo:
|
||||
|
||||
```
|
||||
make compile simulate verify
|
||||
```
|
||||
|
||||
## Updating the target for new tests
|
||||
|
||||
As tests for new extensions are added to the architectural test repo, the spike target (i.e.
|
||||
arch_test_target directory) will also need to be updated accordingly. Please refer to the [Porting a new target](https://github.com/riscv/riscv-arch-test/blob/master/doc/README.adoc#5-porting-a-new-target)
|
||||
section for more details on what those changes/updates should be.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
34
vendor/riscv-isa-sim/arch_test_target/spike/device/Makefile_common.inc
vendored
Normal file
34
vendor/riscv-isa-sim/arch_test_target/spike/device/Makefile_common.inc
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
TARGET_SIM ?= spike
|
||||
TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS)
|
||||
ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),)
|
||||
$(error Target simulator executable '$(TARGET_SIM)` not found)
|
||||
endif
|
||||
|
||||
RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf-
|
||||
RISCV_GCC ?= $(RISCV_PREFIX)gcc
|
||||
RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump
|
||||
RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES)
|
||||
|
||||
COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \
|
||||
-I$(ROOTDIR)/riscv-test-suite/env/ \
|
||||
-I$(TARGETDIR)/$(RISCV_TARGET)/ \
|
||||
-T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \
|
||||
$$(<) -o $$@
|
||||
OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \
|
||||
$$(RISCV_OBJDUMP) $$@ --source > $$@.debug
|
||||
|
||||
|
||||
COMPILE_TARGET=\
|
||||
$(COMPILE_CMD); \
|
||||
if [ $$$$? -ne 0 ] ; \
|
||||
then \
|
||||
echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \
|
||||
exit 1 ; \
|
||||
fi ; \
|
||||
$(OBJ_CMD); \
|
||||
if [ $$$$? -ne 0 ] ; \
|
||||
then \
|
||||
echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \
|
||||
exit 1 ; \
|
||||
fi ;
|
||||
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/C/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/C/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32ec \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/E/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/E/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32e \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/M/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32e_unratified/M/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32em \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/C/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/C/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32ic \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/F/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/F/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32if \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/I/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/I/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32i \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/M/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/M/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32im \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/Zifencei/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/Zifencei/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32i \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/privilege/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv32i_m/privilege/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv32ic \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/C/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/C/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64ic \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
8
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/D/Makefile.include
vendored
Normal file
8
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/D/Makefile.include
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64ifd \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
||||
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/I/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/I/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64i \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
8
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/M/Makefile.include
vendored
Normal file
8
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/M/Makefile.include
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64im \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
||||
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/Zifencei/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/Zifencei/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64i \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/privilege/Makefile.include
vendored
Normal file
7
vendor/riscv-isa-sim/arch_test_target/spike/device/rv64i_m/privilege/Makefile.include
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
include $(TARGETDIR)/spike/device/Makefile_common.inc
|
||||
RUN_CMD = $(TARGET_SIM) $(TARGET_FLAGS) --isa=rv64ic \
|
||||
+signature=$(*).signature.output +signature-granularity=4\
|
||||
$<
|
||||
|
||||
RUN_TARGET=\
|
||||
$(RUN_CMD)
|
18
vendor/riscv-isa-sim/arch_test_target/spike/link.ld
vendored
Normal file
18
vendor/riscv-isa-sim/arch_test_target/spike/link.ld
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(rvtest_entry_point)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
.text.init : { *(.text.init) }
|
||||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.data : { *(.data) }
|
||||
.data.string : { *(.data.string)}
|
||||
.bss : { *(.bss) }
|
||||
_end = .;
|
||||
}
|
||||
|
70
vendor/riscv-isa-sim/arch_test_target/spike/model_test.h
vendored
Normal file
70
vendor/riscv-isa-sim/arch_test_target/spike/model_test.h
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "ibex_macros.h"
|
||||
|
||||
#ifndef _COMPLIANCE_MODEL_H
|
||||
#define _COMPLIANCE_MODEL_H
|
||||
|
||||
#if XLEN == 64
|
||||
#define ALIGNMENT 3
|
||||
#else
|
||||
#define ALIGNMENT 2
|
||||
#endif
|
||||
|
||||
#define RVMODEL_DATA_SECTION \
|
||||
.pushsection .tohost,"aw",@progbits; \
|
||||
.align 8; .global tohost; tohost: .dword 0; \
|
||||
.align 8; .global fromhost; fromhost: .dword 0; \
|
||||
.popsection; \
|
||||
.align 8; .global begin_regstate; begin_regstate: \
|
||||
.word 128; \
|
||||
.align 8; .global end_regstate; end_regstate: \
|
||||
.word 4;
|
||||
|
||||
//RV_COMPLIANCE_HALT
|
||||
#define RVMODEL_HALT \
|
||||
fence; \
|
||||
li x2, SIGNATURE_ADDR; \
|
||||
li x1, (FINISHED_IRQ << 8) | CORE_STATUS; \
|
||||
sw x1, 0(x2); \
|
||||
li x1, (TEST_PASS << 8) | TEST_RESULT; \
|
||||
sw x1, 0(x2); \
|
||||
self_loop: j self_loop;
|
||||
|
||||
#define RVMODEL_BOOT
|
||||
|
||||
//RV_COMPLIANCE_DATA_BEGIN
|
||||
#define RVMODEL_DATA_BEGIN \
|
||||
.align 4; .global begin_signature; begin_signature:
|
||||
|
||||
//RV_COMPLIANCE_DATA_END
|
||||
#define RVMODEL_DATA_END \
|
||||
.align 4; .global end_signature; end_signature: \
|
||||
RVMODEL_DATA_SECTION \
|
||||
|
||||
//RVTEST_IO_INIT
|
||||
#define RVMODEL_IO_INIT
|
||||
//RVTEST_IO_WRITE_STR
|
||||
#define RVMODEL_IO_WRITE_STR(_R, _STR)
|
||||
//RVTEST_IO_CHECK
|
||||
#define RVMODEL_IO_CHECK()
|
||||
//RVTEST_IO_ASSERT_GPR_EQ
|
||||
#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I)
|
||||
//RVTEST_IO_ASSERT_SFPR_EQ
|
||||
#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I)
|
||||
//RVTEST_IO_ASSERT_DFPR_EQ
|
||||
#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I)
|
||||
|
||||
#define RVMODEL_SET_MSW_INT \
|
||||
li t1, 1; \
|
||||
li t2, 0x2000000; \
|
||||
sw t1, 0(t2);
|
||||
|
||||
#define RVMODEL_CLEAR_MSW_INT \
|
||||
li t2, 0x2000000; \
|
||||
sw x0, 0(t2);
|
||||
|
||||
#define RVMODEL_CLEAR_MTIMER_INT
|
||||
|
||||
#define RVMODEL_CLEAR_MEXT_INT
|
||||
|
||||
#endif // _COMPLIANCE_MODEL_H
|
||||
|
50
vendor/riscv-isa-sim/ax_append_flag.m4
vendored
Normal file
50
vendor/riscv-isa-sim/ax_append_flag.m4
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
|
||||
# added in between.
|
||||
#
|
||||
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
|
||||
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
|
||||
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
|
||||
# FLAG.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 8
|
||||
|
||||
AC_DEFUN([AX_APPEND_FLAG],
|
||||
[dnl
|
||||
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
|
||||
AS_VAR_SET_IF(FLAGS,[
|
||||
AS_CASE([" AS_VAR_GET(FLAGS) "],
|
||||
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
|
||||
[
|
||||
AS_VAR_APPEND(FLAGS,[" $1"])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
],
|
||||
[
|
||||
AS_VAR_SET(FLAGS,[$1])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])dnl AX_APPEND_FLAG
|
44
vendor/riscv-isa-sim/ax_append_link_flags.m4
vendored
Normal file
44
vendor/riscv-isa-sim/ax_append_link_flags.m4
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# For every FLAG1, FLAG2 it is checked whether the linker works with the
|
||||
# flag. If it does, the flag is added FLAGS-VARIABLE
|
||||
#
|
||||
# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is
|
||||
# used. During the check the flag is always added to the linker's flags.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
|
||||
# when the check is done. The check is thus made with the flags: "LDFLAGS
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
|
||||
# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 7
|
||||
|
||||
AC_DEFUN([AX_APPEND_LINK_FLAGS],
|
||||
[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
for flag in $1; do
|
||||
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
|
||||
done
|
||||
])dnl AX_APPEND_LINK_FLAGS
|
110
vendor/riscv-isa-sim/ax_boost_asio.m4
vendored
Normal file
110
vendor/riscv-isa-sim/ax_boost_asio.m4
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_ASIO
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Asio library from the Boost C++ libraries. The macro requires a
|
||||
# preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_ASIO_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_ASIO
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 18
|
||||
|
||||
AC_DEFUN([AX_BOOST_ASIO],
|
||||
[
|
||||
AC_ARG_WITH([boost-asio],
|
||||
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
|
||||
[use the ASIO library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_asio_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
|
||||
ax_cv_boost_asio,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
|
||||
]],
|
||||
[[
|
||||
|
||||
boost::asio::io_service io;
|
||||
boost::system::error_code timer_result;
|
||||
boost::asio::deadline_timer t(io);
|
||||
t.cancel();
|
||||
io.run_one();
|
||||
return 0;
|
||||
]])],
|
||||
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_asio" = "xyes"; then
|
||||
AC_DEFINE(HAVE_BOOST_ASIO,,[define if the Boost::ASIO library is available])
|
||||
BN=boost_system
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
if test "x$ax_boost_user_asio_lib" = "x"; then
|
||||
for ax_lib in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.dylib* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_system.*\)\.a.*$;\1;' ` ; do
|
||||
AC_CHECK_LIB($ax_lib, main, [BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_thread="yes" break],
|
||||
[link_thread="no"])
|
||||
done
|
||||
else
|
||||
for ax_lib in $ax_boost_user_asio_lib $BN-$ax_boost_user_asio_lib; do
|
||||
AC_CHECK_LIB($ax_lib, main,
|
||||
[BOOST_ASIO_LIB="-l$ax_lib" AC_SUBST(BOOST_ASIO_LIB) link_asio="yes" break],
|
||||
[link_asio="no"])
|
||||
done
|
||||
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the Boost::Asio library!)
|
||||
fi
|
||||
if test "x$link_asio" = "xno"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
303
vendor/riscv-isa-sim/ax_boost_base.m4
vendored
Normal file
303
vendor/riscv-isa-sim/ax_boost_base.m4
vendored
Normal file
|
@ -0,0 +1,303 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for the Boost C++ libraries of a particular version (or newer)
|
||||
#
|
||||
# If no path to the installed boost library is given the macro searchs
|
||||
# under /usr, /usr/local, /opt and /opt/local and evaluates the
|
||||
# $BOOST_ROOT environment variable. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2009 Peter Adolphs
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 49
|
||||
|
||||
# example boost program (need to pass version)
|
||||
m4_define([_AX_BOOST_BASE_PROGRAM],
|
||||
[AC_LANG_PROGRAM([[
|
||||
#include <boost/version.hpp>
|
||||
]],[[
|
||||
(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));
|
||||
]])])
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
AC_ARG_WITH([boost],
|
||||
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
|
||||
[use Boost library from a standard location (ARG=yes),
|
||||
from the specified location (ARG=<path>),
|
||||
or disable it (ARG=no)
|
||||
@<:@ARG=yes@:>@ ])],
|
||||
[
|
||||
AS_CASE([$withval],
|
||||
[no],[want_boost="no";_AX_BOOST_BASE_boost_path=""],
|
||||
[yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""],
|
||||
[want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"])
|
||||
],
|
||||
[want_boost="yes"])
|
||||
|
||||
|
||||
AC_ARG_WITH([boost-libdir],
|
||||
[AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
|
||||
[Force given directory for boost libraries.
|
||||
Note that this will override library path detection,
|
||||
so use this parameter only if default library detection fails
|
||||
and you know exactly where your boost libraries are located.])],
|
||||
[
|
||||
AS_IF([test -d "$withval"],
|
||||
[_AX_BOOST_BASE_boost_lib_path="$withval"],
|
||||
[AC_MSG_ERROR([--with-boost-libdir expected directory name])])
|
||||
],
|
||||
[_AX_BOOST_BASE_boost_lib_path=""])
|
||||
|
||||
BOOST_LDFLAGS=""
|
||||
BOOST_CPPFLAGS=""
|
||||
AS_IF([test "x$want_boost" = "xyes"],
|
||||
[_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
|
||||
AC_SUBST(BOOST_CPPFLAGS)
|
||||
AC_SUBST(BOOST_LDFLAGS)
|
||||
])
|
||||
|
||||
|
||||
# convert a version string in $2 to numeric and affect to polymorphic var $1
|
||||
AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[
|
||||
AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"])
|
||||
_AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
_AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'`
|
||||
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"],
|
||||
[AC_MSG_ERROR([You should at least specify libboost major version])])
|
||||
_AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'`
|
||||
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"],
|
||||
[_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"])
|
||||
_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
|
||||
AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"],
|
||||
[_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"])
|
||||
_AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor`
|
||||
AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET)
|
||||
])
|
||||
|
||||
dnl Run the detection of boost should be run only if $want_boost
|
||||
AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
|
||||
_AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1])
|
||||
succeeded=no
|
||||
|
||||
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
dnl On 64-bit systems check for system libraries in both lib64 and lib.
|
||||
dnl The former is specified by FHS, but e.g. Debian does not adhere to
|
||||
dnl this (as it rises problems for generic multi-arch support).
|
||||
dnl The last entry in the list is chosen by default when no libraries
|
||||
dnl are found, e.g. when only header-only libraries are installed!
|
||||
AS_CASE([${host_cpu}],
|
||||
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
|
||||
[mips*64*],[libsubdirs="lib64 lib32 lib lib64"],
|
||||
[ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k],[libsubdirs="lib64 lib lib64"],
|
||||
[libsubdirs="lib"]
|
||||
)
|
||||
|
||||
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
|
||||
dnl them priority over the other paths since, if libs are found there, they
|
||||
dnl are almost assuredly the ones desired.
|
||||
AS_CASE([${host_cpu}],
|
||||
[i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
|
||||
[armv7l],[multiarch_libsubdir="lib/arm-${host_os}"],
|
||||
[multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
|
||||
)
|
||||
|
||||
dnl first we check the system location for boost libraries
|
||||
dnl this location ist chosen if boost libraries are installed with the --layout=system option
|
||||
dnl or if you install boost with RPM
|
||||
AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
|
||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
|
||||
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[
|
||||
AC_MSG_RESULT([yes])
|
||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include"
|
||||
for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do
|
||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
|
||||
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
|
||||
AC_MSG_RESULT([yes])
|
||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
|
||||
break;
|
||||
],
|
||||
[AC_MSG_RESULT([no])])
|
||||
done],[
|
||||
AC_MSG_RESULT([no])])
|
||||
],[
|
||||
if test X"$cross_compiling" = Xyes; then
|
||||
search_libsubdirs=$multiarch_libsubdir
|
||||
else
|
||||
search_libsubdirs="$multiarch_libsubdir $libsubdirs"
|
||||
fi
|
||||
for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
|
||||
for libsubdir in $search_libsubdirs ; do
|
||||
if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
|
||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
])
|
||||
|
||||
dnl overwrite ld flags if we have required special directory with
|
||||
dnl --with-boost-libdir parameter
|
||||
AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
|
||||
[BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
|
||||
|
||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_REQUIRE([AC_PROG_CXX])
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
|
||||
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes" ; then
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
BOOST_CPPFLAGS=
|
||||
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
||||
BOOST_LDFLAGS=
|
||||
fi
|
||||
_version=0
|
||||
if test -n "$_AX_BOOST_BASE_boost_path" ; then
|
||||
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
|
||||
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "x$V_CHECK" = "x1" ; then
|
||||
_version=$_version_tmp
|
||||
fi
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
dnl if nothing found search for layout used in Windows distributions
|
||||
if test -z "$BOOST_CPPFLAGS"; then
|
||||
if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then
|
||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
|
||||
fi
|
||||
fi
|
||||
dnl if we found something and BOOST_LDFLAGS was unset before
|
||||
dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
|
||||
if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test "x$cross_compiling" != "xyes" ; then
|
||||
for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do
|
||||
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then
|
||||
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
|
||||
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
||||
V_CHECK=`expr $_version_tmp \> $_version`
|
||||
if test "x$V_CHECK" = "x1" ; then
|
||||
_version=$_version_tmp
|
||||
best_path=$_AX_BOOST_BASE_boost_path
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
|
||||
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
BOOST_LDFLAGS="-L$best_path/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$BOOST_ROOT" ; then
|
||||
for libsubdir in $libsubdirs ; do
|
||||
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
||||
done
|
||||
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
|
||||
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
|
||||
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
|
||||
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
|
||||
V_CHECK=`expr $stage_version_shorten \>\= $_version`
|
||||
if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
||||
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
|
||||
BOOST_CPPFLAGS="-I$BOOST_ROOT"
|
||||
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
|
||||
AC_MSG_RESULT(yes)
|
||||
succeeded=yes
|
||||
found_system=yes
|
||||
],[
|
||||
])
|
||||
AC_LANG_POP([C++])
|
||||
fi
|
||||
|
||||
if test "x$succeeded" != "xyes" ; then
|
||||
if test "x$_version" = "x0" ; then
|
||||
AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
|
||||
else
|
||||
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
|
||||
fi
|
||||
# execute ACTION-IF-NOT-FOUND (if present):
|
||||
ifelse([$3], , :, [$3])
|
||||
else
|
||||
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
|
||||
# execute ACTION-IF-FOUND (if present):
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
|
||||
])
|
111
vendor/riscv-isa-sim/ax_boost_regex.m4
vendored
Normal file
111
vendor/riscv-isa-sim/ax_boost_regex.m4
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_boost_regex.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_BOOST_REGEX
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Test for Regex library from the Boost C++ libraries. The macro requires
|
||||
# a preceding call to AX_BOOST_BASE. Further documentation is available at
|
||||
# <http://randspringer.de/boost/index.html>.
|
||||
#
|
||||
# This macro calls:
|
||||
#
|
||||
# AC_SUBST(BOOST_REGEX_LIB)
|
||||
#
|
||||
# And sets:
|
||||
#
|
||||
# HAVE_BOOST_REGEX
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
||||
# Copyright (c) 2008 Michael Tindal
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 23
|
||||
|
||||
AC_DEFUN([AX_BOOST_REGEX],
|
||||
[
|
||||
AC_ARG_WITH([boost-regex],
|
||||
AS_HELP_STRING([--with-boost-regex@<:@=special-lib@:>@],
|
||||
[use the Regex library from boost - it is possible to specify a certain library for the linker
|
||||
e.g. --with-boost-regex=boost_regex-gcc-mt-d-1_33_1 ]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
elif test "$withval" = "yes"; then
|
||||
want_boost="yes"
|
||||
ax_boost_user_regex_lib=""
|
||||
else
|
||||
want_boost="yes"
|
||||
ax_boost_user_regex_lib="$withval"
|
||||
fi
|
||||
],
|
||||
[want_boost="yes"]
|
||||
)
|
||||
|
||||
if test "x$want_boost" = "xyes"; then
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
||||
export CPPFLAGS
|
||||
|
||||
LDFLAGS_SAVED="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
||||
export LDFLAGS
|
||||
|
||||
AC_CACHE_CHECK(whether the Boost::Regex library is available,
|
||||
ax_cv_boost_regex,
|
||||
[AC_LANG_PUSH([C++])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/regex.hpp>
|
||||
]],
|
||||
[[boost::regex r(); return 0;]])],
|
||||
ax_cv_boost_regex=yes, ax_cv_boost_regex=no)
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
if test "x$ax_cv_boost_regex" = "xyes"; then
|
||||
AC_DEFINE(HAVE_BOOST_REGEX,,[define if the Boost::Regex library is available])
|
||||
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
|
||||
if test "x$ax_boost_user_regex_lib" = "x"; then
|
||||
for libextension in `ls $BOOSTLIBDIR/libboost_regex*.so* $BOOSTLIBDIR/libboost_regex*.dylib* $BOOSTLIBDIR/libboost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_regex.*\)\.so.*$;\1;' -e 's;^lib\(boost_regex.*\)\.dylib.*;\1;' -e 's;^lib\(boost_regex.*\)\.a.*$;\1;'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break],
|
||||
[link_regex="no"])
|
||||
done
|
||||
if test "x$link_regex" != "xyes"; then
|
||||
for libextension in `ls $BOOSTLIBDIR/boost_regex*.dll* $BOOSTLIBDIR/boost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_regex.*\)\.dll.*$;\1;' -e 's;^\(boost_regex.*\)\.a.*$;\1;'` ; do
|
||||
ax_lib=${libextension}
|
||||
AC_CHECK_LIB($ax_lib, exit,
|
||||
[BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break],
|
||||
[link_regex="no"])
|
||||
done
|
||||
fi
|
||||
|
||||
else
|
||||
for ax_lib in $ax_boost_user_regex_lib boost_regex-$ax_boost_user_regex_lib; do
|
||||
AC_CHECK_LIB($ax_lib, main,
|
||||
[BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break],
|
||||
[link_regex="no"])
|
||||
done
|
||||
fi
|
||||
if test "x$ax_lib" = "x"; then
|
||||
AC_MSG_ERROR(Could not find a version of the Boost::Regex library!)
|
||||
fi
|
||||
if test "x$link_regex" != "xyes"; then
|
||||
AC_MSG_ERROR(Could not link against $ax_lib !)
|
||||
fi
|
||||
fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
fi
|
||||
])
|
53
vendor/riscv-isa-sim/ax_check_compile_flag.m4
vendored
Normal file
53
vendor/riscv-isa-sim/ax_check_compile_flag.m4
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the current language's compiler
|
||||
# or gives an error. (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the current language's default
|
||||
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
|
||||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
|
||||
# force the compiler to issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 6
|
||||
|
||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
|
||||
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_COMPILE_FLAGS
|
53
vendor/riscv-isa-sim/ax_check_link_flag.m4
vendored
Normal file
53
vendor/riscv-isa-sim/ax_check_link_flag.m4
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the linker or gives an error.
|
||||
# (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
|
||||
# when the check is done. The check is thus made with the flags: "LDFLAGS
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_LINK_IFELSE.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 6
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_LINK_FLAGS
|
37
vendor/riscv-isa-sim/ax_require_defined.m4
vendored
Normal file
37
vendor/riscv-isa-sim/ax_require_defined.m4
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_REQUIRE_DEFINED(MACRO)
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
|
||||
# been defined and thus are available for use. This avoids random issues
|
||||
# where a macro isn't expanded. Instead the configure script emits a
|
||||
# non-fatal:
|
||||
#
|
||||
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
|
||||
#
|
||||
# It's like AC_REQUIRE except it doesn't expand the required macro.
|
||||
#
|
||||
# Here's an example:
|
||||
#
|
||||
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 2
|
||||
|
||||
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
|
||||
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
|
||||
])dnl AX_REQUIRE_DEFINED
|
11
vendor/riscv-isa-sim/ci-tests/test-spike
vendored
Executable file
11
vendor/riscv-isa-sim/ci-tests/test-spike
vendored
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
mkdir install
|
||||
$DIR/../configure --prefix=`pwd`/install
|
||||
make -j4
|
||||
make install
|
142
vendor/riscv-isa-sim/config.h.in
vendored
Normal file
142
vendor/riscv-isa-sim/config.h.in
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef CUSTOMEXT_ENABLED
|
||||
|
||||
/* Default value for --isa switch */
|
||||
#undef DEFAULT_ISA
|
||||
|
||||
/* Default value for --priv switch */
|
||||
#undef DEFAULT_PRIV
|
||||
|
||||
/* Default value for --varch switch */
|
||||
#undef DEFAULT_VARCH
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef DISASM_ENABLED
|
||||
|
||||
/* Executable name of device-tree-compiler */
|
||||
#undef DTC
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef FDT_ENABLED
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef FESVR_ENABLED
|
||||
|
||||
/* define if the Boost library is available */
|
||||
#undef HAVE_BOOST
|
||||
|
||||
/* define if the Boost::ASIO library is available */
|
||||
#undef HAVE_BOOST_ASIO
|
||||
|
||||
/* Dynamic library loading is supported */
|
||||
#undef HAVE_DLOPEN
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `boost_regex' library (-lboost_regex). */
|
||||
#undef HAVE_LIBBOOST_REGEX
|
||||
|
||||
/* Define to 1 if you have the `boost_system' library (-lboost_system). */
|
||||
#undef HAVE_LIBBOOST_SYSTEM
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if struct statx exists. */
|
||||
#undef HAVE_STATX
|
||||
|
||||
/* Define to 1 if struct statx has stx_mnt_id. */
|
||||
#undef HAVE_STATX_MNT_ID
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef RISCV_ENABLED
|
||||
|
||||
/* Enable commit log generation */
|
||||
#undef RISCV_ENABLE_COMMITLOG
|
||||
|
||||
/* Enable hardware management of PTE accessed and dirty bits */
|
||||
#undef RISCV_ENABLE_DIRTY
|
||||
|
||||
/* Enable support for running target in either endianness */
|
||||
#undef RISCV_ENABLE_DUAL_ENDIAN
|
||||
|
||||
/* Enable PC histogram generation */
|
||||
#undef RISCV_ENABLE_HISTOGRAM
|
||||
|
||||
/* Enable hardware support for misaligned loads and stores */
|
||||
#undef RISCV_ENABLE_MISALIGNED
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef SOFTFLOAT_ENABLED
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef SPIKE_DASM_ENABLED
|
||||
|
||||
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
|
||||
#undef SPIKE_MAIN_ENABLED
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Default value for --with-target switch */
|
||||
#undef TARGET_ARCH
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
7714
vendor/riscv-isa-sim/configure
vendored
Executable file
7714
vendor/riscv-isa-sim/configure
vendored
Executable file
File diff suppressed because it is too large
Load diff
126
vendor/riscv-isa-sim/configure.ac
vendored
Normal file
126
vendor/riscv-isa-sim/configure.ac
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
#=========================================================================
|
||||
# Toplevel configure.ac for the Modular C++ Build System
|
||||
#=========================================================================
|
||||
# Please read the documenation in 'mcppbs-doc.txt' for more details on
|
||||
# how the Modular C++ Build System works. For most new projects, a
|
||||
# developer will only need to make the following changes:
|
||||
#
|
||||
# - change the project metadata listed right below
|
||||
# - update the list of subprojects via the 'MCPPBS_SUBPROJECTS' macro
|
||||
# - possibly add subproject groups if needed to ease configuration
|
||||
# - add more configure checks for platform specific configuration
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Project metadata
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
m4_define( proj_name, [RISC-V ISA Simulator])
|
||||
m4_define( proj_maintainer, [Andrew Waterman])
|
||||
m4_define( proj_abbreviation, [spike])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Project version information
|
||||
#-------------------------------------------------------------------------
|
||||
# Version information is meant to be managed through a version control
|
||||
# system's tags and revision numbers. In a working copy the version will
|
||||
# not be defined here (you should just use the version control system's
|
||||
# mechanisms). When we make a distribution then we can set the version
|
||||
# here as formed by the scripts/vcs-version.sh script so that the
|
||||
# distribution knows what version it came from. If you are not using
|
||||
# version control then it is fine to set this directly.
|
||||
|
||||
m4_define( proj_version, [?])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Setup
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AC_INIT(proj_name,proj_version,proj_maintainer,proj_abbreviation)
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_CONFIG_SRCDIR([riscv/common.h])
|
||||
AC_CONFIG_AUX_DIR([scripts])
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
m4_include(ax_require_defined.m4)
|
||||
m4_include(ax_append_flag.m4)
|
||||
m4_include(ax_check_compile_flag.m4)
|
||||
m4_include(ax_check_link_flag.m4)
|
||||
m4_include(ax_append_link_flags.m4)
|
||||
m4_include(ax_boost_base.m4)
|
||||
m4_include(ax_boost_asio.m4)
|
||||
m4_include(ax_boost_regex.m4)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Checks for programs
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL([AR],[ar])
|
||||
AC_CHECK_TOOL([RANLIB],[ranlib])
|
||||
AC_PATH_PROG([DTC],[dtc],[no])
|
||||
AS_IF([test x"$DTC" == xno],AC_MSG_ERROR([device-tree-compiler not found]))
|
||||
AC_DEFINE_UNQUOTED(DTC, ["dtc"], [Executable name of device-tree-compiler])
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS specific program checks
|
||||
#-------------------------------------------------------------------------
|
||||
# These macros check to see if we can do a stow-based install and also
|
||||
# check for an isa simulator suitable for running the unit test programs
|
||||
# via the makefile.
|
||||
|
||||
MCPPBS_PROG_INSTALL
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Checks for header files
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AC_HEADER_STDC
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Checks for type
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AC_CHECK_TYPE([__int128_t], AC_SUBST([HAVE_INT128],[yes]))
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Default compiler flags
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AX_APPEND_LINK_FLAGS([-Wl,--export-dynamic])
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-relocatable-pch], AC_SUBST([HAVE_CLANG_PCH],[yes]))
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS subproject list
|
||||
#-------------------------------------------------------------------------
|
||||
# Order list so that subprojects only depend on those listed earlier.
|
||||
# The '*' suffix indicates an optional subproject. The '**' suffix
|
||||
# indicates an optional subproject which is also the name of a group.
|
||||
|
||||
MCPPBS_SUBPROJECTS([ fesvr, riscv, disasm, customext, fdt, softfloat, spike_main, spike_dasm ])
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# MCPPBS subproject groups
|
||||
#-------------------------------------------------------------------------
|
||||
# If a group has the same name as a subproject then you must add the
|
||||
# '**' suffix in the subproject list above. The list of subprojects in a
|
||||
# group should be ordered so that subprojets only depend on those listed
|
||||
# earlier. Here is an example:
|
||||
#
|
||||
# MCPPBS_GROUP( [group-name], [sproja,sprojb,...] )
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Output
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([riscv-fesvr.pc])
|
||||
AC_CONFIG_FILES([riscv-disasm.pc])
|
||||
AC_OUTPUT
|
42
vendor/riscv-isa-sim/customext/cflush.cc
vendored
Normal file
42
vendor/riscv-isa-sim/customext/cflush.cc
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "insn_macros.h"
|
||||
#include "extension.h"
|
||||
#include <cstring>
|
||||
|
||||
struct : public arg_t {
|
||||
std::string to_string(insn_t insn) const {
|
||||
return xpr_name[insn.rs1()];
|
||||
}
|
||||
} xrs1;
|
||||
|
||||
static reg_t custom_cflush(processor_t* p, insn_t insn, reg_t pc)
|
||||
{
|
||||
require_privilege(PRV_M);
|
||||
|
||||
return pc + 4; \
|
||||
}
|
||||
|
||||
class cflush_t : public extension_t
|
||||
{
|
||||
public:
|
||||
const char* name() { return "cflush"; }
|
||||
|
||||
cflush_t() {}
|
||||
|
||||
std::vector<insn_desc_t> get_instructions() {
|
||||
std::vector<insn_desc_t> insns;
|
||||
insns.push_back((insn_desc_t){true, 0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush});
|
||||
insns.push_back((insn_desc_t){true, 0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush});
|
||||
insns.push_back((insn_desc_t){true, 0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush});
|
||||
return insns;
|
||||
}
|
||||
|
||||
std::vector<disasm_insn_t*> get_disasms() {
|
||||
std::vector<disasm_insn_t*> insns;
|
||||
insns.push_back(new disasm_insn_t("cflush.d.l1", 0xFC000073, 0xFFF07FFF, {&xrs1}));
|
||||
insns.push_back(new disasm_insn_t("cdiscard.d.l1", 0xFC200073, 0xFFF07FFF, {&xrs1}));
|
||||
insns.push_back(new disasm_insn_t("cflush.i.l1", 0xFC100073, 0xFFF07FFF, {&xrs1}));
|
||||
return insns;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_EXTENSION(cflush, []() { return new cflush_t; })
|
0
vendor/riscv-isa-sim/customext/customext.ac
vendored
Normal file
0
vendor/riscv-isa-sim/customext/customext.ac
vendored
Normal file
11
vendor/riscv-isa-sim/customext/customext.mk.in
vendored
Normal file
11
vendor/riscv-isa-sim/customext/customext.mk.in
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
customext_subproject_deps = \
|
||||
spike_main \
|
||||
riscv \
|
||||
disasm \
|
||||
softfloat \
|
||||
|
||||
customext_srcs = \
|
||||
dummy_rocc.cc \
|
||||
cflush.cc \
|
||||
|
||||
customext_install_shared_lib = yes
|
47
vendor/riscv-isa-sim/customext/dummy_rocc.cc
vendored
Normal file
47
vendor/riscv-isa-sim/customext/dummy_rocc.cc
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "rocc.h"
|
||||
#include "mmu.h"
|
||||
#include <cstring>
|
||||
|
||||
class dummy_rocc_t : public rocc_t
|
||||
{
|
||||
public:
|
||||
const char* name() { return "dummy_rocc"; }
|
||||
|
||||
reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t xs2)
|
||||
{
|
||||
reg_t prev_acc = acc[insn.rs2];
|
||||
|
||||
if (insn.rs2 >= num_acc)
|
||||
illegal_instruction();
|
||||
|
||||
switch (insn.funct)
|
||||
{
|
||||
case 0: // acc <- xs1
|
||||
acc[insn.rs2] = xs1;
|
||||
break;
|
||||
case 1: // xd <- acc (the only real work is the return statement below)
|
||||
break;
|
||||
case 2: // acc[rs2] <- Mem[xs1]
|
||||
acc[insn.rs2] = p->get_mmu()->load_uint64(xs1);
|
||||
break;
|
||||
case 3: // acc[rs2] <- accX + xs1
|
||||
acc[insn.rs2] += xs1;
|
||||
break;
|
||||
default:
|
||||
illegal_instruction();
|
||||
}
|
||||
|
||||
return prev_acc; // in all cases, xd <- previous value of acc[rs2]
|
||||
}
|
||||
|
||||
dummy_rocc_t()
|
||||
{
|
||||
memset(acc, 0, sizeof(acc));
|
||||
}
|
||||
|
||||
private:
|
||||
static const int num_acc = 4;
|
||||
reg_t acc[num_acc];
|
||||
};
|
||||
|
||||
REGISTER_EXTENSION(dummy_rocc, []() { return new dummy_rocc_t; })
|
29
vendor/riscv-isa-sim/customext/dummy_rocc_test.c
vendored
Normal file
29
vendor/riscv-isa-sim/customext/dummy_rocc_test.c
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// The following is a RISC-V program to test the functionality of the
|
||||
// dummy RoCC accelerator.
|
||||
// Compile with riscv64-unknown-elf-gcc dummy_rocc_test.c
|
||||
// Run with spike --extension=dummy_rocc pk a.out
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main() {
|
||||
uint64_t x = 123, y = 456, z = 0;
|
||||
// load x into accumulator 2 (funct=0)
|
||||
asm volatile ("custom0 x0, %0, 2, 0" : : "r"(x));
|
||||
// read it back into z (funct=1) to verify it
|
||||
asm volatile ("custom0 %0, x0, 2, 1" : "=r"(z));
|
||||
assert(z == x);
|
||||
// accumulate 456 into it (funct=3)
|
||||
asm volatile ("custom0 x0, %0, 2, 3" : : "r"(y));
|
||||
// verify it
|
||||
asm volatile ("custom0 %0, x0, 2, 1" : "=r"(z));
|
||||
assert(z == x+y);
|
||||
// do it all again, but initialize acc2 via memory this time (funct=2)
|
||||
asm volatile ("custom0 x0, %0, 2, 2" : : "r"(&x));
|
||||
asm volatile ("custom0 x0, %0, 2, 3" : : "r"(y));
|
||||
asm volatile ("custom0 %0, x0, 2, 1" : "=r"(z));
|
||||
assert(z == x+y);
|
||||
|
||||
printf("success!\n");
|
||||
}
|
5
vendor/riscv-isa-sim/debug_rom/.gitignore
vendored
Normal file
5
vendor/riscv-isa-sim/debug_rom/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/debug_rom
|
||||
/debug_rom32
|
||||
/debug_rom64
|
||||
/debug_rom32.h
|
||||
/debug_rom64.h
|
24
vendor/riscv-isa-sim/debug_rom/Makefile
vendored
Normal file
24
vendor/riscv-isa-sim/debug_rom/Makefile
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Recursive make is bad, but in this case we're cross compiling which is a
|
||||
# pretty unusual use case.
|
||||
|
||||
CC = $(RISCV)/bin/riscv64-unknown-elf-gcc
|
||||
OBJCOPY = $(RISCV)/bin/riscv64-unknown-elf-objcopy
|
||||
|
||||
COMPILE = $(CC) -nostdlib -nostartfiles -I.. -Tlink.ld
|
||||
|
||||
ELFS = debug_rom
|
||||
DEPS = debug_rom.S link.ld ../riscv/debug_rom_defines.h ../riscv/encoding.h
|
||||
|
||||
all: $(patsubst %,%.h,$(ELFS))
|
||||
|
||||
%.h: %.raw
|
||||
xxd -i $^ | sed "s/^unsigned/static const unsigned/" > $@
|
||||
|
||||
%.raw: %
|
||||
$(OBJCOPY) -O binary --only-section .text $^ $@
|
||||
|
||||
debug_rom: $(DEPS)
|
||||
$(COMPILE) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f $(ELFS) debug_rom*.raw debug_rom.h
|
79
vendor/riscv-isa-sim/debug_rom/debug_rom.S
vendored
Executable file
79
vendor/riscv-isa-sim/debug_rom/debug_rom.S
vendored
Executable file
|
@ -0,0 +1,79 @@
|
|||
// See LICENSE.SiFive for license details.
|
||||
|
||||
#include "riscv/encoding.h"
|
||||
#include "riscv/debug_rom_defines.h"
|
||||
|
||||
.option norvc
|
||||
.global entry
|
||||
.global exception
|
||||
|
||||
// Entry location on ebreak, Halt, or Breakpoint
|
||||
// It is the same for all harts. They branch when
|
||||
// their GO or RESUME bit is set.
|
||||
|
||||
entry:
|
||||
jal zero, _entry
|
||||
resume:
|
||||
// Not used.
|
||||
jal zero, _resume
|
||||
exception:
|
||||
jal zero, _exception
|
||||
|
||||
_entry:
|
||||
// This fence is required because the execution may have written something
|
||||
// into the Abstract Data or Program Buffer registers.
|
||||
fence
|
||||
csrw CSR_DSCRATCH, s0 // Save s0 to allow signaling MHARTID
|
||||
|
||||
// We continue to let the hart know that we are halted in order that
|
||||
// a DM which was reset is still made aware that a hart is halted.
|
||||
// We keep checking both whether there is something the debugger wants
|
||||
// us to do, or whether we should resume.
|
||||
entry_loop:
|
||||
csrr s0, CSR_MHARTID
|
||||
sw s0, DEBUG_ROM_HALTED(zero)
|
||||
lbu s0, DEBUG_ROM_FLAGS(s0) // 1 byte flag per hart. Only one hart advances here.
|
||||
andi s0, s0, (1 << DEBUG_ROM_FLAG_GO)
|
||||
bnez s0, going
|
||||
csrr s0, CSR_MHARTID
|
||||
lbu s0, DEBUG_ROM_FLAGS(s0) // multiple harts can resume here
|
||||
andi s0, s0, (1 << DEBUG_ROM_FLAG_RESUME)
|
||||
bnez s0, _resume
|
||||
wfi
|
||||
jal zero, entry_loop
|
||||
|
||||
_exception:
|
||||
// Restore S0, which we always save to dscratch.
|
||||
// We need this in case the user tried an abstract write to a
|
||||
// non-existent CSR.
|
||||
csrr s0, CSR_DSCRATCH
|
||||
sw zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception.
|
||||
ebreak
|
||||
|
||||
going:
|
||||
csrr s0, CSR_MHARTID
|
||||
sw s0, DEBUG_ROM_GOING(zero) // When debug module sees this write, the GO flag is reset.
|
||||
csrr s0, CSR_DSCRATCH // Restore s0 here
|
||||
fence
|
||||
fence.i
|
||||
jalr zero, zero, %lo(whereto) // Debug module will put different instructions and data in the RAM,
|
||||
// so we use fence and fence.i for safety. (rocket-chip doesn't have this
|
||||
// because jalr is special there)
|
||||
|
||||
_resume:
|
||||
csrr s0, CSR_MHARTID
|
||||
sw s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset.
|
||||
csrr s0, CSR_DSCRATCH // Restore s0
|
||||
dret
|
||||
|
||||
// END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT.
|
||||
|
||||
.section .whereto
|
||||
whereto:
|
||||
nop
|
||||
// Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer,
|
||||
// or jal x0 resume, as desired.
|
||||
// Debug Module state machine tracks what is 'desired'.
|
||||
// We don't need/want to use jalr here because all of the
|
||||
// Variable ROM contents are set by
|
||||
// Debug Module before setting the OK_GO byte.
|
13
vendor/riscv-isa-sim/debug_rom/debug_rom.h
vendored
Normal file
13
vendor/riscv-isa-sim/debug_rom/debug_rom.h
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
static const unsigned char debug_rom_raw[] = {
|
||||
0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x00, 0x06, 0x6f, 0x00, 0x80, 0x03,
|
||||
0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1,
|
||||
0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00,
|
||||
0x63, 0x14, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40,
|
||||
0x13, 0x74, 0x24, 0x00, 0x63, 0x18, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10,
|
||||
0x6f, 0xf0, 0x9f, 0xfd, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10,
|
||||
0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x22, 0x80, 0x10,
|
||||
0x73, 0x24, 0x20, 0x7b, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00,
|
||||
0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10,
|
||||
0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b
|
||||
};
|
||||
static const unsigned int debug_rom_raw_len = 116;
|
15
vendor/riscv-isa-sim/debug_rom/link.ld
vendored
Normal file
15
vendor/riscv-isa-sim/debug_rom/link.ld
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY( entry )
|
||||
SECTIONS
|
||||
{
|
||||
.whereto 0x300 :
|
||||
{
|
||||
*(.whereto)
|
||||
}
|
||||
. = 0x800;
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
_end = .;
|
||||
}
|
0
vendor/riscv-isa-sim/disasm/disasm.ac
vendored
Normal file
0
vendor/riscv-isa-sim/disasm/disasm.ac
vendored
Normal file
2147
vendor/riscv-isa-sim/disasm/disasm.cc
vendored
Normal file
2147
vendor/riscv-isa-sim/disasm/disasm.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
vendor/riscv-isa-sim/disasm/disasm.mk.in
vendored
Normal file
5
vendor/riscv-isa-sim/disasm/disasm.mk.in
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
disasm_srcs = \
|
||||
disasm.cc \
|
||||
regnames.cc \
|
||||
|
||||
disasm_install_lib = yes
|
33
vendor/riscv-isa-sim/disasm/regnames.cc
vendored
Normal file
33
vendor/riscv-isa-sim/disasm/regnames.cc
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "disasm.h"
|
||||
|
||||
const char* xpr_name[] = {
|
||||
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
|
||||
};
|
||||
|
||||
const char* fpr_name[] = {
|
||||
"ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
|
||||
"fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
|
||||
"fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
|
||||
"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
|
||||
};
|
||||
|
||||
const char* vr_name[] = {
|
||||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
||||
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
||||
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
|
||||
};
|
||||
|
||||
const char* csr_name(int which) {
|
||||
switch (which) {
|
||||
#define DECLARE_CSR(name, number) case number: return #name;
|
||||
#include "encoding.h"
|
||||
#undef DECLARE_CSR
|
||||
}
|
||||
return "unknown-csr";
|
||||
}
|
0
vendor/riscv-isa-sim/fdt/fdt.ac
vendored
Normal file
0
vendor/riscv-isa-sim/fdt/fdt.ac
vendored
Normal file
291
vendor/riscv-isa-sim/fdt/fdt.c
vendored
Normal file
291
vendor/riscv-isa-sim/fdt/fdt.c
vendored
Normal file
|
@ -0,0 +1,291 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include "fdt.h"
|
||||
#include "libfdt.h"
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
/*
|
||||
* Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
|
||||
* that the given buffer contains what appears to be a flattened
|
||||
* device tree with sane information in its header.
|
||||
*/
|
||||
int32_t fdt_ro_probe_(const void *fdt)
|
||||
{
|
||||
uint32_t totalsize = fdt_totalsize(fdt);
|
||||
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
/* Complete tree */
|
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
/* Unfinished sequential-write blob */
|
||||
if (fdt_size_dt_struct(fdt) == 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
} else {
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
}
|
||||
|
||||
if (totalsize < INT32_MAX)
|
||||
return totalsize;
|
||||
else
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
|
||||
{
|
||||
return (off >= hdrsize) && (off <= totalsize);
|
||||
}
|
||||
|
||||
static int check_block_(uint32_t hdrsize, uint32_t totalsize,
|
||||
uint32_t base, uint32_t size)
|
||||
{
|
||||
if (!check_off_(hdrsize, totalsize, base))
|
||||
return 0; /* block start out of bounds */
|
||||
if ((base + size) < base)
|
||||
return 0; /* overflow */
|
||||
if (!check_off_(hdrsize, totalsize, base + size))
|
||||
return 0; /* block end out of bounds */
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t fdt_header_size_(uint32_t version)
|
||||
{
|
||||
if (version <= 1)
|
||||
return FDT_V1_SIZE;
|
||||
else if (version <= 2)
|
||||
return FDT_V2_SIZE;
|
||||
else if (version <= 3)
|
||||
return FDT_V3_SIZE;
|
||||
else if (version <= 16)
|
||||
return FDT_V16_SIZE;
|
||||
else
|
||||
return FDT_V17_SIZE;
|
||||
}
|
||||
|
||||
int fdt_check_header(const void *fdt)
|
||||
{
|
||||
size_t hdrsize;
|
||||
|
||||
if (fdt_magic(fdt) != FDT_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
hdrsize = fdt_header_size(fdt);
|
||||
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
|| (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
|
||||
if ((fdt_totalsize(fdt) < hdrsize)
|
||||
|| (fdt_totalsize(fdt) > INT_MAX))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* Bounds check memrsv block */
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* Bounds check structure block */
|
||||
if (fdt_version(fdt) < 17) {
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
} else {
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* Bounds check strings block */
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||
{
|
||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
||||
|
||||
if ((absoffset < offset)
|
||||
|| ((absoffset + len) < absoffset)
|
||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||
return NULL;
|
||||
|
||||
if (fdt_version(fdt) >= 0x11)
|
||||
if (((offset + len) < offset)
|
||||
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||
return NULL;
|
||||
|
||||
return fdt_offset_ptr_(fdt, offset);
|
||||
}
|
||||
|
||||
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
{
|
||||
const fdt32_t *tagp, *lenp;
|
||||
uint32_t tag;
|
||||
int offset = startoffset;
|
||||
const char *p;
|
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||
if (!tagp)
|
||||
return FDT_END; /* premature end */
|
||||
tag = fdt32_to_cpu(*tagp);
|
||||
offset += FDT_TAGSIZE;
|
||||
|
||||
*nextoffset = -FDT_ERR_BADSTRUCTURE;
|
||||
switch (tag) {
|
||||
case FDT_BEGIN_NODE:
|
||||
/* skip name */
|
||||
do {
|
||||
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||
} while (p && (*p != '\0'));
|
||||
if (!p)
|
||||
return FDT_END; /* premature end */
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||
if (!lenp)
|
||||
return FDT_END; /* premature end */
|
||||
/* skip-name offset, length and value */
|
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||
+ fdt32_to_cpu(*lenp);
|
||||
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
|
||||
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
|
||||
offset += 4;
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
case FDT_END_NODE:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
return FDT_END;
|
||||
}
|
||||
|
||||
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
|
||||
return FDT_END; /* premature end */
|
||||
|
||||
*nextoffset = FDT_TAGALIGN(offset);
|
||||
return tag;
|
||||
}
|
||||
|
||||
int fdt_check_node_offset_(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_check_prop_offset_(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_next_node(const void *fdt, int offset, int *depth)
|
||||
{
|
||||
int nextoffset = 0;
|
||||
uint32_t tag;
|
||||
|
||||
if (offset >= 0)
|
||||
if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
|
||||
return nextoffset;
|
||||
|
||||
do {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_PROP:
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
if (depth)
|
||||
(*depth)++;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth && ((--(*depth)) < 0))
|
||||
return nextoffset;
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
if ((nextoffset >= 0)
|
||||
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else
|
||||
return nextoffset;
|
||||
}
|
||||
} while (tag != FDT_BEGIN_NODE);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_first_subnode(const void *fdt, int offset)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
if (offset < 0 || depth != 1)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_next_subnode(const void *fdt, int offset)
|
||||
{
|
||||
int depth = 1;
|
||||
|
||||
/*
|
||||
* With respect to the parent, the depth of the next subnode will be
|
||||
* the same as the last.
|
||||
*/
|
||||
do {
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
if (offset < 0 || depth < 1)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
} while (depth > 1);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
|
||||
{
|
||||
int len = strlen(s) + 1;
|
||||
const char *last = strtab + tabsize - len;
|
||||
const char *p;
|
||||
|
||||
for (p = strtab; p <= last; p++)
|
||||
if (memcmp(p, s, len) == 0)
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_move(const void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (fdt_totalsize(fdt) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
memmove(buf, fdt, fdt_totalsize(fdt));
|
||||
return 0;
|
||||
}
|
66
vendor/riscv-isa-sim/fdt/fdt.h
vendored
Normal file
66
vendor/riscv-isa-sim/fdt/fdt.h
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef FDT_H
|
||||
#define FDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct fdt_header {
|
||||
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||
fdt32_t totalsize; /* total size of DT block */
|
||||
fdt32_t off_dt_struct; /* offset to structure */
|
||||
fdt32_t off_dt_strings; /* offset to strings */
|
||||
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
|
||||
fdt32_t version; /* format version */
|
||||
fdt32_t last_comp_version; /* last compatible version */
|
||||
|
||||
/* version 2 fields below */
|
||||
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
|
||||
booting on */
|
||||
/* version 3 fields below */
|
||||
fdt32_t size_dt_strings; /* size of the strings block */
|
||||
|
||||
/* version 17 fields below */
|
||||
fdt32_t size_dt_struct; /* size of the structure block */
|
||||
};
|
||||
|
||||
struct fdt_reserve_entry {
|
||||
fdt64_t address;
|
||||
fdt64_t size;
|
||||
};
|
||||
|
||||
struct fdt_node_header {
|
||||
fdt32_t tag;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct fdt_property {
|
||||
fdt32_t tag;
|
||||
fdt32_t len;
|
||||
fdt32_t nameoff;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLY */
|
||||
|
||||
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
|
||||
#define FDT_TAGSIZE sizeof(fdt32_t)
|
||||
|
||||
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
|
||||
#define FDT_END_NODE 0x2 /* End node */
|
||||
#define FDT_PROP 0x3 /* Property: name off,
|
||||
size, content */
|
||||
#define FDT_NOP 0x4 /* nop */
|
||||
#define FDT_END 0x9
|
||||
|
||||
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
|
||||
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V16_SIZE FDT_V3_SIZE
|
||||
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
|
||||
|
||||
#endif /* FDT_H */
|
17
vendor/riscv-isa-sim/fdt/fdt.mk.in
vendored
Normal file
17
vendor/riscv-isa-sim/fdt/fdt.mk.in
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
fdt_subproject_deps = \
|
||||
|
||||
fdt_hdrs = \
|
||||
fdt.h \
|
||||
libfdt.h \
|
||||
libfdt_env.h \
|
||||
|
||||
fdt_c_srcs = \
|
||||
fdt.c \
|
||||
fdt_ro.c \
|
||||
fdt_wip.c \
|
||||
fdt_sw.c \
|
||||
fdt_rw.c \
|
||||
fdt_strerror.c \
|
||||
fdt_empty_tree.c \
|
||||
fdt_addresses.c \
|
||||
fdt_overlay.c \
|
101
vendor/riscv-isa-sim/fdt/fdt_addresses.c
vendored
Normal file
101
vendor/riscv-isa-sim/fdt/fdt_addresses.c
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
|
||||
* Copyright (C) 2018 embedded brains GmbH
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
const fdt32_t *c;
|
||||
uint32_t val;
|
||||
int len;
|
||||
|
||||
c = fdt_getprop(fdt, nodeoffset, name, &len);
|
||||
if (!c)
|
||||
return len;
|
||||
|
||||
if (len != sizeof(*c))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*c);
|
||||
if (val > FDT_MAX_NCELLS)
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = fdt_cells(fdt, nodeoffset, "#address-cells");
|
||||
if (val == 0)
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
if (val == -FDT_ERR_NOTFOUND)
|
||||
return 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
int fdt_size_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = fdt_cells(fdt, nodeoffset, "#size-cells");
|
||||
if (val == -FDT_ERR_NOTFOUND)
|
||||
return 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This function assumes that [address|size]_cells is 1 or 2 */
|
||||
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
|
||||
const char *name, uint64_t addr, uint64_t size)
|
||||
{
|
||||
int addr_cells, size_cells, ret;
|
||||
uint8_t data[sizeof(fdt64_t) * 2], *prop;
|
||||
|
||||
ret = fdt_address_cells(fdt, parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
addr_cells = ret;
|
||||
|
||||
ret = fdt_size_cells(fdt, parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
size_cells = ret;
|
||||
|
||||
/* check validity of address */
|
||||
prop = data;
|
||||
if (addr_cells == 1) {
|
||||
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
fdt32_st(prop, (uint32_t)addr);
|
||||
} else if (addr_cells == 2) {
|
||||
fdt64_st(prop, addr);
|
||||
} else {
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
}
|
||||
|
||||
/* check validity of size */
|
||||
prop += addr_cells * sizeof(fdt32_t);
|
||||
if (size_cells == 1) {
|
||||
if (size > UINT32_MAX)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
fdt32_st(prop, (uint32_t)size);
|
||||
} else if (size_cells == 2) {
|
||||
fdt64_st(prop, size);
|
||||
} else {
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
}
|
||||
|
||||
return fdt_appendprop(fdt, nodeoffset, name, data,
|
||||
(addr_cells + size_cells) * sizeof(fdt32_t));
|
||||
}
|
38
vendor/riscv-isa-sim/fdt/fdt_empty_tree.c
vendored
Normal file
38
vendor/riscv-isa-sim/fdt/fdt_empty_tree.c
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fdt_create(buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish_reservemap(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_begin_node(buf, "");
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_end_node(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fdt_finish(buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
881
vendor/riscv-isa-sim/fdt/fdt_overlay.c
vendored
Normal file
881
vendor/riscv-isa-sim/fdt/fdt_overlay.c
vendored
Normal file
|
@ -0,0 +1,881 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2016 Free Electrons
|
||||
* Copyright (C) 2016 NextThing Co.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
/**
|
||||
* overlay_get_target_phandle - retrieves the target phandle of a fragment
|
||||
* @fdto: pointer to the device tree overlay blob
|
||||
* @fragment: node offset of the fragment in the overlay
|
||||
*
|
||||
* overlay_get_target_phandle() retrieves the target phandle of an
|
||||
* overlay fragment when that fragment uses a phandle (target
|
||||
* property) instead of a path (target-path property).
|
||||
*
|
||||
* returns:
|
||||
* the phandle pointed by the target property
|
||||
* 0, if the phandle was not found
|
||||
* -1, if the phandle was malformed
|
||||
*/
|
||||
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||
{
|
||||
const fdt32_t *val;
|
||||
int len;
|
||||
|
||||
val = fdt_getprop(fdto, fragment, "target", &len);
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
|
||||
return (uint32_t)-1;
|
||||
|
||||
return fdt32_to_cpu(*val);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_get_target - retrieves the offset of a fragment's target
|
||||
* @fdt: Base device tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @fragment: node offset of the fragment in the overlay
|
||||
* @pathp: pointer which receives the path of the target (or NULL)
|
||||
*
|
||||
* overlay_get_target() retrieves the target offset in the base
|
||||
* device tree of a fragment, no matter how the actual targeting is
|
||||
* done (through a phandle or a path)
|
||||
*
|
||||
* returns:
|
||||
* the targeted node offset in the base device tree
|
||||
* Negative error code on error
|
||||
*/
|
||||
static int overlay_get_target(const void *fdt, const void *fdto,
|
||||
int fragment, char const **pathp)
|
||||
{
|
||||
uint32_t phandle;
|
||||
const char *path = NULL;
|
||||
int path_len = 0, ret;
|
||||
|
||||
/* Try first to do a phandle based lookup */
|
||||
phandle = overlay_get_target_phandle(fdto, fragment);
|
||||
if (phandle == (uint32_t)-1)
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
/* no phandle, try path */
|
||||
if (!phandle) {
|
||||
/* And then a path based lookup */
|
||||
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
||||
if (path)
|
||||
ret = fdt_path_offset(fdt, path);
|
||||
else
|
||||
ret = path_len;
|
||||
} else
|
||||
ret = fdt_node_offset_by_phandle(fdt, phandle);
|
||||
|
||||
/*
|
||||
* If we haven't found either a target or a
|
||||
* target-path property in a node that contains a
|
||||
* __overlay__ subnode (we wouldn't be called
|
||||
* otherwise), consider it a improperly written
|
||||
* overlay
|
||||
*/
|
||||
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
|
||||
ret = -FDT_ERR_BADOVERLAY;
|
||||
|
||||
/* return on error */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* return pointer to path (if available) */
|
||||
if (pathp)
|
||||
*pathp = path ? path : NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_phandle_add_offset - Increases a phandle by an offset
|
||||
* @fdt: Base device tree blob
|
||||
* @node: Device tree overlay blob
|
||||
* @name: Name of the property to modify (phandle or linux,phandle)
|
||||
* @delta: offset to apply
|
||||
*
|
||||
* overlay_phandle_add_offset() increments a node phandle by a given
|
||||
* offset.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success.
|
||||
* Negative error code on error
|
||||
*/
|
||||
static int overlay_phandle_add_offset(void *fdt, int node,
|
||||
const char *name, uint32_t delta)
|
||||
{
|
||||
const fdt32_t *val;
|
||||
uint32_t adj_val;
|
||||
int len;
|
||||
|
||||
val = fdt_getprop(fdt, node, name, &len);
|
||||
if (!val)
|
||||
return len;
|
||||
|
||||
if (len != sizeof(*val))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
adj_val = fdt32_to_cpu(*val);
|
||||
if ((adj_val + delta) < adj_val)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
adj_val += delta;
|
||||
if (adj_val == (uint32_t)-1)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_adjust_node_phandles - Offsets the phandles of a node
|
||||
* @fdto: Device tree overlay blob
|
||||
* @node: Offset of the node we want to adjust
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_adjust_node_phandles() adds a constant to all the phandles
|
||||
* of a given node. This is mainly use as part of the overlay
|
||||
* application process, when we want to update all the overlay
|
||||
* phandles to not conflict with the overlays of the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_adjust_node_phandles(void *fdto, int node,
|
||||
uint32_t delta)
|
||||
{
|
||||
int child;
|
||||
int ret;
|
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
|
||||
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||
return ret;
|
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
|
||||
if (ret && ret != -FDT_ERR_NOTFOUND)
|
||||
return ret;
|
||||
|
||||
fdt_for_each_subnode(child, fdto, node) {
|
||||
ret = overlay_adjust_node_phandles(fdto, child, delta);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
|
||||
* @fdto: Device tree overlay blob
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_adjust_local_phandles() adds a constant to all the
|
||||
* phandles of an overlay. This is mainly use as part of the overlay
|
||||
* application process, when we want to update all the overlay
|
||||
* phandles to not conflict with the overlays of the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
|
||||
{
|
||||
/*
|
||||
* Start adjusting the phandles from the overlay root
|
||||
*/
|
||||
return overlay_adjust_node_phandles(fdto, 0, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_update_local_node_references - Adjust the overlay references
|
||||
* @fdto: Device tree overlay blob
|
||||
* @tree_node: Node offset of the node to operate on
|
||||
* @fixup_node: Node offset of the matching local fixups node
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_update_local_nodes_references() update the phandles
|
||||
* pointing to a node within the device tree overlay by adding a
|
||||
* constant delta.
|
||||
*
|
||||
* This is mainly used as part of a device tree application process,
|
||||
* where you want the device tree overlays phandles to not conflict
|
||||
* with the ones from the base device tree before merging them.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_update_local_node_references(void *fdto,
|
||||
int tree_node,
|
||||
int fixup_node,
|
||||
uint32_t delta)
|
||||
{
|
||||
int fixup_prop;
|
||||
int fixup_child;
|
||||
int ret;
|
||||
|
||||
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
|
||||
const fdt32_t *fixup_val;
|
||||
const char *tree_val;
|
||||
const char *name;
|
||||
int fixup_len;
|
||||
int tree_len;
|
||||
int i;
|
||||
|
||||
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
|
||||
&name, &fixup_len);
|
||||
if (!fixup_val)
|
||||
return fixup_len;
|
||||
|
||||
if (fixup_len % sizeof(uint32_t))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
|
||||
if (!tree_val) {
|
||||
if (tree_len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
return tree_len;
|
||||
}
|
||||
|
||||
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
|
||||
fdt32_t adj_val;
|
||||
uint32_t poffset;
|
||||
|
||||
poffset = fdt32_to_cpu(fixup_val[i]);
|
||||
|
||||
/*
|
||||
* phandles to fixup can be unaligned.
|
||||
*
|
||||
* Use a memcpy for the architectures that do
|
||||
* not support unaligned accesses.
|
||||
*/
|
||||
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
|
||||
|
||||
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
|
||||
|
||||
ret = fdt_setprop_inplace_namelen_partial(fdto,
|
||||
tree_node,
|
||||
name,
|
||||
strlen(name),
|
||||
poffset,
|
||||
&adj_val,
|
||||
sizeof(adj_val));
|
||||
if (ret == -FDT_ERR_NOSPACE)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
|
||||
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
|
||||
NULL);
|
||||
int tree_child;
|
||||
|
||||
tree_child = fdt_subnode_offset(fdto, tree_node,
|
||||
fixup_child_name);
|
||||
if (tree_child == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
if (tree_child < 0)
|
||||
return tree_child;
|
||||
|
||||
ret = overlay_update_local_node_references(fdto,
|
||||
tree_child,
|
||||
fixup_child,
|
||||
delta);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_update_local_references - Adjust the overlay references
|
||||
* @fdto: Device tree overlay blob
|
||||
* @delta: Offset to shift the phandles of
|
||||
*
|
||||
* overlay_update_local_references() update all the phandles pointing
|
||||
* to a node within the device tree overlay by adding a constant
|
||||
* delta to not conflict with the base overlay.
|
||||
*
|
||||
* This is mainly used as part of a device tree application process,
|
||||
* where you want the device tree overlays phandles to not conflict
|
||||
* with the ones from the base device tree before merging them.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_update_local_references(void *fdto, uint32_t delta)
|
||||
{
|
||||
int fixups;
|
||||
|
||||
fixups = fdt_path_offset(fdto, "/__local_fixups__");
|
||||
if (fixups < 0) {
|
||||
/* There's no local phandles to adjust, bail out */
|
||||
if (fixups == -FDT_ERR_NOTFOUND)
|
||||
return 0;
|
||||
|
||||
return fixups;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update our local references from the root of the tree
|
||||
*/
|
||||
return overlay_update_local_node_references(fdto, 0, fixups,
|
||||
delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||
* @path: Path to a node holding a phandle in the overlay
|
||||
* @path_len: number of path characters to consider
|
||||
* @name: Name of the property holding the phandle reference in the overlay
|
||||
* @name_len: number of name characters to consider
|
||||
* @poffset: Offset within the overlay property where the phandle is stored
|
||||
* @label: Label of the node referenced by the phandle
|
||||
*
|
||||
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
|
||||
* a node in the base device tree.
|
||||
*
|
||||
* This is part of the device tree overlay application process, when
|
||||
* you want all the phandles in the overlay to point to the actual
|
||||
* base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
|
||||
int symbols_off,
|
||||
const char *path, uint32_t path_len,
|
||||
const char *name, uint32_t name_len,
|
||||
int poffset, const char *label)
|
||||
{
|
||||
const char *symbol_path;
|
||||
uint32_t phandle;
|
||||
fdt32_t phandle_prop;
|
||||
int symbol_off, fixup_off;
|
||||
int prop_len;
|
||||
|
||||
if (symbols_off < 0)
|
||||
return symbols_off;
|
||||
|
||||
symbol_path = fdt_getprop(fdt, symbols_off, label,
|
||||
&prop_len);
|
||||
if (!symbol_path)
|
||||
return prop_len;
|
||||
|
||||
symbol_off = fdt_path_offset(fdt, symbol_path);
|
||||
if (symbol_off < 0)
|
||||
return symbol_off;
|
||||
|
||||
phandle = fdt_get_phandle(fdt, symbol_off);
|
||||
if (!phandle)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
|
||||
if (fixup_off == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
if (fixup_off < 0)
|
||||
return fixup_off;
|
||||
|
||||
phandle_prop = cpu_to_fdt32(phandle);
|
||||
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
|
||||
name, name_len, poffset,
|
||||
&phandle_prop,
|
||||
sizeof(phandle_prop));
|
||||
};
|
||||
|
||||
/**
|
||||
* overlay_fixup_phandle - Set an overlay phandle to the base one
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
* @symbols_off: Node offset of the symbols node in the base device tree
|
||||
* @property: Property offset in the overlay holding the list of fixups
|
||||
*
|
||||
* overlay_fixup_phandle() resolves all the overlay phandles pointed
|
||||
* to in a __fixups__ property, and updates them to match the phandles
|
||||
* in use in the base device tree.
|
||||
*
|
||||
* This is part of the device tree overlay application process, when
|
||||
* you want all the phandles in the overlay to point to the actual
|
||||
* base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
|
||||
int property)
|
||||
{
|
||||
const char *value;
|
||||
const char *label;
|
||||
int len;
|
||||
|
||||
value = fdt_getprop_by_offset(fdto, property,
|
||||
&label, &len);
|
||||
if (!value) {
|
||||
if (len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
do {
|
||||
const char *path, *name, *fixup_end;
|
||||
const char *fixup_str = value;
|
||||
uint32_t path_len, name_len;
|
||||
uint32_t fixup_len;
|
||||
char *sep, *endptr;
|
||||
int poffset, ret;
|
||||
|
||||
fixup_end = memchr(value, '\0', len);
|
||||
if (!fixup_end)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
fixup_len = fixup_end - fixup_str;
|
||||
|
||||
len -= fixup_len + 1;
|
||||
value += fixup_len + 1;
|
||||
|
||||
path = fixup_str;
|
||||
sep = memchr(fixup_str, ':', fixup_len);
|
||||
if (!sep || *sep != ':')
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
path_len = sep - path;
|
||||
if (path_len == (fixup_len - 1))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
fixup_len -= path_len + 1;
|
||||
name = sep + 1;
|
||||
sep = memchr(name, ':', fixup_len);
|
||||
if (!sep || *sep != ':')
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
name_len = sep - name;
|
||||
if (!name_len)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
poffset = strtoul(sep + 1, &endptr, 10);
|
||||
if ((*endptr != '\0') || (endptr <= (sep + 1)))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
|
||||
path, path_len, name, name_len,
|
||||
poffset, label);
|
||||
if (ret)
|
||||
return ret;
|
||||
} while (len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_fixup_phandles - Resolve the overlay phandles to the base
|
||||
* device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
*
|
||||
* overlay_fixup_phandles() resolves all the overlay phandles pointing
|
||||
* to nodes in the base device tree.
|
||||
*
|
||||
* This is one of the steps of the device tree overlay application
|
||||
* process, when you want all the phandles in the overlay to point to
|
||||
* the actual base dt nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_fixup_phandles(void *fdt, void *fdto)
|
||||
{
|
||||
int fixups_off, symbols_off;
|
||||
int property;
|
||||
|
||||
/* We can have overlays without any fixups */
|
||||
fixups_off = fdt_path_offset(fdto, "/__fixups__");
|
||||
if (fixups_off == -FDT_ERR_NOTFOUND)
|
||||
return 0; /* nothing to do */
|
||||
if (fixups_off < 0)
|
||||
return fixups_off;
|
||||
|
||||
/* And base DTs without symbols */
|
||||
symbols_off = fdt_path_offset(fdt, "/__symbols__");
|
||||
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
|
||||
return symbols_off;
|
||||
|
||||
fdt_for_each_property_offset(property, fdto, fixups_off) {
|
||||
int ret;
|
||||
|
||||
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_apply_node - Merges a node into the base device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @target: Node offset in the base device tree to apply the fragment to
|
||||
* @fdto: Device tree overlay blob
|
||||
* @node: Node offset in the overlay holding the changes to merge
|
||||
*
|
||||
* overlay_apply_node() merges a node into a target base device tree
|
||||
* node pointed.
|
||||
*
|
||||
* This is part of the final step in the device tree overlay
|
||||
* application process, when all the phandles have been adjusted and
|
||||
* resolved and you just have to merge overlay into the base device
|
||||
* tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_apply_node(void *fdt, int target,
|
||||
void *fdto, int node)
|
||||
{
|
||||
int property;
|
||||
int subnode;
|
||||
|
||||
fdt_for_each_property_offset(property, fdto, node) {
|
||||
const char *name;
|
||||
const void *prop;
|
||||
int prop_len;
|
||||
int ret;
|
||||
|
||||
prop = fdt_getprop_by_offset(fdto, property, &name,
|
||||
&prop_len);
|
||||
if (prop_len == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
if (prop_len < 0)
|
||||
return prop_len;
|
||||
|
||||
ret = fdt_setprop(fdt, target, name, prop, prop_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(subnode, fdto, node) {
|
||||
const char *name = fdt_get_name(fdto, subnode, NULL);
|
||||
int nnode;
|
||||
int ret;
|
||||
|
||||
nnode = fdt_add_subnode(fdt, target, name);
|
||||
if (nnode == -FDT_ERR_EXISTS) {
|
||||
nnode = fdt_subnode_offset(fdt, target, name);
|
||||
if (nnode == -FDT_ERR_NOTFOUND)
|
||||
return -FDT_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
if (nnode < 0)
|
||||
return nnode;
|
||||
|
||||
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_merge - Merge an overlay into its base device tree
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
*
|
||||
* overlay_merge() merges an overlay into its base device tree.
|
||||
*
|
||||
* This is the next to last step in the device tree overlay application
|
||||
* process, when all the phandles have been adjusted and resolved and
|
||||
* you just have to merge overlay into the base device tree.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_merge(void *fdt, void *fdto)
|
||||
{
|
||||
int fragment;
|
||||
|
||||
fdt_for_each_subnode(fragment, fdto, 0) {
|
||||
int overlay;
|
||||
int target;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Each fragments will have an __overlay__ node. If
|
||||
* they don't, it's not supposed to be merged
|
||||
*/
|
||||
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||
if (overlay == -FDT_ERR_NOTFOUND)
|
||||
continue;
|
||||
|
||||
if (overlay < 0)
|
||||
return overlay;
|
||||
|
||||
target = overlay_get_target(fdt, fdto, fragment, NULL);
|
||||
if (target < 0)
|
||||
return target;
|
||||
|
||||
ret = overlay_apply_node(fdt, target, fdto, overlay);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_path_len(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int len = 0, namelen;
|
||||
const char *name;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
for (;;) {
|
||||
name = fdt_get_name(fdt, nodeoffset, &namelen);
|
||||
if (!name)
|
||||
return namelen;
|
||||
|
||||
/* root? we're done */
|
||||
if (namelen == 0)
|
||||
break;
|
||||
|
||||
nodeoffset = fdt_parent_offset(fdt, nodeoffset);
|
||||
if (nodeoffset < 0)
|
||||
return nodeoffset;
|
||||
len += namelen + 1;
|
||||
}
|
||||
|
||||
/* in case of root pretend it's "/" */
|
||||
if (len == 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* overlay_symbol_update - Update the symbols of base tree after a merge
|
||||
* @fdt: Base Device Tree blob
|
||||
* @fdto: Device tree overlay blob
|
||||
*
|
||||
* overlay_symbol_update() updates the symbols of the base tree with the
|
||||
* symbols of the applied overlay
|
||||
*
|
||||
* This is the last step in the device tree overlay application
|
||||
* process, allowing the reference of overlay symbols by subsequent
|
||||
* overlay operations.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success
|
||||
* Negative error code on failure
|
||||
*/
|
||||
static int overlay_symbol_update(void *fdt, void *fdto)
|
||||
{
|
||||
int root_sym, ov_sym, prop, path_len, fragment, target;
|
||||
int len, frag_name_len, ret, rel_path_len;
|
||||
const char *s, *e;
|
||||
const char *path;
|
||||
const char *name;
|
||||
const char *frag_name;
|
||||
const char *rel_path;
|
||||
const char *target_path;
|
||||
char *buf;
|
||||
void *p;
|
||||
|
||||
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
|
||||
|
||||
/* if no overlay symbols exist no problem */
|
||||
if (ov_sym < 0)
|
||||
return 0;
|
||||
|
||||
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
|
||||
|
||||
/* it no root symbols exist we should create them */
|
||||
if (root_sym == -FDT_ERR_NOTFOUND)
|
||||
root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
|
||||
|
||||
/* any error is fatal now */
|
||||
if (root_sym < 0)
|
||||
return root_sym;
|
||||
|
||||
/* iterate over each overlay symbol */
|
||||
fdt_for_each_property_offset(prop, fdto, ov_sym) {
|
||||
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
|
||||
if (!path)
|
||||
return path_len;
|
||||
|
||||
/* verify it's a string property (terminated by a single \0) */
|
||||
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
/* keep end marker to avoid strlen() */
|
||||
e = path + path_len;
|
||||
|
||||
if (*path != '/')
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
/* get fragment name first */
|
||||
s = strchr(path + 1, '/');
|
||||
if (!s) {
|
||||
/* Symbol refers to something that won't end
|
||||
* up in the target tree */
|
||||
continue;
|
||||
}
|
||||
|
||||
frag_name = path + 1;
|
||||
frag_name_len = s - path - 1;
|
||||
|
||||
/* verify format; safe since "s" lies in \0 terminated prop */
|
||||
len = sizeof("/__overlay__/") - 1;
|
||||
if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
|
||||
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||
rel_path = s + len;
|
||||
rel_path_len = e - rel_path;
|
||||
} else if ((e - s) == len
|
||||
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
|
||||
/* /<fragment-name>/__overlay__ */
|
||||
rel_path = "";
|
||||
rel_path_len = 0;
|
||||
} else {
|
||||
/* Symbol refers to something that won't end
|
||||
* up in the target tree */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the fragment index in which the symbol lies */
|
||||
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
|
||||
frag_name_len);
|
||||
/* not found? */
|
||||
if (ret < 0)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
fragment = ret;
|
||||
|
||||
/* an __overlay__ subnode must exist */
|
||||
ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
|
||||
if (ret < 0)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
/* get the target of the fragment */
|
||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
target = ret;
|
||||
|
||||
/* if we have a target path use */
|
||||
if (!target_path) {
|
||||
ret = get_path_len(fdt, target);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len = ret;
|
||||
} else {
|
||||
len = strlen(target_path);
|
||||
}
|
||||
|
||||
ret = fdt_setprop_placeholder(fdt, root_sym, name,
|
||||
len + (len > 1) + rel_path_len + 1, &p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!target_path) {
|
||||
/* again in case setprop_placeholder changed it */
|
||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
target = ret;
|
||||
}
|
||||
|
||||
buf = p;
|
||||
if (len > 1) { /* target is not root */
|
||||
if (!target_path) {
|
||||
ret = fdt_get_path(fdt, target, buf, len + 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else
|
||||
memcpy(buf, target_path, len + 1);
|
||||
|
||||
} else
|
||||
len--;
|
||||
|
||||
buf[len] = '/';
|
||||
memcpy(buf + len + 1, rel_path, rel_path_len);
|
||||
buf[len + 1 + rel_path_len] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_overlay_apply(void *fdt, void *fdto)
|
||||
{
|
||||
uint32_t delta;
|
||||
int ret;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
FDT_RO_PROBE(fdto);
|
||||
|
||||
ret = fdt_find_max_phandle(fdt, &delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_adjust_local_phandles(fdto, delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_update_local_references(fdto, delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_fixup_phandles(fdt, fdto);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_merge(fdt, fdto);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_symbol_update(fdt, fdto);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* The overlay has been damaged, erase its magic.
|
||||
*/
|
||||
fdt_set_magic(fdto, ~0);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/*
|
||||
* The overlay might have been damaged, erase its magic.
|
||||
*/
|
||||
fdt_set_magic(fdto, ~0);
|
||||
|
||||
/*
|
||||
* The base device tree might have been damaged, erase its
|
||||
* magic.
|
||||
*/
|
||||
fdt_set_magic(fdt, ~0);
|
||||
|
||||
return ret;
|
||||
}
|
898
vendor/riscv-isa-sim/fdt/fdt_ro.c
vendored
Normal file
898
vendor/riscv-isa-sim/fdt/fdt_ro.c
vendored
Normal file
|
@ -0,0 +1,898 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int fdt_nodename_eq_(const void *fdt, int offset,
|
||||
const char *s, int len)
|
||||
{
|
||||
int olen;
|
||||
const char *p = fdt_get_name(fdt, offset, &olen);
|
||||
|
||||
if (!p || olen < len)
|
||||
/* short match */
|
||||
return 0;
|
||||
|
||||
if (memcmp(p, s, len) != 0)
|
||||
return 0;
|
||||
|
||||
if (p[len] == '\0')
|
||||
return 1;
|
||||
else if (!memchr(s, '@', len) && (p[len] == '@'))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||
{
|
||||
int32_t totalsize = fdt_ro_probe_(fdt);
|
||||
uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
|
||||
size_t len;
|
||||
int err;
|
||||
const char *s, *n;
|
||||
|
||||
err = totalsize;
|
||||
if (totalsize < 0)
|
||||
goto fail;
|
||||
|
||||
err = -FDT_ERR_BADOFFSET;
|
||||
if (absoffset >= totalsize)
|
||||
goto fail;
|
||||
len = totalsize - absoffset;
|
||||
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
if (stroffset < 0)
|
||||
goto fail;
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
if (stroffset >= fdt_size_dt_strings(fdt))
|
||||
goto fail;
|
||||
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
|
||||
len = fdt_size_dt_strings(fdt) - stroffset;
|
||||
}
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
if ((stroffset >= 0)
|
||||
|| (stroffset < -fdt_size_dt_strings(fdt)))
|
||||
goto fail;
|
||||
if ((-stroffset) < len)
|
||||
len = -stroffset;
|
||||
} else {
|
||||
err = -FDT_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s = (const char *)fdt + absoffset;
|
||||
n = memchr(s, '\0', len);
|
||||
if (!n) {
|
||||
/* missing terminating NULL */
|
||||
err = -FDT_ERR_TRUNCATED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = n - s;
|
||||
return s;
|
||||
|
||||
fail:
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *fdt_string(const void *fdt, int stroffset)
|
||||
{
|
||||
return fdt_get_string(fdt, stroffset, NULL);
|
||||
}
|
||||
|
||||
static int fdt_string_eq_(const void *fdt, int stroffset,
|
||||
const char *s, int len)
|
||||
{
|
||||
int slen;
|
||||
const char *p = fdt_get_string(fdt, stroffset, &slen);
|
||||
|
||||
return p && (slen == len) && (memcmp(p, s, len) == 0);
|
||||
}
|
||||
|
||||
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
|
||||
{
|
||||
uint32_t max = 0;
|
||||
int offset = -1;
|
||||
|
||||
while (true) {
|
||||
uint32_t value;
|
||||
|
||||
offset = fdt_next_node(fdt, offset, NULL);
|
||||
if (offset < 0) {
|
||||
if (offset == -FDT_ERR_NOTFOUND)
|
||||
break;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
value = fdt_get_phandle(fdt, offset);
|
||||
|
||||
if (value > max)
|
||||
max = value;
|
||||
}
|
||||
|
||||
if (phandle)
|
||||
*phandle = max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
|
||||
{
|
||||
uint32_t max;
|
||||
int err;
|
||||
|
||||
err = fdt_find_max_phandle(fdt, &max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (max == FDT_MAX_PHANDLE)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
if (phandle)
|
||||
*phandle = max + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
|
||||
{
|
||||
int offset = n * sizeof(struct fdt_reserve_entry);
|
||||
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
|
||||
|
||||
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
||||
return NULL;
|
||||
if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
|
||||
return NULL;
|
||||
return fdt_mem_rsv_(fdt, n);
|
||||
}
|
||||
|
||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||
{
|
||||
const struct fdt_reserve_entry *re;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
re = fdt_mem_rsv(fdt, n);
|
||||
if (!re)
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
*address = fdt64_ld(&re->address);
|
||||
*size = fdt64_ld(&re->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_num_mem_rsv(const void *fdt)
|
||||
{
|
||||
int i;
|
||||
const struct fdt_reserve_entry *re;
|
||||
|
||||
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
|
||||
if (fdt64_ld(&re->size) == 0)
|
||||
return i;
|
||||
}
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
static int nextprop_(const void *fdt, int offset)
|
||||
{
|
||||
uint32_t tag;
|
||||
int nextoffset;
|
||||
|
||||
do {
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
switch (tag) {
|
||||
case FDT_END:
|
||||
if (nextoffset >= 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
else
|
||||
return nextoffset;
|
||||
|
||||
case FDT_PROP:
|
||||
return offset;
|
||||
}
|
||||
offset = nextoffset;
|
||||
} while (tag == FDT_NOP);
|
||||
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
int depth;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
for (depth = 0;
|
||||
(offset >= 0) && (depth >= 0);
|
||||
offset = fdt_next_node(fdt, offset, &depth))
|
||||
if ((depth == 1)
|
||||
&& fdt_nodename_eq_(fdt, offset, name, namelen))
|
||||
return offset;
|
||||
|
||||
if (depth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
return offset; /* error */
|
||||
}
|
||||
|
||||
int fdt_subnode_offset(const void *fdt, int parentoffset,
|
||||
const char *name)
|
||||
{
|
||||
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
|
||||
{
|
||||
const char *end = path + namelen;
|
||||
const char *p = path;
|
||||
int offset = 0;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* see if we have an alias */
|
||||
if (*path != '/') {
|
||||
const char *q = memchr(path, '/', end - p);
|
||||
|
||||
if (!q)
|
||||
q = end;
|
||||
|
||||
p = fdt_get_alias_namelen(fdt, p, q - p);
|
||||
if (!p)
|
||||
return -FDT_ERR_BADPATH;
|
||||
offset = fdt_path_offset(fdt, p);
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
while (p < end) {
|
||||
const char *q;
|
||||
|
||||
while (*p == '/') {
|
||||
p++;
|
||||
if (p == end)
|
||||
return offset;
|
||||
}
|
||||
q = memchr(p, '/', end - p);
|
||||
if (! q)
|
||||
q = end;
|
||||
|
||||
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_path_offset(const void *fdt, const char *path)
|
||||
{
|
||||
return fdt_path_offset_namelen(fdt, path, strlen(path));
|
||||
}
|
||||
|
||||
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
{
|
||||
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
|
||||
const char *nameptr;
|
||||
int err;
|
||||
|
||||
if (((err = fdt_ro_probe_(fdt)) < 0)
|
||||
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
|
||||
goto fail;
|
||||
|
||||
nameptr = nh->name;
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
/*
|
||||
* For old FDT versions, match the naming conventions of V16:
|
||||
* give only the leaf name (after all /). The actual tree
|
||||
* contents are loosely checked.
|
||||
*/
|
||||
const char *leaf;
|
||||
leaf = strrchr(nameptr, '/');
|
||||
if (leaf == NULL) {
|
||||
err = -FDT_ERR_BADSTRUCTURE;
|
||||
goto fail;
|
||||
}
|
||||
nameptr = leaf+1;
|
||||
}
|
||||
|
||||
if (len)
|
||||
*len = strlen(nameptr);
|
||||
|
||||
return nameptr;
|
||||
|
||||
fail:
|
||||
if (len)
|
||||
*len = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_first_property_offset(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
|
||||
return offset;
|
||||
|
||||
return nextprop_(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_next_property_offset(const void *fdt, int offset)
|
||||
{
|
||||
if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
|
||||
return offset;
|
||||
|
||||
return nextprop_(fdt, offset);
|
||||
}
|
||||
|
||||
static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
|
||||
int offset,
|
||||
int *lenp)
|
||||
{
|
||||
int err;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prop = fdt_offset_ptr_(fdt, offset);
|
||||
|
||||
if (lenp)
|
||||
*lenp = fdt32_ld(&prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
int offset,
|
||||
int *lenp)
|
||||
{
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fdt_get_property_by_offset_(fdt, offset, lenp);
|
||||
}
|
||||
|
||||
static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
|
||||
int offset,
|
||||
const char *name,
|
||||
int namelen,
|
||||
int *lenp,
|
||||
int *poffset)
|
||||
{
|
||||
for (offset = fdt_first_property_offset(fdt, offset);
|
||||
(offset >= 0);
|
||||
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
|
||||
offset = -FDT_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
|
||||
name, namelen)) {
|
||||
if (poffset)
|
||||
*poffset = offset;
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = offset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
int offset,
|
||||
const char *name,
|
||||
int namelen, int *lenp)
|
||||
{
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
const struct fdt_property *fdt_get_property(const void *fdt,
|
||||
int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_get_property_namelen(fdt, nodeoffset, name,
|
||||
strlen(name), lenp);
|
||||
}
|
||||
|
||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
const char *name, int namelen, int *lenp)
|
||||
{
|
||||
int poffset;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
|
||||
&poffset);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
|
||||
fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
const char **namep, int *lenp)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
if (namep) {
|
||||
const char *name;
|
||||
int namelen;
|
||||
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
|
||||
&namelen);
|
||||
if (!name) {
|
||||
if (lenp)
|
||||
*lenp = namelen;
|
||||
return NULL;
|
||||
}
|
||||
*namep = name;
|
||||
}
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
|
||||
fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
|
||||
const void *fdt_getprop(const void *fdt, int nodeoffset,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
|
||||
}
|
||||
|
||||
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *php;
|
||||
int len;
|
||||
|
||||
/* FIXME: This is a bit sub-optimal, since we potentially scan
|
||||
* over all the properties twice. */
|
||||
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
|
||||
if (!php || (len != sizeof(*php))) {
|
||||
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
|
||||
if (!php || (len != sizeof(*php)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fdt32_ld(php);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias_namelen(const void *fdt,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
int aliasoffset;
|
||||
|
||||
aliasoffset = fdt_path_offset(fdt, "/aliases");
|
||||
if (aliasoffset < 0)
|
||||
return NULL;
|
||||
|
||||
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias(const void *fdt, const char *name)
|
||||
{
|
||||
return fdt_get_alias_namelen(fdt, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
{
|
||||
int pdepth = 0, p = 0;
|
||||
int offset, depth, namelen;
|
||||
const char *name;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (buflen < 2)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
for (offset = 0, depth = 0;
|
||||
(offset >= 0) && (offset <= nodeoffset);
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
while (pdepth > depth) {
|
||||
do {
|
||||
p--;
|
||||
} while (buf[p-1] != '/');
|
||||
pdepth--;
|
||||
}
|
||||
|
||||
if (pdepth >= depth) {
|
||||
name = fdt_get_name(fdt, offset, &namelen);
|
||||
if (!name)
|
||||
return namelen;
|
||||
if ((p + namelen + 1) <= buflen) {
|
||||
memcpy(buf + p, name, namelen);
|
||||
p += namelen;
|
||||
buf[p++] = '/';
|
||||
pdepth++;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == nodeoffset) {
|
||||
if (pdepth < (depth + 1))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
if (p > 1) /* special case so that root path is "/", not "" */
|
||||
p--;
|
||||
buf[p] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||
int supernodedepth, int *nodedepth)
|
||||
{
|
||||
int offset, depth;
|
||||
int supernodeoffset = -FDT_ERR_INTERNAL;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (supernodedepth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
for (offset = 0, depth = 0;
|
||||
(offset >= 0) && (offset <= nodeoffset);
|
||||
offset = fdt_next_node(fdt, offset, &depth)) {
|
||||
if (depth == supernodedepth)
|
||||
supernodeoffset = offset;
|
||||
|
||||
if (offset == nodeoffset) {
|
||||
if (nodedepth)
|
||||
*nodedepth = depth;
|
||||
|
||||
if (supernodedepth > depth)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
else
|
||||
return supernodeoffset;
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_node_depth(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int nodedepth;
|
||||
int err;
|
||||
|
||||
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
|
||||
if (err)
|
||||
return (err < 0) ? err : -FDT_ERR_INTERNAL;
|
||||
return nodedepth;
|
||||
}
|
||||
|
||||
int fdt_parent_offset(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int nodedepth = fdt_node_depth(fdt, nodeoffset);
|
||||
|
||||
if (nodedepth < 0)
|
||||
return nodedepth;
|
||||
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
|
||||
nodedepth - 1, NULL);
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||
const char *propname,
|
||||
const void *propval, int proplen)
|
||||
{
|
||||
int offset;
|
||||
const void *val;
|
||||
int len;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_getprop(), then if that didn't
|
||||
* find what we want, we scan over them again making our way
|
||||
* to the next node. Still it's the easiest to implement
|
||||
* approach; performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
val = fdt_getprop(fdt, offset, propname, &len);
|
||||
if (val && (len == proplen)
|
||||
&& (memcmp(val, propval, len) == 0))
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((phandle == 0) || (phandle == -1))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we
|
||||
* potentially scan each property of a node in
|
||||
* fdt_get_phandle(), then if that didn't find what
|
||||
* we want, we scan over them again making our way to the next
|
||||
* node. Still it's the easiest to implement approach;
|
||||
* performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, -1, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
if (fdt_get_phandle(fdt, offset) == phandle)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
const char *p;
|
||||
|
||||
while (listlen >= len) {
|
||||
if (memcmp(str, strlist, len+1) == 0)
|
||||
return 1;
|
||||
p = memchr(strlist, '\0', listlen);
|
||||
if (!p)
|
||||
return 0; /* malformed strlist.. */
|
||||
listlen -= (p-strlist) + 1;
|
||||
strlist = p + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
|
||||
{
|
||||
const char *list, *end;
|
||||
int length, count = 0;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list)
|
||||
return length;
|
||||
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
list += length;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
||||
const char *string)
|
||||
{
|
||||
int length, len, idx = 0;
|
||||
const char *list, *end;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list)
|
||||
return length;
|
||||
|
||||
len = strlen(string) + 1;
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
if (length == len && memcmp(list, string, length) == 0)
|
||||
return idx;
|
||||
|
||||
list += length;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
|
||||
const char *property, int idx,
|
||||
int *lenp)
|
||||
{
|
||||
const char *list, *end;
|
||||
int length;
|
||||
|
||||
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
||||
if (!list) {
|
||||
if (lenp)
|
||||
*lenp = length;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = list + length;
|
||||
|
||||
while (list < end) {
|
||||
length = strnlen(list, end - list) + 1;
|
||||
|
||||
/* Abort if the last string isn't properly NUL-terminated. */
|
||||
if (list + length > end) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVALUE;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (idx == 0) {
|
||||
if (lenp)
|
||||
*lenp = length - 1;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
list += length;
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_NOTFOUND;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
|
||||
const char *compatible)
|
||||
{
|
||||
const void *prop;
|
||||
int len;
|
||||
|
||||
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
return !fdt_stringlist_contains(prop, len, compatible);
|
||||
}
|
||||
|
||||
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||
const char *compatible)
|
||||
{
|
||||
int offset, err;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_node_check_compatible(), then if
|
||||
* that didn't find what we want, we scan over them again
|
||||
* making our way to the next node. Still it's the easiest to
|
||||
* implement approach; performance can come later. */
|
||||
for (offset = fdt_next_node(fdt, startoffset, NULL);
|
||||
offset >= 0;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
err = fdt_node_check_compatible(fdt, offset, compatible);
|
||||
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
|
||||
return err;
|
||||
else if (err == 0)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
|
||||
int fdt_check_full(const void *fdt, size_t bufsize)
|
||||
{
|
||||
int err;
|
||||
int num_memrsv;
|
||||
int offset, nextoffset = 0;
|
||||
uint32_t tag;
|
||||
unsigned depth = 0;
|
||||
const void *prop;
|
||||
const char *propname;
|
||||
|
||||
if (bufsize < FDT_V1_SIZE)
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
err = fdt_check_header(fdt);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (bufsize < fdt_totalsize(fdt))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
num_memrsv = fdt_num_mem_rsv(fdt);
|
||||
if (num_memrsv < 0)
|
||||
return num_memrsv;
|
||||
|
||||
while (1) {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
switch (tag) {
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
||||
case FDT_END:
|
||||
if (depth != 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
return 0;
|
||||
|
||||
case FDT_BEGIN_NODE:
|
||||
depth++;
|
||||
if (depth > INT_MAX)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
break;
|
||||
|
||||
case FDT_END_NODE:
|
||||
if (depth == 0)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
depth--;
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
prop = fdt_getprop_by_offset(fdt, offset, &propname,
|
||||
&err);
|
||||
if (!prop)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -FDT_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
}
|
476
vendor/riscv-isa-sim/fdt/fdt_rw.c
vendored
Normal file
476
vendor/riscv-isa-sim/fdt/fdt_rw.c
vendored
Normal file
|
@ -0,0 +1,476 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int fdt_blocks_misordered_(const void *fdt,
|
||||
int mem_rsv_size, int struct_size)
|
||||
{
|
||||
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|
||||
|| (fdt_off_dt_struct(fdt) <
|
||||
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|
||||
|| (fdt_off_dt_strings(fdt) <
|
||||
(fdt_off_dt_struct(fdt) + struct_size))
|
||||
|| (fdt_totalsize(fdt) <
|
||||
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
|
||||
}
|
||||
|
||||
static int fdt_rw_probe_(void *fdt)
|
||||
{
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (fdt_version(fdt) < 17)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_BADLAYOUT;
|
||||
if (fdt_version(fdt) > 17)
|
||||
fdt_set_version(fdt, 17);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_RW_PROBE(fdt) \
|
||||
{ \
|
||||
int err_; \
|
||||
if ((err_ = fdt_rw_probe_(fdt)) != 0) \
|
||||
return err_; \
|
||||
}
|
||||
|
||||
static inline int fdt_data_size_(void *fdt)
|
||||
{
|
||||
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||
}
|
||||
|
||||
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
|
||||
{
|
||||
char *p = splicepoint;
|
||||
char *end = (char *)fdt + fdt_data_size_(fdt);
|
||||
|
||||
if (((p + oldlen) < p) || ((p + oldlen) > end))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
memmove(p + newlen, p + oldlen, end - p - oldlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
|
||||
int oldn, int newn)
|
||||
{
|
||||
int delta = (newn - oldn) * sizeof(*p);
|
||||
int err;
|
||||
err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
|
||||
if (err)
|
||||
return err;
|
||||
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
|
||||
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_splice_struct_(void *fdt, void *p,
|
||||
int oldlen, int newlen)
|
||||
{
|
||||
int delta = newlen - oldlen;
|
||||
int err;
|
||||
|
||||
if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
|
||||
return err;
|
||||
|
||||
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
|
||||
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must only be used to roll back in case of error */
|
||||
static void fdt_del_last_string_(void *fdt, const char *s)
|
||||
{
|
||||
int newlen = strlen(s) + 1;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
|
||||
}
|
||||
|
||||
static int fdt_splice_string_(void *fdt, int newlen)
|
||||
{
|
||||
void *p = (char *)fdt
|
||||
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||
int err;
|
||||
|
||||
if ((err = fdt_splice_(fdt, p, 0, newlen)))
|
||||
return err;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
|
||||
const char *p;
|
||||
char *new;
|
||||
int len = strlen(s) + 1;
|
||||
int err;
|
||||
|
||||
*allocated = 0;
|
||||
|
||||
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
|
||||
if (p)
|
||||
/* found it */
|
||||
return (p - strtab);
|
||||
|
||||
new = strtab + fdt_size_dt_strings(fdt);
|
||||
err = fdt_splice_string_(fdt, len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*allocated = 1;
|
||||
|
||||
memcpy(new, s, len);
|
||||
return (new - strtab);
|
||||
}
|
||||
|
||||
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
||||
{
|
||||
struct fdt_reserve_entry *re;
|
||||
int err;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
|
||||
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
re->address = cpu_to_fdt64(address);
|
||||
re->size = cpu_to_fdt64(size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_del_mem_rsv(void *fdt, int n)
|
||||
{
|
||||
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
if (n >= fdt_num_mem_rsv(fdt))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
|
||||
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
|
||||
}
|
||||
|
||||
static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
|
||||
int len, struct fdt_property **prop)
|
||||
{
|
||||
int oldlen;
|
||||
int err;
|
||||
|
||||
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (!*prop)
|
||||
return oldlen;
|
||||
|
||||
if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
|
||||
FDT_TAGALIGN(len))))
|
||||
return err;
|
||||
|
||||
(*prop)->len = cpu_to_fdt32(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
|
||||
int len, struct fdt_property **prop)
|
||||
{
|
||||
int proplen;
|
||||
int nextoffset;
|
||||
int namestroff;
|
||||
int err;
|
||||
int allocated;
|
||||
|
||||
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
|
||||
return nextoffset;
|
||||
|
||||
namestroff = fdt_find_add_string_(fdt, name, &allocated);
|
||||
if (namestroff < 0)
|
||||
return namestroff;
|
||||
|
||||
*prop = fdt_offset_ptr_w_(fdt, nextoffset);
|
||||
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
|
||||
|
||||
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
|
||||
if (err) {
|
||||
if (allocated)
|
||||
fdt_del_last_string_(fdt, name);
|
||||
return err;
|
||||
}
|
||||
|
||||
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
|
||||
(*prop)->nameoff = cpu_to_fdt32(namestroff);
|
||||
(*prop)->len = cpu_to_fdt32(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
char *namep;
|
||||
int oldlen, newlen;
|
||||
int err;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
|
||||
if (!namep)
|
||||
return oldlen;
|
||||
|
||||
newlen = strlen(name);
|
||||
|
||||
err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
|
||||
FDT_TAGALIGN(newlen+1));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(namep, name, newlen+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||
int len, void **prop_data)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
|
||||
if (err == -FDT_ERR_NOTFOUND)
|
||||
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*prop_data = prop->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
void *prop_data;
|
||||
int err;
|
||||
|
||||
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (len)
|
||||
memcpy(prop_data, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err, oldlen, newlen;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (prop) {
|
||||
newlen = len + oldlen;
|
||||
err = fdt_splice_struct_(fdt, prop->data,
|
||||
FDT_TAGALIGN(oldlen),
|
||||
FDT_TAGALIGN(newlen));
|
||||
if (err)
|
||||
return err;
|
||||
prop->len = cpu_to_fdt32(newlen);
|
||||
memcpy(prop->data + oldlen, val, len);
|
||||
} else {
|
||||
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
|
||||
if (err)
|
||||
return err;
|
||||
memcpy(prop->data, val, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int len, proplen;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
|
||||
return fdt_splice_struct_(fdt, prop, proplen, 0);
|
||||
}
|
||||
|
||||
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
struct fdt_node_header *nh;
|
||||
int offset, nextoffset;
|
||||
int nodelen;
|
||||
int err;
|
||||
uint32_t tag;
|
||||
fdt32_t *endtag;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
|
||||
if (offset >= 0)
|
||||
return -FDT_ERR_EXISTS;
|
||||
else if (offset != -FDT_ERR_NOTFOUND)
|
||||
return offset;
|
||||
|
||||
/* Try to place the new node after the parent's properties */
|
||||
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
|
||||
do {
|
||||
offset = nextoffset;
|
||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
|
||||
|
||||
nh = fdt_offset_ptr_w_(fdt, offset);
|
||||
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
|
||||
|
||||
err = fdt_splice_struct_(fdt, nh, 0, nodelen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||
memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
|
||||
memcpy(nh->name, name, namelen);
|
||||
endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
|
||||
*endtag = cpu_to_fdt32(FDT_END_NODE);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
|
||||
{
|
||||
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
|
||||
}
|
||||
|
||||
int fdt_del_node(void *fdt, int nodeoffset)
|
||||
{
|
||||
int endoffset;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
|
||||
if (endoffset < 0)
|
||||
return endoffset;
|
||||
|
||||
return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
|
||||
endoffset - nodeoffset, 0);
|
||||
}
|
||||
|
||||
static void fdt_packblocks_(const char *old, char *new,
|
||||
int mem_rsv_size, int struct_size)
|
||||
{
|
||||
int mem_rsv_off, struct_off, strings_off;
|
||||
|
||||
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
|
||||
struct_off = mem_rsv_off + mem_rsv_size;
|
||||
strings_off = struct_off + struct_size;
|
||||
|
||||
memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
|
||||
fdt_set_off_mem_rsvmap(new, mem_rsv_off);
|
||||
|
||||
memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
|
||||
fdt_set_off_dt_struct(new, struct_off);
|
||||
fdt_set_size_dt_struct(new, struct_size);
|
||||
|
||||
memmove(new + strings_off, old + fdt_off_dt_strings(old),
|
||||
fdt_size_dt_strings(old));
|
||||
fdt_set_off_dt_strings(new, strings_off);
|
||||
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
|
||||
}
|
||||
|
||||
int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
int err;
|
||||
int mem_rsv_size, struct_size;
|
||||
int newsize;
|
||||
const char *fdtstart = fdt;
|
||||
const char *fdtend = fdtstart + fdt_totalsize(fdt);
|
||||
char *tmp;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
struct_size = fdt_size_dt_struct(fdt);
|
||||
} else {
|
||||
struct_size = 0;
|
||||
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
||||
;
|
||||
if (struct_size < 0)
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
|
||||
/* no further work necessary */
|
||||
err = fdt_move(fdt, buf, bufsize);
|
||||
if (err)
|
||||
return err;
|
||||
fdt_set_version(buf, 17);
|
||||
fdt_set_size_dt_struct(buf, struct_size);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Need to reorder */
|
||||
newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
|
||||
+ struct_size + fdt_size_dt_strings(fdt);
|
||||
|
||||
if (bufsize < newsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
/* First attempt to build converted tree at beginning of buffer */
|
||||
tmp = buf;
|
||||
/* But if that overlaps with the old tree... */
|
||||
if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
|
||||
/* Try right after the old tree instead */
|
||||
tmp = (char *)(uintptr_t)fdtend;
|
||||
if ((tmp + newsize) > ((char *)buf + bufsize))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
}
|
||||
|
||||
fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
|
||||
memmove(buf, tmp, newsize);
|
||||
|
||||
fdt_set_magic(buf, FDT_MAGIC);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
fdt_set_version(buf, 17);
|
||||
fdt_set_last_comp_version(buf, 16);
|
||||
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_pack(void *fdt)
|
||||
{
|
||||
int mem_rsv_size;
|
||||
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
|
||||
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
|
||||
|
||||
return 0;
|
||||
}
|
59
vendor/riscv-isa-sim/fdt/fdt_strerror.c
vendored
Normal file
59
vendor/riscv-isa-sim/fdt/fdt_strerror.c
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
struct fdt_errtabent {
|
||||
const char *str;
|
||||
};
|
||||
|
||||
#define FDT_ERRTABENT(val) \
|
||||
[(val)] = { .str = #val, }
|
||||
|
||||
static struct fdt_errtabent fdt_errtable[] = {
|
||||
FDT_ERRTABENT(FDT_ERR_NOTFOUND),
|
||||
FDT_ERRTABENT(FDT_ERR_EXISTS),
|
||||
FDT_ERRTABENT(FDT_ERR_NOSPACE),
|
||||
|
||||
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
|
||||
FDT_ERRTABENT(FDT_ERR_BADPATH),
|
||||
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADSTATE),
|
||||
|
||||
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
|
||||
FDT_ERRTABENT(FDT_ERR_BADMAGIC),
|
||||
FDT_ERRTABENT(FDT_ERR_BADVERSION),
|
||||
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
|
||||
FDT_ERRTABENT(FDT_ERR_INTERNAL),
|
||||
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
|
||||
FDT_ERRTABENT(FDT_ERR_BADVALUE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
|
||||
};
|
||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
||||
|
||||
const char *fdt_strerror(int errval)
|
||||
{
|
||||
if (errval > 0)
|
||||
return "<valid offset/length>";
|
||||
else if (errval == 0)
|
||||
return "<no error>";
|
||||
else if (errval > -FDT_ERRTABSIZE) {
|
||||
const char *s = fdt_errtable[-errval].str;
|
||||
|
||||
if (s)
|
||||
return s;
|
||||
}
|
||||
|
||||
return "<unknown error>";
|
||||
}
|
376
vendor/riscv-isa-sim/fdt/fdt_sw.c
vendored
Normal file
376
vendor/riscv-isa-sim/fdt/fdt_sw.c
vendored
Normal file
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int fdt_sw_probe_(void *fdt)
|
||||
{
|
||||
if (fdt_magic(fdt) == FDT_MAGIC)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_PROBE(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_probe_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
/* 'memrsv' state: Initial state after fdt_create()
|
||||
*
|
||||
* Allowed functions:
|
||||
* fdt_add_reservmap_entry()
|
||||
* fdt_finish_reservemap() [moves to 'struct' state]
|
||||
*/
|
||||
static int fdt_sw_probe_memrsv_(void *fdt)
|
||||
{
|
||||
int err = fdt_sw_probe_(fdt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fdt_off_dt_strings(fdt) != 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_PROBE_MEMRSV(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
/* 'struct' state: Enter this state after fdt_finish_reservemap()
|
||||
*
|
||||
* Allowed functions:
|
||||
* fdt_begin_node()
|
||||
* fdt_end_node()
|
||||
* fdt_property*()
|
||||
* fdt_finish() [moves to 'complete' state]
|
||||
*/
|
||||
static int fdt_sw_probe_struct_(void *fdt)
|
||||
{
|
||||
int err = fdt_sw_probe_(fdt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_PROBE_STRUCT(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
static inline uint32_t sw_flags(void *fdt)
|
||||
{
|
||||
/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
|
||||
return fdt_last_comp_version(fdt);
|
||||
}
|
||||
|
||||
/* 'complete' state: Enter this state after fdt_finish()
|
||||
*
|
||||
* Allowed functions: none
|
||||
*/
|
||||
|
||||
static void *fdt_grab_space_(void *fdt, size_t len)
|
||||
{
|
||||
int offset = fdt_size_dt_struct(fdt);
|
||||
int spaceleft;
|
||||
|
||||
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
|
||||
- fdt_size_dt_strings(fdt);
|
||||
|
||||
if ((offset + len < offset) || (offset + len > spaceleft))
|
||||
return NULL;
|
||||
|
||||
fdt_set_size_dt_struct(fdt, offset + len);
|
||||
return fdt_offset_ptr_w_(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
|
||||
{
|
||||
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
|
||||
sizeof(struct fdt_reserve_entry));
|
||||
void *fdt = buf;
|
||||
|
||||
if (bufsize < hdrsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
if (flags & ~FDT_CREATE_FLAGS_ALL)
|
||||
return -FDT_ERR_BADFLAGS;
|
||||
|
||||
memset(buf, 0, bufsize);
|
||||
|
||||
/*
|
||||
* magic and last_comp_version keep intermediate state during the fdt
|
||||
* creation process, which is replaced with the proper FDT format by
|
||||
* fdt_finish().
|
||||
*
|
||||
* flags should be accessed with sw_flags().
|
||||
*/
|
||||
fdt_set_magic(fdt, FDT_SW_MAGIC);
|
||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
|
||||
fdt_set_last_comp_version(fdt, flags);
|
||||
|
||||
fdt_set_totalsize(fdt, bufsize);
|
||||
|
||||
fdt_set_off_mem_rsvmap(fdt, hdrsize);
|
||||
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
|
||||
fdt_set_off_dt_strings(fdt, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_create(void *buf, int bufsize)
|
||||
{
|
||||
return fdt_create_with_flags(buf, bufsize, 0);
|
||||
}
|
||||
|
||||
int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
size_t headsize, tailsize;
|
||||
char *oldtail, *newtail;
|
||||
|
||||
FDT_SW_PROBE(fdt);
|
||||
|
||||
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
tailsize = fdt_size_dt_strings(fdt);
|
||||
|
||||
if ((headsize + tailsize) > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_INTERNAL;
|
||||
|
||||
if ((headsize + tailsize) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
|
||||
newtail = (char *)buf + bufsize - tailsize;
|
||||
|
||||
/* Two cases to avoid clobbering data if the old and new
|
||||
* buffers partially overlap */
|
||||
if (buf <= fdt) {
|
||||
memmove(buf, fdt, headsize);
|
||||
memmove(newtail, oldtail, tailsize);
|
||||
} else {
|
||||
memmove(newtail, oldtail, tailsize);
|
||||
memmove(buf, fdt, headsize);
|
||||
}
|
||||
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
if (fdt_off_dt_strings(buf))
|
||||
fdt_set_off_dt_strings(buf, bufsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
|
||||
{
|
||||
struct fdt_reserve_entry *re;
|
||||
int offset;
|
||||
|
||||
FDT_SW_PROBE_MEMRSV(fdt);
|
||||
|
||||
offset = fdt_off_dt_struct(fdt);
|
||||
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
re = (struct fdt_reserve_entry *)((char *)fdt + offset);
|
||||
re->address = cpu_to_fdt64(addr);
|
||||
re->size = cpu_to_fdt64(size);
|
||||
|
||||
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_finish_reservemap(void *fdt)
|
||||
{
|
||||
int err = fdt_add_reservemap_entry(fdt, 0, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_begin_node(void *fdt, const char *name)
|
||||
{
|
||||
struct fdt_node_header *nh;
|
||||
int namelen;
|
||||
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
namelen = strlen(name) + 1;
|
||||
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
|
||||
if (! nh)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
|
||||
memcpy(nh->name, name, namelen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_end_node(void *fdt)
|
||||
{
|
||||
fdt32_t *en;
|
||||
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
en = fdt_grab_space_(fdt, FDT_TAGSIZE);
|
||||
if (! en)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
*en = cpu_to_fdt32(FDT_END_NODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_add_string_(void *fdt, const char *s)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
int len = strlen(s) + 1;
|
||||
int struct_top, offset;
|
||||
|
||||
offset = -strtabsize - len;
|
||||
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
if (fdt_totalsize(fdt) + offset < struct_top)
|
||||
return 0; /* no more room :( */
|
||||
|
||||
memcpy(strtab + offset, s, len);
|
||||
fdt_set_size_dt_strings(fdt, strtabsize + len);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Must only be used to roll back in case of error */
|
||||
static void fdt_del_last_string_(void *fdt, const char *s)
|
||||
{
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
int len = strlen(s) + 1;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, strtabsize - len);
|
||||
}
|
||||
|
||||
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
const char *p;
|
||||
|
||||
*allocated = 0;
|
||||
|
||||
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
|
||||
if (p)
|
||||
return p - strtab;
|
||||
|
||||
*allocated = 1;
|
||||
|
||||
return fdt_add_string_(fdt, s);
|
||||
}
|
||||
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int nameoff;
|
||||
int allocated;
|
||||
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
|
||||
if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
|
||||
allocated = 1;
|
||||
nameoff = fdt_add_string_(fdt, name);
|
||||
} else {
|
||||
nameoff = fdt_find_add_string_(fdt, name, &allocated);
|
||||
}
|
||||
if (nameoff == 0)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
|
||||
if (! prop) {
|
||||
if (allocated)
|
||||
fdt_del_last_string_(fdt, name);
|
||||
return -FDT_ERR_NOSPACE;
|
||||
}
|
||||
|
||||
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
prop->len = cpu_to_fdt32(len);
|
||||
*valp = prop->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||||
{
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
ret = fdt_property_placeholder(fdt, name, len, &ptr);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy(ptr, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_finish(void *fdt)
|
||||
{
|
||||
char *p = (char *)fdt;
|
||||
fdt32_t *end;
|
||||
int oldstroffset, newstroffset;
|
||||
uint32_t tag;
|
||||
int offset, nextoffset;
|
||||
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
/* Add terminator */
|
||||
end = fdt_grab_space_(fdt, sizeof(*end));
|
||||
if (! end)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
*end = cpu_to_fdt32(FDT_END);
|
||||
|
||||
/* Relocate the string table */
|
||||
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
|
||||
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
|
||||
fdt_set_off_dt_strings(fdt, newstroffset);
|
||||
|
||||
/* Walk the structure, correcting string offsets */
|
||||
offset = 0;
|
||||
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
|
||||
if (tag == FDT_PROP) {
|
||||
struct fdt_property *prop =
|
||||
fdt_offset_ptr_w_(fdt, offset);
|
||||
int nameoff;
|
||||
|
||||
nameoff = fdt32_to_cpu(prop->nameoff);
|
||||
nameoff += fdt_size_dt_strings(fdt);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
}
|
||||
offset = nextoffset;
|
||||
}
|
||||
if (nextoffset < 0)
|
||||
return nextoffset;
|
||||
|
||||
/* Finally, adjust the header */
|
||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||
|
||||
/* And fix up fields that were keeping intermediate state. */
|
||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
||||
fdt_set_magic(fdt, FDT_MAGIC);
|
||||
|
||||
return 0;
|
||||
}
|
94
vendor/riscv-isa-sim/fdt/fdt_wip.c
vendored
Normal file
94
vendor/riscv-isa-sim/fdt/fdt_wip.c
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||
const char *name, int namelen,
|
||||
uint32_t idx, const void *val,
|
||||
int len)
|
||||
{
|
||||
void *propval;
|
||||
int proplen;
|
||||
|
||||
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
|
||||
&proplen);
|
||||
if (!propval)
|
||||
return proplen;
|
||||
|
||||
if (proplen < (len + idx))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
memcpy((char *)propval + idx, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
{
|
||||
const void *propval;
|
||||
int proplen;
|
||||
|
||||
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||||
if (!propval)
|
||||
return proplen;
|
||||
|
||||
if (proplen != len)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
|
||||
strlen(name), 0,
|
||||
val, len);
|
||||
}
|
||||
|
||||
static void fdt_nop_region_(void *start, int len)
|
||||
{
|
||||
fdt32_t *p;
|
||||
|
||||
for (p = start; (char *)p < ((char *)start + len); p++)
|
||||
*p = cpu_to_fdt32(FDT_NOP);
|
||||
}
|
||||
|
||||
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
fdt_nop_region_(prop, len + sizeof(*prop));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_node_end_offset_(void *fdt, int offset)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
while ((offset >= 0) && (depth >= 0))
|
||||
offset = fdt_next_node(fdt, offset, &depth);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_nop_node(void *fdt, int nodeoffset)
|
||||
{
|
||||
int endoffset;
|
||||
|
||||
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
|
||||
if (endoffset < 0)
|
||||
return endoffset;
|
||||
|
||||
fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
|
||||
endoffset - nodeoffset);
|
||||
return 0;
|
||||
}
|
2077
vendor/riscv-isa-sim/fdt/libfdt.h
vendored
Normal file
2077
vendor/riscv-isa-sim/fdt/libfdt.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
95
vendor/riscv-isa-sim/fdt/libfdt_env.h
vendored
Normal file
95
vendor/riscv-isa-sim/fdt/libfdt_env.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef LIBFDT_ENV_H
|
||||
#define LIBFDT_ENV_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
#define FDT_FORCE __attribute__((force))
|
||||
#define FDT_BITWISE __attribute__((bitwise))
|
||||
#else
|
||||
#define FDT_FORCE
|
||||
#define FDT_BITWISE
|
||||
#endif
|
||||
|
||||
typedef uint16_t FDT_BITWISE fdt16_t;
|
||||
typedef uint32_t FDT_BITWISE fdt32_t;
|
||||
typedef uint64_t FDT_BITWISE fdt64_t;
|
||||
|
||||
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
|
||||
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
|
||||
#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
|
||||
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
|
||||
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
|
||||
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
|
||||
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
|
||||
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
|
||||
|
||||
static inline uint16_t fdt16_to_cpu(fdt16_t x)
|
||||
{
|
||||
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
|
||||
}
|
||||
static inline fdt16_t cpu_to_fdt16(uint16_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t fdt32_to_cpu(fdt32_t x)
|
||||
{
|
||||
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
|
||||
}
|
||||
static inline fdt32_t cpu_to_fdt32(uint32_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t fdt64_to_cpu(fdt64_t x)
|
||||
{
|
||||
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
|
||||
}
|
||||
static inline fdt64_t cpu_to_fdt64(uint64_t x)
|
||||
{
|
||||
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
|
||||
}
|
||||
#undef CPU_TO_FDT64
|
||||
#undef CPU_TO_FDT32
|
||||
#undef CPU_TO_FDT16
|
||||
#undef EXTRACT_BYTE
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
/* strnlen() is not available on Mac OS < 10.7 */
|
||||
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
|
||||
MAC_OS_X_VERSION_10_7)
|
||||
|
||||
#define strnlen fdt_strnlen
|
||||
|
||||
/*
|
||||
* fdt_strnlen: returns the length of a string or max_count - which ever is
|
||||
* smallest.
|
||||
* Input 1 string: the string whose size is to be determined
|
||||
* Input 2 max_count: the maximum value returned by this function
|
||||
* Output: length of the string or max_count (the smallest of the two)
|
||||
*/
|
||||
static inline size_t fdt_strnlen(const char *string, size_t max_count)
|
||||
{
|
||||
const char *p = memchr(string, 0, max_count);
|
||||
return p ? p - string : max_count;
|
||||
}
|
||||
|
||||
#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
|
||||
MAC_OS_X_VERSION_10_7) */
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#endif /* LIBFDT_ENV_H */
|
51
vendor/riscv-isa-sim/fdt/libfdt_internal.h
vendored
Normal file
51
vendor/riscv-isa-sim/fdt/libfdt_internal.h
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef LIBFDT_INTERNAL_H
|
||||
#define LIBFDT_INTERNAL_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*/
|
||||
#include <fdt.h>
|
||||
|
||||
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||
|
||||
int fdt_ro_probe_(const void *fdt);
|
||||
#define FDT_RO_PROBE(fdt) \
|
||||
{ \
|
||||
int totalsize_; \
|
||||
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
|
||||
return totalsize_; \
|
||||
}
|
||||
|
||||
int fdt_check_node_offset_(const void *fdt, int offset);
|
||||
int fdt_check_prop_offset_(const void *fdt, int offset);
|
||||
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
|
||||
int fdt_node_end_offset_(void *fdt, int nodeoffset);
|
||||
|
||||
static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
|
||||
{
|
||||
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
|
||||
}
|
||||
|
||||
static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
|
||||
{
|
||||
return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
|
||||
}
|
||||
|
||||
static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
|
||||
{
|
||||
const struct fdt_reserve_entry *rsv_table =
|
||||
(const struct fdt_reserve_entry *)
|
||||
((const char *)fdt + fdt_off_mem_rsvmap(fdt));
|
||||
|
||||
return rsv_table + n;
|
||||
}
|
||||
static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
|
||||
{
|
||||
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
|
||||
}
|
||||
|
||||
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||
|
||||
#endif /* LIBFDT_INTERNAL_H */
|
94
vendor/riscv-isa-sim/fesvr/byteorder.h
vendored
Normal file
94
vendor/riscv-isa-sim/fesvr/byteorder.h
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef _RISCV_BYTEORDER_H
|
||||
#define _RISCV_BYTEORDER_H
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint8_t swap(uint8_t n) { return n; }
|
||||
static inline uint16_t swap(uint16_t n) { return (n >> 8) | (n << 8); }
|
||||
static inline uint32_t swap(uint32_t n) { return (swap(uint16_t(n)) << 16) | swap(uint16_t(n >> 16)); }
|
||||
static inline uint64_t swap(uint64_t n) { return (uint64_t(swap(uint32_t(n))) << 32) | swap(uint32_t(n >> 32)); }
|
||||
static inline int8_t swap(int8_t n) { return n; }
|
||||
static inline int16_t swap(int16_t n) { return int16_t(swap(uint16_t(n))); }
|
||||
static inline int32_t swap(int32_t n) { return int32_t(swap(uint32_t(n))); }
|
||||
static inline int64_t swap(int64_t n) { return int64_t(swap(uint64_t(n))); }
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
template<typename T> static inline T from_be(T n) { return n; }
|
||||
template<typename T> static inline T to_be(T n) { return n; }
|
||||
template<typename T> static inline T from_le(T n) { return swap(n); }
|
||||
template<typename T> static inline T to_le(T n) { return swap(n); }
|
||||
#else
|
||||
template<typename T> static inline T from_le(T n) { return n; }
|
||||
template<typename T> static inline T to_le(T n) { return n; }
|
||||
template<typename T> static inline T from_be(T n) { return swap(n); }
|
||||
template<typename T> static inline T to_be(T n) { return swap(n); }
|
||||
#endif
|
||||
|
||||
// Wrapper to mark a value as target endian, to guide conversion code
|
||||
|
||||
template<typename T> class base_endian {
|
||||
|
||||
protected:
|
||||
T value;
|
||||
|
||||
base_endian(T n) : value(n) {}
|
||||
|
||||
public:
|
||||
// Setting to and testing against zero never needs swapping
|
||||
base_endian() : value(0) {}
|
||||
bool operator!() { return !value; }
|
||||
|
||||
// Bitwise logic operations can be performed without swapping
|
||||
base_endian& operator|=(const base_endian& rhs) { value |= rhs.value; return *this; }
|
||||
base_endian& operator&=(const base_endian& rhs) { value &= rhs.value; return *this; }
|
||||
base_endian& operator^=(const base_endian& rhs) { value ^= rhs.value; return *this; }
|
||||
|
||||
inline T from_be() { return ::from_be(value); }
|
||||
inline T from_le() { return ::from_le(value); }
|
||||
};
|
||||
|
||||
template<typename T> class target_endian : public base_endian<T> {
|
||||
protected:
|
||||
target_endian(T n) : base_endian<T>(n) {}
|
||||
|
||||
public:
|
||||
target_endian() {}
|
||||
|
||||
static inline target_endian to_be(T n) { return target_endian(::to_be(n)); }
|
||||
static inline target_endian to_le(T n) { return target_endian(::to_le(n)); }
|
||||
|
||||
// Useful values over which swapping is identity
|
||||
static const target_endian zero;
|
||||
static const target_endian all_ones;
|
||||
};
|
||||
|
||||
template<typename T> const target_endian<T> target_endian<T>::zero = target_endian(T(0));
|
||||
template<typename T> const target_endian<T> target_endian<T>::all_ones = target_endian(~T(0));
|
||||
|
||||
|
||||
// Specializations with implicit conversions (no swap information needed)
|
||||
|
||||
template<> class target_endian<uint8_t> : public base_endian<uint8_t> {
|
||||
public:
|
||||
target_endian() {}
|
||||
target_endian(uint8_t n) : base_endian<uint8_t>(n) {}
|
||||
operator uint8_t() { return value; }
|
||||
|
||||
static inline target_endian to_be(uint8_t n) { return target_endian(n); }
|
||||
static inline target_endian to_le(uint8_t n) { return target_endian(n); }
|
||||
};
|
||||
|
||||
template<> class target_endian<int8_t> : public base_endian<int8_t> {
|
||||
public:
|
||||
target_endian() {}
|
||||
target_endian(int8_t n) : base_endian<int8_t>(n) {}
|
||||
operator int8_t() { return value; }
|
||||
|
||||
static inline target_endian to_be(int8_t n) { return target_endian(n); }
|
||||
static inline target_endian to_le(int8_t n) { return target_endian(n); }
|
||||
};
|
||||
|
||||
#endif
|
115
vendor/riscv-isa-sim/fesvr/context.cc
vendored
Normal file
115
vendor/riscv-isa-sim/fesvr/context.cc
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "context.h"
|
||||
#include <assert.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static __thread context_t* cur;
|
||||
|
||||
context_t::context_t()
|
||||
: creator(NULL), func(NULL), arg(NULL),
|
||||
#ifndef USE_UCONTEXT
|
||||
mutex(PTHREAD_MUTEX_INITIALIZER),
|
||||
cond(PTHREAD_COND_INITIALIZER), flag(0)
|
||||
#else
|
||||
context(new ucontext_t)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef USE_UCONTEXT
|
||||
#ifndef GLIBC_64BIT_PTR_BUG
|
||||
void context_t::wrapper(context_t* ctx)
|
||||
{
|
||||
#else
|
||||
void context_t::wrapper(unsigned int hi, unsigned int lo)
|
||||
{
|
||||
context_t* ctx = reinterpret_cast<context_t*>(static_cast<unsigned long>(lo) | (static_cast<unsigned long>(hi) << 32));
|
||||
#endif
|
||||
ctx->creator->switch_to();
|
||||
ctx->func(ctx->arg);
|
||||
}
|
||||
#else
|
||||
void* context_t::wrapper(void* a)
|
||||
{
|
||||
context_t* ctx = static_cast<context_t*>(a);
|
||||
cur = ctx;
|
||||
ctx->creator->switch_to();
|
||||
|
||||
ctx->func(ctx->arg);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void context_t::init(void (*f)(void*), void* a)
|
||||
{
|
||||
func = f;
|
||||
arg = a;
|
||||
creator = current();
|
||||
|
||||
#ifdef USE_UCONTEXT
|
||||
getcontext(context.get());
|
||||
context->uc_link = creator->context.get();
|
||||
context->uc_stack.ss_size = 64*1024;
|
||||
context->uc_stack.ss_sp = new void*[context->uc_stack.ss_size/sizeof(void*)];
|
||||
#ifndef GLIBC_64BIT_PTR_BUG
|
||||
makecontext(context.get(), (void(*)(void))&context_t::wrapper, 1, this);
|
||||
#else
|
||||
unsigned int hi(reinterpret_cast<unsigned long>(this) >> 32);
|
||||
unsigned int lo(reinterpret_cast<unsigned long>(this));
|
||||
makecontext(context.get(), (void(*)(void))&context_t::wrapper, 2, hi, lo);
|
||||
#endif
|
||||
switch_to();
|
||||
#else
|
||||
assert(flag == 0);
|
||||
|
||||
pthread_mutex_lock(&creator->mutex);
|
||||
creator->flag = 0;
|
||||
if (pthread_create(&thread, NULL, &context_t::wrapper, this) != 0)
|
||||
abort();
|
||||
pthread_detach(thread);
|
||||
while (!creator->flag)
|
||||
pthread_cond_wait(&creator->cond, &creator->mutex);
|
||||
pthread_mutex_unlock(&creator->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
context_t::~context_t()
|
||||
{
|
||||
assert(this != cur);
|
||||
}
|
||||
|
||||
void context_t::switch_to()
|
||||
{
|
||||
assert(this != cur);
|
||||
#ifdef USE_UCONTEXT
|
||||
context_t* prev = cur;
|
||||
cur = this;
|
||||
if (swapcontext(prev->context.get(), context.get()) != 0)
|
||||
abort();
|
||||
#else
|
||||
cur->flag = 0;
|
||||
this->flag = 1;
|
||||
pthread_mutex_lock(&this->mutex);
|
||||
pthread_cond_signal(&this->cond);
|
||||
pthread_mutex_unlock(&this->mutex);
|
||||
pthread_mutex_lock(&cur->mutex);
|
||||
while (!cur->flag)
|
||||
pthread_cond_wait(&cur->cond, &cur->mutex);
|
||||
pthread_mutex_unlock(&cur->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
context_t* context_t::current()
|
||||
{
|
||||
if (cur == NULL)
|
||||
{
|
||||
cur = new context_t;
|
||||
#ifdef USE_UCONTEXT
|
||||
getcontext(cur->context.get());
|
||||
#else
|
||||
cur->thread = pthread_self();
|
||||
cur->flag = 1;
|
||||
#endif
|
||||
}
|
||||
return cur;
|
||||
}
|
54
vendor/riscv-isa-sim/fesvr/context.h
vendored
Normal file
54
vendor/riscv-isa-sim/fesvr/context.h
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef _HTIF_CONTEXT_H
|
||||
#define _HTIF_CONTEXT_H
|
||||
|
||||
// A replacement for ucontext.h, which is sadly deprecated.
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
# undef USE_UCONTEXT
|
||||
# define USE_UCONTEXT
|
||||
# include <ucontext.h>
|
||||
# include <memory>
|
||||
#include <limits.h>
|
||||
|
||||
#if (ULONG_MAX > UINT_MAX) // 64-bit systems only
|
||||
#if (100*GLIB_MAJOR_VERSION+GLIB_MINOR_VERSION < 208)
|
||||
#define GLIBC_64BIT_PTR_BUG
|
||||
static_assert (sizeof(unsigned int) == 4, "uint size doesn't match expected 32bit");
|
||||
static_assert (sizeof(unsigned long) == 8, "ulong size doesn't match expected 64bit");
|
||||
static_assert (sizeof(void*) == 8, "ptr size doesn't match expected 64bit");
|
||||
#endif
|
||||
#endif /* ULONG_MAX > UINT_MAX */
|
||||
|
||||
#endif
|
||||
|
||||
class context_t
|
||||
{
|
||||
public:
|
||||
context_t();
|
||||
~context_t();
|
||||
void init(void (*func)(void*), void* arg);
|
||||
void switch_to();
|
||||
static context_t* current();
|
||||
private:
|
||||
context_t* creator;
|
||||
void (*func)(void*);
|
||||
void* arg;
|
||||
#ifdef USE_UCONTEXT
|
||||
std::unique_ptr<ucontext_t> context;
|
||||
#ifndef GLIBC_64BIT_PTR_BUG
|
||||
static void wrapper(context_t*);
|
||||
#else
|
||||
static void wrapper(unsigned int, unsigned int);
|
||||
#endif
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
volatile int flag;
|
||||
static void* wrapper(void*);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
1418
vendor/riscv-isa-sim/fesvr/debug_defines.h
vendored
Normal file
1418
vendor/riscv-isa-sim/fesvr/debug_defines.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
154
vendor/riscv-isa-sim/fesvr/device.cc
vendored
Normal file
154
vendor/riscv-isa-sim/fesvr/device.cc
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
#include "device.h"
|
||||
#include "term.h"
|
||||
#include "memif.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
using namespace std::placeholders;
|
||||
|
||||
device_t::device_t()
|
||||
: command_handlers(command_t::MAX_COMMANDS),
|
||||
command_names(command_t::MAX_COMMANDS)
|
||||
{
|
||||
for (size_t cmd = 0; cmd < command_t::MAX_COMMANDS; cmd++)
|
||||
register_command(cmd, std::bind(&device_t::handle_null_command, this, _1), "");
|
||||
register_command(command_t::MAX_COMMANDS-1, std::bind(&device_t::handle_identify, this, _1), "identity");
|
||||
}
|
||||
|
||||
void device_t::register_command(size_t cmd, command_func_t handler, const char* name)
|
||||
{
|
||||
assert(cmd < command_t::MAX_COMMANDS);
|
||||
assert(strlen(name) < IDENTITY_SIZE);
|
||||
command_handlers[cmd] = handler;
|
||||
command_names[cmd] = name;
|
||||
}
|
||||
|
||||
void device_t::handle_command(command_t cmd)
|
||||
{
|
||||
command_handlers[cmd.cmd()](cmd);
|
||||
}
|
||||
|
||||
void device_t::handle_null_command(command_t cmd)
|
||||
{
|
||||
}
|
||||
|
||||
void device_t::handle_identify(command_t cmd)
|
||||
{
|
||||
size_t what = cmd.payload() % command_t::MAX_COMMANDS;
|
||||
uint64_t addr = cmd.payload() / command_t::MAX_COMMANDS;
|
||||
|
||||
char id[IDENTITY_SIZE] = {0};
|
||||
if (what == command_t::MAX_COMMANDS-1)
|
||||
{
|
||||
assert(strlen(identity()) < IDENTITY_SIZE);
|
||||
strcpy(id, identity());
|
||||
}
|
||||
else
|
||||
strcpy(id, command_names[what].c_str());
|
||||
|
||||
cmd.memif().write(addr, IDENTITY_SIZE, id);
|
||||
cmd.respond(1);
|
||||
}
|
||||
|
||||
bcd_t::bcd_t()
|
||||
{
|
||||
register_command(0, std::bind(&bcd_t::handle_read, this, _1), "read");
|
||||
register_command(1, std::bind(&bcd_t::handle_write, this, _1), "write");
|
||||
}
|
||||
|
||||
void bcd_t::handle_read(command_t cmd)
|
||||
{
|
||||
pending_reads.push(cmd);
|
||||
}
|
||||
|
||||
void bcd_t::handle_write(command_t cmd)
|
||||
{
|
||||
canonical_terminal_t::write(cmd.payload());
|
||||
}
|
||||
|
||||
void bcd_t::tick()
|
||||
{
|
||||
int ch;
|
||||
if (!pending_reads.empty() && (ch = canonical_terminal_t::read()) != -1)
|
||||
{
|
||||
pending_reads.front().respond(0x100 | ch);
|
||||
pending_reads.pop();
|
||||
}
|
||||
}
|
||||
|
||||
disk_t::disk_t(const char* fn)
|
||||
{
|
||||
fd = ::open(fn, O_RDWR);
|
||||
if (fd < 0)
|
||||
throw std::runtime_error("could not open " + std::string(fn));
|
||||
|
||||
register_command(0, std::bind(&disk_t::handle_read, this, _1), "read");
|
||||
register_command(1, std::bind(&disk_t::handle_write, this, _1), "write");
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) < 0)
|
||||
throw std::runtime_error("could not stat " + std::string(fn));
|
||||
|
||||
size = st.st_size;
|
||||
id = "disk size=" + std::to_string(size);
|
||||
}
|
||||
|
||||
disk_t::~disk_t()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void disk_t::handle_read(command_t cmd)
|
||||
{
|
||||
request_t req;
|
||||
cmd.memif().read(cmd.payload(), sizeof(req), &req);
|
||||
|
||||
std::vector<uint8_t> buf(req.size);
|
||||
if ((size_t)::pread(fd, buf.data(), buf.size(), req.offset) != req.size)
|
||||
throw std::runtime_error("could not read " + id + " @ " + std::to_string(req.offset));
|
||||
|
||||
cmd.memif().write(req.addr, buf.size(), buf.data());
|
||||
cmd.respond(req.tag);
|
||||
}
|
||||
|
||||
void disk_t::handle_write(command_t cmd)
|
||||
{
|
||||
request_t req;
|
||||
cmd.memif().read(cmd.payload(), sizeof(req), &req);
|
||||
|
||||
std::vector<uint8_t> buf(req.size);
|
||||
cmd.memif().read(req.addr, buf.size(), buf.data());
|
||||
|
||||
if ((size_t)::pwrite(fd, buf.data(), buf.size(), req.offset) != req.size)
|
||||
throw std::runtime_error("could not write " + id + " @ " + std::to_string(req.offset));
|
||||
|
||||
cmd.respond(req.tag);
|
||||
}
|
||||
|
||||
device_list_t::device_list_t()
|
||||
: devices(command_t::MAX_COMMANDS, &null_device), num_devices(0)
|
||||
{
|
||||
}
|
||||
|
||||
void device_list_t::register_device(device_t* dev)
|
||||
{
|
||||
num_devices++;
|
||||
assert(num_devices < command_t::MAX_DEVICES);
|
||||
devices[num_devices-1] = dev;
|
||||
}
|
||||
|
||||
void device_list_t::handle_command(command_t cmd)
|
||||
{
|
||||
devices[cmd.device()]->handle_command(cmd);
|
||||
}
|
||||
|
||||
void device_list_t::tick()
|
||||
{
|
||||
for (size_t i = 0; i < num_devices; i++)
|
||||
devices[i]->tick();
|
||||
}
|
118
vendor/riscv-isa-sim/fesvr/device.h
vendored
Normal file
118
vendor/riscv-isa-sim/fesvr/device.h
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
#ifndef _DEVICE_H
|
||||
#define _DEVICE_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class memif_t;
|
||||
|
||||
class command_t
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(uint64_t)> callback_t;
|
||||
command_t(memif_t& memif, uint64_t tohost, callback_t cb)
|
||||
: _memif(memif), tohost(tohost), cb(cb) {}
|
||||
|
||||
memif_t& memif() { return _memif; }
|
||||
uint8_t device() { return tohost >> 56; }
|
||||
uint8_t cmd() { return tohost >> 48; }
|
||||
uint64_t payload() { return tohost << 16 >> 16; }
|
||||
void respond(uint64_t resp) { cb((tohost >> 48 << 48) | (resp << 16 >> 16)); }
|
||||
|
||||
static const size_t MAX_COMMANDS = 256;
|
||||
static const size_t MAX_DEVICES = 256;
|
||||
|
||||
private:
|
||||
memif_t& _memif;
|
||||
uint64_t tohost;
|
||||
callback_t cb;
|
||||
};
|
||||
|
||||
class device_t
|
||||
{
|
||||
public:
|
||||
device_t();
|
||||
virtual ~device_t() {}
|
||||
virtual const char* identity() = 0;
|
||||
virtual void tick() {}
|
||||
|
||||
void handle_command(command_t cmd);
|
||||
|
||||
protected:
|
||||
typedef std::function<void(command_t)> command_func_t;
|
||||
void register_command(size_t, command_func_t, const char*);
|
||||
|
||||
private:
|
||||
device_t& operator = (const device_t&); // disallow
|
||||
device_t(const device_t&); // disallow
|
||||
|
||||
static const size_t IDENTITY_SIZE = 64;
|
||||
void handle_null_command(command_t cmd);
|
||||
void handle_identify(command_t cmd);
|
||||
|
||||
std::vector<command_func_t> command_handlers;
|
||||
std::vector<std::string> command_names;
|
||||
};
|
||||
|
||||
class bcd_t : public device_t
|
||||
{
|
||||
public:
|
||||
bcd_t();
|
||||
const char* identity() { return "bcd"; }
|
||||
void tick();
|
||||
|
||||
private:
|
||||
void handle_read(command_t cmd);
|
||||
void handle_write(command_t cmd);
|
||||
|
||||
std::queue<command_t> pending_reads;
|
||||
};
|
||||
|
||||
class disk_t : public device_t
|
||||
{
|
||||
public:
|
||||
disk_t(const char* fn);
|
||||
~disk_t();
|
||||
const char* identity() { return id.c_str(); }
|
||||
|
||||
private:
|
||||
struct request_t
|
||||
{
|
||||
uint64_t addr;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint64_t tag;
|
||||
};
|
||||
|
||||
void handle_read(command_t cmd);
|
||||
void handle_write(command_t cmd);
|
||||
|
||||
std::string id;
|
||||
size_t size;
|
||||
int fd;
|
||||
};
|
||||
|
||||
class null_device_t : public device_t
|
||||
{
|
||||
public:
|
||||
const char* identity() { return ""; }
|
||||
};
|
||||
|
||||
class device_list_t
|
||||
{
|
||||
public:
|
||||
device_list_t();
|
||||
void register_device(device_t* dev);
|
||||
void handle_command(command_t cmd);
|
||||
void tick();
|
||||
|
||||
private:
|
||||
std::vector<device_t*> devices;
|
||||
null_device_t null_device;
|
||||
size_t num_devices;
|
||||
};
|
||||
|
||||
#endif
|
644
vendor/riscv-isa-sim/fesvr/dtm.cc
vendored
Normal file
644
vendor/riscv-isa-sim/fesvr/dtm.cc
vendored
Normal file
|
@ -0,0 +1,644 @@
|
|||
#include "dtm.h"
|
||||
#include "debug_defines.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#define RV_X(x, s, n) \
|
||||
(((x) >> (s)) & ((1 << (n)) - 1))
|
||||
#define ENCODE_ITYPE_IMM(x) \
|
||||
(RV_X(x, 0, 12) << 20)
|
||||
#define ENCODE_STYPE_IMM(x) \
|
||||
((RV_X(x, 0, 5) << 7) | (RV_X(x, 5, 7) << 25))
|
||||
#define ENCODE_SBTYPE_IMM(x) \
|
||||
((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
|
||||
#define ENCODE_UTYPE_IMM(x) \
|
||||
(RV_X(x, 12, 20) << 12)
|
||||
#define ENCODE_UJTYPE_IMM(x) \
|
||||
((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
|
||||
|
||||
#define LOAD(xlen, dst, base, imm) \
|
||||
(((xlen) == 64 ? 0x00003003 : 0x00002003) \
|
||||
| ((dst) << 7) | ((base) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
|
||||
#define STORE(xlen, src, base, imm) \
|
||||
(((xlen) == 64 ? 0x00003023 : 0x00002023) \
|
||||
| ((src) << 20) | ((base) << 15) | (uint32_t)ENCODE_STYPE_IMM(imm))
|
||||
#define JUMP(there, here) (0x6f | (uint32_t)ENCODE_UJTYPE_IMM((there) - (here)))
|
||||
#define BNE(r1, r2, there, here) (0x1063 | ((r1) << 15) | ((r2) << 20) | (uint32_t)ENCODE_SBTYPE_IMM((there) - (here)))
|
||||
#define ADDI(dst, src, imm) (0x13 | ((dst) << 7) | ((src) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
|
||||
#define SRL(dst, src, sh) (0x5033 | ((dst) << 7) | ((src) << 15) | ((sh) << 20))
|
||||
#define FENCE_I 0x100f
|
||||
#define EBREAK 0x00100073
|
||||
#define X0 0
|
||||
#define S0 8
|
||||
#define S1 9
|
||||
|
||||
#define AC_AR_REGNO(x) ((0x1000 | x) << AC_ACCESS_REGISTER_REGNO_OFFSET)
|
||||
#define AC_AR_SIZE(x) (((x == 128)? 4 : (x == 64 ? 3 : 2)) << AC_ACCESS_REGISTER_SIZE_OFFSET)
|
||||
|
||||
#define WRITE 1
|
||||
#define SET 2
|
||||
#define CLEAR 3
|
||||
#define CSRRx(type, dst, csr, src) (0x73 | ((type) << 12) | ((dst) << 7) | ((src) << 15) | (uint32_t)((csr) << 20))
|
||||
|
||||
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
|
||||
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
|
||||
|
||||
#define RUN_AC_OR_DIE(a, b, c, d, e) { \
|
||||
uint32_t cmderr = run_abstract_command(a, b, c, d, e); \
|
||||
if (cmderr) { \
|
||||
die(cmderr); \
|
||||
} \
|
||||
}
|
||||
|
||||
uint32_t dtm_t::do_command(dtm_t::req r)
|
||||
{
|
||||
req_buf = r;
|
||||
target->switch_to();
|
||||
assert(resp_buf.resp == 0);
|
||||
return resp_buf.data;
|
||||
}
|
||||
|
||||
uint32_t dtm_t::read(uint32_t addr)
|
||||
{
|
||||
return do_command((req){addr, 1, 0});
|
||||
}
|
||||
|
||||
uint32_t dtm_t::write(uint32_t addr, uint32_t data)
|
||||
{
|
||||
return do_command((req){addr, 2, data});
|
||||
}
|
||||
|
||||
void dtm_t::nop()
|
||||
{
|
||||
do_command((req){0, 0, 0});
|
||||
}
|
||||
|
||||
void dtm_t::select_hart(int hartsel) {
|
||||
int dmcontrol = read(DMI_DMCONTROL);
|
||||
write (DMI_DMCONTROL, set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel));
|
||||
current_hart = hartsel;
|
||||
}
|
||||
|
||||
int dtm_t::enumerate_harts() {
|
||||
int max_hart = (1 << DMI_DMCONTROL_HARTSEL_LENGTH) - 1;
|
||||
write(DMI_DMCONTROL, set_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL, max_hart));
|
||||
read(DMI_DMSTATUS);
|
||||
max_hart = get_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL);
|
||||
|
||||
int hartsel;
|
||||
for (hartsel = 0; hartsel <= max_hart; hartsel++) {
|
||||
select_hart(hartsel);
|
||||
int dmstatus = read(DMI_DMSTATUS);
|
||||
if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT))
|
||||
break;
|
||||
}
|
||||
return hartsel;
|
||||
}
|
||||
|
||||
void dtm_t::halt(int hartsel)
|
||||
{
|
||||
if (running) {
|
||||
write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
|
||||
// Read dmstatus to avoid back-to-back writes to dmcontrol.
|
||||
read(DMI_DMSTATUS);
|
||||
}
|
||||
|
||||
int dmcontrol = DMI_DMCONTROL_HALTREQ | DMI_DMCONTROL_DMACTIVE;
|
||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
|
||||
write(DMI_DMCONTROL, dmcontrol);
|
||||
int dmstatus;
|
||||
do {
|
||||
dmstatus = read(DMI_DMSTATUS);
|
||||
} while(get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
|
||||
dmcontrol &= ~DMI_DMCONTROL_HALTREQ;
|
||||
write(DMI_DMCONTROL, dmcontrol);
|
||||
// Read dmstatus to avoid back-to-back writes to dmcontrol.
|
||||
read(DMI_DMSTATUS);
|
||||
current_hart = hartsel;
|
||||
}
|
||||
|
||||
void dtm_t::resume(int hartsel)
|
||||
{
|
||||
int dmcontrol = DMI_DMCONTROL_RESUMEREQ | DMI_DMCONTROL_DMACTIVE;
|
||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
|
||||
write(DMI_DMCONTROL, dmcontrol);
|
||||
int dmstatus;
|
||||
do {
|
||||
dmstatus = read(DMI_DMSTATUS);
|
||||
} while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0);
|
||||
dmcontrol &= ~DMI_DMCONTROL_RESUMEREQ;
|
||||
write(DMI_DMCONTROL, dmcontrol);
|
||||
// Read dmstatus to avoid back-to-back writes to dmcontrol.
|
||||
read(DMI_DMSTATUS);
|
||||
current_hart = hartsel;
|
||||
|
||||
if (running) {
|
||||
write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
|
||||
// Read dmstatus to avoid back-to-back writes to dmcontrol.
|
||||
read(DMI_DMSTATUS);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t dtm_t::save_reg(unsigned regno)
|
||||
{
|
||||
uint32_t data[xlen/(8*4)];
|
||||
uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno);
|
||||
RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
|
||||
|
||||
uint64_t result = data[0];
|
||||
if (xlen > 32) {
|
||||
result |= ((uint64_t)data[1]) << 32;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void dtm_t::restore_reg(unsigned regno, uint64_t val)
|
||||
{
|
||||
uint32_t data[xlen/(8*4)];
|
||||
data[0] = (uint32_t) val;
|
||||
if (xlen > 32) {
|
||||
data[1] = (uint32_t) (val >> 32);
|
||||
}
|
||||
|
||||
uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(regno);
|
||||
|
||||
RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
|
||||
|
||||
}
|
||||
|
||||
uint32_t dtm_t::run_abstract_command(uint32_t command,
|
||||
const uint32_t program[], size_t program_n,
|
||||
uint32_t data[], size_t data_n)
|
||||
{
|
||||
assert(program_n <= ram_words);
|
||||
assert(data_n <= data_words);
|
||||
|
||||
for (size_t i = 0; i < program_n; i++) {
|
||||
write(DMI_PROGBUF0 + i, program[i]);
|
||||
}
|
||||
|
||||
if (get_field(command, AC_ACCESS_REGISTER_WRITE) &&
|
||||
get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
|
||||
for (size_t i = 0; i < data_n; i++) {
|
||||
write(DMI_DATA0 + i, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
write(DMI_COMMAND, command);
|
||||
|
||||
// Wait for not busy and then check for error.
|
||||
uint32_t abstractcs;
|
||||
do {
|
||||
abstractcs = read(DMI_ABSTRACTCS);
|
||||
} while (abstractcs & DMI_ABSTRACTCS_BUSY);
|
||||
|
||||
if ((get_field(command, AC_ACCESS_REGISTER_WRITE) == 0) &&
|
||||
get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
|
||||
for (size_t i = 0; i < data_n; i++){
|
||||
data[i] = read(DMI_DATA0 + i);
|
||||
}
|
||||
}
|
||||
|
||||
return get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||
|
||||
}
|
||||
|
||||
size_t dtm_t::chunk_align()
|
||||
{
|
||||
return xlen / 8;
|
||||
}
|
||||
|
||||
void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst)
|
||||
{
|
||||
uint32_t prog[ram_words];
|
||||
uint32_t data[data_words];
|
||||
|
||||
uint8_t * curr = (uint8_t*) dst;
|
||||
|
||||
halt(current_hart);
|
||||
|
||||
uint64_t s0 = save_reg(S0);
|
||||
uint64_t s1 = save_reg(S1);
|
||||
|
||||
prog[0] = LOAD(xlen, S1, S0, 0);
|
||||
prog[1] = ADDI(S0, S0, xlen/8);
|
||||
prog[2] = EBREAK;
|
||||
|
||||
data[0] = (uint32_t) taddr;
|
||||
if (xlen > 32) {
|
||||
data[1] = (uint32_t) (taddr >> 32);
|
||||
}
|
||||
|
||||
// Write s0 with the address, then execute program buffer.
|
||||
// This will get S1 with the data and increment s0.
|
||||
uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_ACCESS_REGISTER_POSTEXEC |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S0);
|
||||
|
||||
RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
|
||||
|
||||
// TODO: could use autoexec here.
|
||||
for (size_t i = 0; i < (len * 8 / xlen); i++){
|
||||
command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S1);
|
||||
if ((i + 1) < (len * 8 / xlen)) {
|
||||
command |= AC_ACCESS_REGISTER_POSTEXEC;
|
||||
}
|
||||
|
||||
RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
|
||||
|
||||
memcpy(curr, data, xlen/8);
|
||||
curr += xlen/8;
|
||||
}
|
||||
|
||||
restore_reg(S0, s0);
|
||||
restore_reg(S1, s1);
|
||||
|
||||
resume(current_hart);
|
||||
|
||||
}
|
||||
|
||||
void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src)
|
||||
{
|
||||
uint32_t prog[ram_words];
|
||||
uint32_t data[data_words];
|
||||
|
||||
const uint8_t * curr = (const uint8_t*) src;
|
||||
|
||||
halt(current_hart);
|
||||
|
||||
uint64_t s0 = save_reg(S0);
|
||||
uint64_t s1 = save_reg(S1);
|
||||
|
||||
prog[0] = STORE(xlen, S1, S0, 0);
|
||||
prog[1] = ADDI(S0, S0, xlen/8);
|
||||
prog[2] = EBREAK;
|
||||
|
||||
data[0] = (uint32_t) taddr;
|
||||
if (xlen > 32) {
|
||||
data[1] = (uint32_t) (taddr >> 32);
|
||||
}
|
||||
|
||||
// Write the program (not used yet).
|
||||
// Write s0 with the address.
|
||||
uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S0);
|
||||
|
||||
RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
|
||||
|
||||
// Use Autoexec for more than one word of transfer.
|
||||
// Write S1 with data, then execution stores S1 to
|
||||
// 0(S0) and increments S0.
|
||||
// Each time we write XLEN bits.
|
||||
memcpy(data, curr, xlen/8);
|
||||
curr += xlen/8;
|
||||
|
||||
command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_POSTEXEC |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S1);
|
||||
|
||||
RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
|
||||
|
||||
uint32_t abstractcs;
|
||||
for (size_t i = 1; i < (len * 8 / xlen); i++){
|
||||
if (i == 1) {
|
||||
write(DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||
}
|
||||
memcpy(data, curr, xlen/8);
|
||||
curr += xlen/8;
|
||||
if (xlen == 64) {
|
||||
write(DMI_DATA0 + 1, data[1]);
|
||||
}
|
||||
write(DMI_DATA0, data[0]); //Triggers a command w/ autoexec.
|
||||
|
||||
do {
|
||||
abstractcs = read(DMI_ABSTRACTCS);
|
||||
} while (abstractcs & DMI_ABSTRACTCS_BUSY);
|
||||
if ( get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
||||
die(get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
|
||||
}
|
||||
}
|
||||
if ((len * 8 / xlen) > 1) {
|
||||
write(DMI_ABSTRACTAUTO, 0);
|
||||
}
|
||||
|
||||
restore_reg(S0, s0);
|
||||
restore_reg(S1, s1);
|
||||
resume(current_hart);
|
||||
}
|
||||
|
||||
void dtm_t::die(uint32_t cmderr)
|
||||
{
|
||||
const char * codes[] = {
|
||||
"OK",
|
||||
"BUSY",
|
||||
"NOT_SUPPORTED",
|
||||
"EXCEPTION",
|
||||
"HALT/RESUME"
|
||||
};
|
||||
const char * msg;
|
||||
if (cmderr < (sizeof(codes) / sizeof(*codes))){
|
||||
msg = codes[cmderr];
|
||||
} else {
|
||||
msg = "OTHER";
|
||||
}
|
||||
//throw std::runtime_error("Debug Abstract Command Error #" + std::to_string(cmderr) + "(" + msg + ")");
|
||||
printf("ERROR: %s:%d, Debug Abstract Command Error #%d (%s)", __FILE__, __LINE__, cmderr, msg);
|
||||
printf("ERROR: %s:%d, Should die, but allowing simulation to continue and fail.", __FILE__, __LINE__);
|
||||
write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||
|
||||
}
|
||||
|
||||
void dtm_t::clear_chunk(uint64_t taddr, size_t len)
|
||||
{
|
||||
uint32_t prog[ram_words];
|
||||
uint32_t data[data_words];
|
||||
|
||||
halt(current_hart);
|
||||
uint64_t s0 = save_reg(S0);
|
||||
uint64_t s1 = save_reg(S1);
|
||||
|
||||
uint32_t command;
|
||||
|
||||
// S0 = Addr
|
||||
data[0] = (uint32_t) taddr;
|
||||
data[1] = (uint32_t) (taddr >> 32);
|
||||
command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S0);
|
||||
RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
|
||||
|
||||
// S1 = Addr + len, loop until S0 = S1
|
||||
prog[0] = STORE(xlen, X0, S0, 0);
|
||||
prog[1] = ADDI(S0, S0, xlen/8);
|
||||
prog[2] = BNE(S0, S1, 0*4, 2*4);
|
||||
prog[3] = EBREAK;
|
||||
|
||||
data[0] = (uint32_t) (taddr + len);
|
||||
data[1] = (uint32_t) ((taddr + len) >> 32);
|
||||
command = AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(S1) |
|
||||
AC_ACCESS_REGISTER_POSTEXEC;
|
||||
RUN_AC_OR_DIE(command, prog, 4, data, xlen/(4*8));
|
||||
|
||||
restore_reg(S0, s0);
|
||||
restore_reg(S1, s1);
|
||||
|
||||
resume(current_hart);
|
||||
}
|
||||
|
||||
uint64_t dtm_t::write_csr(unsigned which, uint64_t data)
|
||||
{
|
||||
return modify_csr(which, data, WRITE);
|
||||
}
|
||||
|
||||
uint64_t dtm_t::set_csr(unsigned which, uint64_t data)
|
||||
{
|
||||
return modify_csr(which, data, SET);
|
||||
}
|
||||
|
||||
uint64_t dtm_t::clear_csr(unsigned which, uint64_t data)
|
||||
{
|
||||
return modify_csr(which, data, CLEAR);
|
||||
}
|
||||
|
||||
uint64_t dtm_t::read_csr(unsigned which)
|
||||
{
|
||||
return set_csr(which, 0);
|
||||
}
|
||||
|
||||
uint64_t dtm_t::modify_csr(unsigned which, uint64_t data, uint32_t type)
|
||||
{
|
||||
halt(current_hart);
|
||||
|
||||
// This code just uses DSCRATCH to save S0
|
||||
// and data_base to do the transfer so we don't
|
||||
// need to run more commands to save and restore
|
||||
// S0.
|
||||
uint32_t prog[] = {
|
||||
CSRRx(WRITE, S0, CSR_DSCRATCH0, S0),
|
||||
LOAD(xlen, S0, X0, data_base),
|
||||
CSRRx(type, S0, which, S0),
|
||||
STORE(xlen, S0, X0, data_base),
|
||||
CSRRx(WRITE, S0, CSR_DSCRATCH0, S0),
|
||||
EBREAK
|
||||
};
|
||||
|
||||
//TODO: Use transfer = 0. For now both HW and OpenOCD
|
||||
// ignore transfer bit, so use "store to X0" NOOP.
|
||||
// We sort of need this anyway because run_abstract_command
|
||||
// needs the DATA to be written so may as well use the WRITE flag.
|
||||
|
||||
uint32_t adata[] = {(uint32_t) data,
|
||||
(uint32_t) (data >> 32)};
|
||||
|
||||
uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
|
||||
AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(X0);
|
||||
|
||||
RUN_AC_OR_DIE(command, prog, sizeof(prog) / sizeof(*prog), adata, xlen/(4*8));
|
||||
|
||||
uint64_t res = read(DMI_DATA0);//adata[0];
|
||||
if (xlen == 64)
|
||||
res |= read(DMI_DATA0 + 1);//((uint64_t) adata[1]) << 32;
|
||||
|
||||
resume(current_hart);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t dtm_t::chunk_max_size()
|
||||
{
|
||||
// Arbitrary choice. 4k Page size seems reasonable.
|
||||
return 4096;
|
||||
}
|
||||
|
||||
uint32_t dtm_t::get_xlen()
|
||||
{
|
||||
// Attempt to read S0 to find out what size it is.
|
||||
// You could also attempt to run code, but you need to save registers
|
||||
// to do that anyway. If what you really want to do is figure out
|
||||
// the size of S0 so you can save it later, then do that.
|
||||
uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0);
|
||||
uint32_t cmderr;
|
||||
|
||||
const uint32_t prog[] = {};
|
||||
uint32_t data[] = {};
|
||||
|
||||
cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0);
|
||||
if (cmderr == 0){
|
||||
throw std::runtime_error("FESVR DTM Does not support 128-bit");
|
||||
abort();
|
||||
return 128;
|
||||
}
|
||||
write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||
|
||||
cmderr = run_abstract_command(command | AC_AR_SIZE(64), prog, 0, data, 0);
|
||||
if (cmderr == 0){
|
||||
return 64;
|
||||
}
|
||||
write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||
|
||||
cmderr = run_abstract_command(command | AC_AR_SIZE(32), prog, 0, data, 0);
|
||||
if (cmderr == 0){
|
||||
return 32;
|
||||
}
|
||||
|
||||
throw std::runtime_error("FESVR DTM can't determine XLEN. Aborting");
|
||||
}
|
||||
|
||||
void dtm_t::fence_i()
|
||||
{
|
||||
halt(current_hart);
|
||||
|
||||
const uint32_t prog[] = {
|
||||
FENCE_I,
|
||||
EBREAK
|
||||
};
|
||||
|
||||
//TODO: Use the transfer = 0.
|
||||
uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
|
||||
AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE |
|
||||
AC_AR_SIZE(xlen) |
|
||||
AC_AR_REGNO(X0);
|
||||
|
||||
RUN_AC_OR_DIE(command, prog, sizeof(prog)/sizeof(*prog), 0, 0);
|
||||
|
||||
resume(current_hart);
|
||||
|
||||
}
|
||||
|
||||
void host_thread_main(void* arg)
|
||||
{
|
||||
((dtm_t*)arg)->producer_thread();
|
||||
}
|
||||
|
||||
void dtm_t::reset()
|
||||
{
|
||||
for (int hartsel = 0; hartsel < num_harts; hartsel ++ ){
|
||||
select_hart(hartsel);
|
||||
// this command also does a halt and resume
|
||||
fence_i();
|
||||
// after this command, the hart will run from _start.
|
||||
write_csr(0x7b1, get_entry_point());
|
||||
}
|
||||
// In theory any hart can handle the memory accesses,
|
||||
// this will enforce that hart 0 handles them.
|
||||
select_hart(0);
|
||||
read(DMI_DMSTATUS);
|
||||
}
|
||||
|
||||
void dtm_t::idle()
|
||||
{
|
||||
for (int idle_cycles = 0; idle_cycles < max_idle_cycles; idle_cycles++)
|
||||
nop();
|
||||
}
|
||||
|
||||
void dtm_t::producer_thread()
|
||||
{
|
||||
// Learn about the Debug Module and assert things we
|
||||
// depend on in this code.
|
||||
|
||||
// Enable the debugger.
|
||||
write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
|
||||
// Poll until the debugger agrees it's enabled.
|
||||
while ((read(DMI_DMCONTROL) & DMI_DMCONTROL_DMACTIVE) == 0) ;
|
||||
|
||||
// These are checked every time we run an abstract command.
|
||||
uint32_t abstractcs = read(DMI_ABSTRACTCS);
|
||||
ram_words = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE);
|
||||
data_words = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
|
||||
|
||||
// These things are only needed for the 'modify_csr' function.
|
||||
// That could be re-written to not use these at some performance
|
||||
// overhead.
|
||||
uint32_t hartinfo = read(DMI_HARTINFO);
|
||||
assert(get_field(hartinfo, DMI_HARTINFO_NSCRATCH) > 0);
|
||||
assert(get_field(hartinfo, DMI_HARTINFO_DATAACCESS));
|
||||
|
||||
data_base = get_field(hartinfo, DMI_HARTINFO_DATAADDR);
|
||||
|
||||
num_harts = enumerate_harts();
|
||||
halt(0);
|
||||
// Note: We don't support systems with heterogeneous XLEN.
|
||||
// It's possible to do this at the cost of extra cycles.
|
||||
xlen = get_xlen();
|
||||
resume(0);
|
||||
|
||||
running = true;
|
||||
|
||||
htif_t::run();
|
||||
|
||||
while (true)
|
||||
nop();
|
||||
}
|
||||
|
||||
void dtm_t::start_host_thread()
|
||||
{
|
||||
req_wait = false;
|
||||
resp_wait = false;
|
||||
|
||||
target = context_t::current();
|
||||
host.init(host_thread_main, this);
|
||||
host.switch_to();
|
||||
}
|
||||
|
||||
dtm_t::dtm_t(int argc, char** argv)
|
||||
: htif_t(argc, argv), running(false)
|
||||
{
|
||||
start_host_thread();
|
||||
}
|
||||
|
||||
dtm_t::~dtm_t()
|
||||
{
|
||||
}
|
||||
|
||||
void dtm_t::tick(
|
||||
bool req_ready,
|
||||
bool resp_valid,
|
||||
resp resp_bits)
|
||||
{
|
||||
if (!resp_wait) {
|
||||
if (!req_wait) {
|
||||
req_wait = true;
|
||||
} else if (req_ready) {
|
||||
req_wait = false;
|
||||
resp_wait = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (resp_valid) {
|
||||
assert(resp_wait);
|
||||
resp_wait = false;
|
||||
|
||||
resp_buf = resp_bits;
|
||||
// update the target with the current context
|
||||
target = context_t::current();
|
||||
host.switch_to();
|
||||
}
|
||||
}
|
||||
|
||||
void dtm_t::return_resp(resp resp_bits){
|
||||
resp_buf = resp_bits;
|
||||
target = context_t::current();
|
||||
host.switch_to();
|
||||
}
|
115
vendor/riscv-isa-sim/fesvr/dtm.h
vendored
Normal file
115
vendor/riscv-isa-sim/fesvr/dtm.h
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef _ROCKET_DTM_H
|
||||
#define _ROCKET_DTM_H
|
||||
|
||||
#include "htif.h"
|
||||
#include "context.h"
|
||||
#include <stdint.h>
|
||||
#include <queue>
|
||||
#include <semaphore.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
// abstract debug transport module
|
||||
class dtm_t : public htif_t
|
||||
{
|
||||
public:
|
||||
dtm_t(int argc, char**argv);
|
||||
~dtm_t();
|
||||
|
||||
struct req {
|
||||
uint32_t addr;
|
||||
uint32_t op;
|
||||
uint32_t data;
|
||||
};
|
||||
|
||||
struct resp {
|
||||
uint32_t resp;
|
||||
uint32_t data;
|
||||
};
|
||||
|
||||
void tick(
|
||||
bool req_ready,
|
||||
bool resp_valid,
|
||||
resp resp_bits
|
||||
);
|
||||
// Akin to tick, but the target thread returns a response on every invocation
|
||||
void return_resp(
|
||||
resp resp_bits
|
||||
);
|
||||
|
||||
|
||||
bool req_valid() { return req_wait; }
|
||||
req req_bits() { return req_buf; }
|
||||
bool resp_ready() { return true; }
|
||||
|
||||
uint32_t read(uint32_t addr);
|
||||
uint32_t write(uint32_t addr, uint32_t data);
|
||||
void nop();
|
||||
|
||||
uint64_t read_csr(unsigned which);
|
||||
uint64_t write_csr(unsigned which, uint64_t data);
|
||||
uint64_t clear_csr(unsigned which, uint64_t data);
|
||||
uint64_t set_csr(unsigned which, uint64_t data);
|
||||
void fence_i();
|
||||
|
||||
void producer_thread();
|
||||
|
||||
protected:
|
||||
virtual void read_chunk(addr_t taddr, size_t len, void* dst) override;
|
||||
virtual void write_chunk(addr_t taddr, size_t len, const void* src) override;
|
||||
virtual void clear_chunk(addr_t taddr, size_t len) override;
|
||||
virtual size_t chunk_align() override;
|
||||
virtual size_t chunk_max_size() override;
|
||||
virtual void reset() override;
|
||||
virtual void idle() override;
|
||||
|
||||
private:
|
||||
context_t host;
|
||||
context_t* target;
|
||||
pthread_t producer;
|
||||
sem_t req_produce;
|
||||
sem_t req_consume;
|
||||
sem_t resp_produce;
|
||||
sem_t resp_consume;
|
||||
req req_buf;
|
||||
resp resp_buf;
|
||||
bool running;
|
||||
|
||||
uint32_t run_abstract_command(uint32_t command, const uint32_t program[], size_t program_n,
|
||||
uint32_t data[], size_t data_n);
|
||||
|
||||
void die(uint32_t cmderr);
|
||||
void halt(int);
|
||||
int enumerate_harts();
|
||||
void select_hart(int);
|
||||
void resume(int);
|
||||
uint64_t save_reg(unsigned regno);
|
||||
void restore_reg(unsigned regno, uint64_t val);
|
||||
|
||||
uint64_t modify_csr(unsigned which, uint64_t data, uint32_t type);
|
||||
|
||||
bool req_wait;
|
||||
bool resp_wait;
|
||||
uint32_t data_base;
|
||||
|
||||
uint32_t xlen;
|
||||
|
||||
static const int max_idle_cycles = 10000;
|
||||
|
||||
size_t ram_words;
|
||||
size_t data_words;
|
||||
int num_harts;
|
||||
int current_hart;
|
||||
|
||||
uint32_t get_xlen();
|
||||
uint32_t do_command(dtm_t::req r);
|
||||
|
||||
void parse_args(const std::vector<std::string>& args);
|
||||
void register_devices();
|
||||
void start_host_thread();
|
||||
|
||||
friend class memif_t;
|
||||
};
|
||||
|
||||
#endif
|
4
vendor/riscv-isa-sim/fesvr/dummy.cc
vendored
Normal file
4
vendor/riscv-isa-sim/fesvr/dummy.cc
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
// help out poor, C-centric autoconf
|
||||
extern "C" void libfesvr_is_present() {}
|
134
vendor/riscv-isa-sim/fesvr/elf.h
vendored
Normal file
134
vendor/riscv-isa-sim/fesvr/elf.h
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
// See LICENSE for details.
|
||||
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ET_EXEC 2
|
||||
#define EM_RISCV 243
|
||||
#define EM_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
#define IS_ELF(hdr) \
|
||||
((hdr).e_ident[0] == 0x7f && (hdr).e_ident[1] == 'E' && \
|
||||
(hdr).e_ident[2] == 'L' && (hdr).e_ident[3] == 'F')
|
||||
|
||||
#define ELF_SWAP(hdr, val) (IS_ELFLE(hdr)? from_le((val)) : from_be((val)))
|
||||
|
||||
#define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1)
|
||||
#define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2)
|
||||
#define IS_ELFLE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 1)
|
||||
#define IS_ELFBE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 2)
|
||||
#define IS_ELF_EXEC(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_type) == ET_EXEC)
|
||||
#define IS_ELF_RISCV(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_machine) == EM_RISCV)
|
||||
#define IS_ELF_EM_NONE(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_machine) == EM_NONE)
|
||||
#define IS_ELF_VCURRENT(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_version) == EV_CURRENT)
|
||||
|
||||
#define PT_LOAD 1
|
||||
|
||||
#define SHT_NOBITS 8
|
||||
|
||||
typedef struct {
|
||||
uint8_t e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint32_t sh_flags;
|
||||
uint32_t sh_addr;
|
||||
uint32_t sh_offset;
|
||||
uint32_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint32_t sh_addralign;
|
||||
uint32_t sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t st_name;
|
||||
uint32_t st_value;
|
||||
uint32_t st_size;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
} Elf32_Sym;
|
||||
|
||||
typedef struct {
|
||||
uint8_t e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint64_t e_entry;
|
||||
uint64_t e_phoff;
|
||||
uint64_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint64_t sh_flags;
|
||||
uint64_t sh_addr;
|
||||
uint64_t sh_offset;
|
||||
uint64_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint64_t sh_addralign;
|
||||
uint64_t sh_entsize;
|
||||
} Elf64_Shdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_flags;
|
||||
uint64_t p_offset;
|
||||
uint64_t p_vaddr;
|
||||
uint64_t p_paddr;
|
||||
uint64_t p_filesz;
|
||||
uint64_t p_memsz;
|
||||
uint64_t p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t st_name;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
uint64_t st_value;
|
||||
uint64_t st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
#endif
|
47
vendor/riscv-isa-sim/fesvr/elf2hex.cc
vendored
Normal file
47
vendor/riscv-isa-sim/fesvr/elf2hex.cc
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include <iostream>
|
||||
#include "htif_hexwriter.h"
|
||||
#include "memif.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc < 4 || argc > 5)
|
||||
{
|
||||
std::cerr << "Usage: " << argv[0] << " <width> <depth> <elf_file> [base]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned width = atoi(argv[1]);
|
||||
if(width == 0 || (width & (width-1)))
|
||||
{
|
||||
std::cerr << "width must be a power of 2" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned long long int base = 0;
|
||||
if(argc==5) {
|
||||
base = atoll(argv[4]);
|
||||
if(base & (width-1))
|
||||
{
|
||||
std::cerr << "base must be divisible by width" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned depth = atoi(argv[2]);
|
||||
if(depth == 0 || (depth & (depth-1)))
|
||||
{
|
||||
std::cerr << "depth must be a power of 2" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
htif_hexwriter_t htif(base, width, depth);
|
||||
memif_t memif(&htif);
|
||||
reg_t entry;
|
||||
load_elf(argv[3], &memif, &entry);
|
||||
std::cout << htif;
|
||||
|
||||
return 0;
|
||||
}
|
117
vendor/riscv-isa-sim/fesvr/elfloader.cc
vendored
Normal file
117
vendor/riscv-isa-sim/fesvr/elfloader.cc
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "elf.h"
|
||||
#include "memif.h"
|
||||
#include "byteorder.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry)
|
||||
{
|
||||
int fd = open(fn, O_RDONLY);
|
||||
struct stat s;
|
||||
assert(fd != -1);
|
||||
if (fstat(fd, &s) < 0)
|
||||
abort();
|
||||
size_t size = s.st_size;
|
||||
|
||||
char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
assert(buf != MAP_FAILED);
|
||||
close(fd);
|
||||
|
||||
assert(size >= sizeof(Elf64_Ehdr));
|
||||
const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf;
|
||||
assert(IS_ELF32(*eh64) || IS_ELF64(*eh64));
|
||||
assert(IS_ELFLE(*eh64) || IS_ELFBE(*eh64));
|
||||
assert(IS_ELF_EXEC(*eh64));
|
||||
assert(IS_ELF_RISCV(*eh64) || IS_ELF_EM_NONE(*eh64));
|
||||
assert(IS_ELF_VCURRENT(*eh64));
|
||||
|
||||
std::vector<uint8_t> zeros;
|
||||
std::map<std::string, uint64_t> symbols;
|
||||
|
||||
#define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t, bswap) \
|
||||
do { \
|
||||
ehdr_t* eh = (ehdr_t*)buf; \
|
||||
phdr_t* ph = (phdr_t*)(buf + bswap(eh->e_phoff)); \
|
||||
*entry = bswap(eh->e_entry); \
|
||||
assert(size >= bswap(eh->e_phoff) + bswap(eh->e_phnum) * sizeof(*ph)); \
|
||||
for (unsigned i = 0; i < bswap(eh->e_phnum); i++) { \
|
||||
if (bswap(ph[i].p_type) == PT_LOAD && bswap(ph[i].p_memsz)) { \
|
||||
if (bswap(ph[i].p_filesz)) { \
|
||||
assert(size >= bswap(ph[i].p_offset) + bswap(ph[i].p_filesz)); \
|
||||
memif->write(bswap(ph[i].p_paddr), bswap(ph[i].p_filesz), \
|
||||
(uint8_t*)buf + bswap(ph[i].p_offset)); \
|
||||
} \
|
||||
if (size_t pad = bswap(ph[i].p_memsz) - bswap(ph[i].p_filesz)) { \
|
||||
zeros.resize(pad); \
|
||||
memif->write(bswap(ph[i].p_paddr) + bswap(ph[i].p_filesz), pad, \
|
||||
zeros.data()); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
shdr_t* sh = (shdr_t*)(buf + bswap(eh->e_shoff)); \
|
||||
assert(size >= bswap(eh->e_shoff) + bswap(eh->e_shnum) * sizeof(*sh)); \
|
||||
assert(bswap(eh->e_shstrndx) < bswap(eh->e_shnum)); \
|
||||
assert(size >= bswap(sh[bswap(eh->e_shstrndx)].sh_offset) + \
|
||||
bswap(sh[bswap(eh->e_shstrndx)].sh_size)); \
|
||||
char* shstrtab = buf + bswap(sh[bswap(eh->e_shstrndx)].sh_offset); \
|
||||
unsigned strtabidx = 0, symtabidx = 0; \
|
||||
for (unsigned i = 0; i < bswap(eh->e_shnum); i++) { \
|
||||
unsigned max_len = \
|
||||
bswap(sh[bswap(eh->e_shstrndx)].sh_size) - bswap(sh[i].sh_name); \
|
||||
assert(bswap(sh[i].sh_name) < bswap(sh[bswap(eh->e_shstrndx)].sh_size)); \
|
||||
assert(strnlen(shstrtab + bswap(sh[i].sh_name), max_len) < max_len); \
|
||||
if (bswap(sh[i].sh_type) & SHT_NOBITS) continue; \
|
||||
assert(size >= bswap(sh[i].sh_offset) + bswap(sh[i].sh_size)); \
|
||||
if (strcmp(shstrtab + bswap(sh[i].sh_name), ".strtab") == 0) \
|
||||
strtabidx = i; \
|
||||
if (strcmp(shstrtab + bswap(sh[i].sh_name), ".symtab") == 0) \
|
||||
symtabidx = i; \
|
||||
} \
|
||||
if (strtabidx && symtabidx) { \
|
||||
char* strtab = buf + bswap(sh[strtabidx].sh_offset); \
|
||||
sym_t* sym = (sym_t*)(buf + bswap(sh[symtabidx].sh_offset)); \
|
||||
for (unsigned i = 0; i < bswap(sh[symtabidx].sh_size) / sizeof(sym_t); \
|
||||
i++) { \
|
||||
unsigned max_len = \
|
||||
bswap(sh[strtabidx].sh_size) - bswap(sym[i].st_name); \
|
||||
assert(bswap(sym[i].st_name) < bswap(sh[strtabidx].sh_size)); \
|
||||
assert(strnlen(strtab + bswap(sym[i].st_name), max_len) < max_len); \
|
||||
symbols[strtab + bswap(sym[i].st_name)] = bswap(sym[i].st_value); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (IS_ELFLE(*eh64)) {
|
||||
memif->set_target_endianness(memif_endianness_little);
|
||||
if (IS_ELF32(*eh64))
|
||||
LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_le);
|
||||
else
|
||||
LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_le);
|
||||
} else {
|
||||
#ifndef RISCV_ENABLE_DUAL_ENDIAN
|
||||
throw std::invalid_argument("Specified ELF is big endian. Configure with --enable-dual-endian to enable support");
|
||||
#else
|
||||
memif->set_target_endianness(memif_endianness_big);
|
||||
if (IS_ELF32(*eh64))
|
||||
LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_be);
|
||||
else
|
||||
LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_be);
|
||||
#endif
|
||||
}
|
||||
|
||||
munmap(buf, size);
|
||||
|
||||
return symbols;
|
||||
}
|
13
vendor/riscv-isa-sim/fesvr/elfloader.h
vendored
Normal file
13
vendor/riscv-isa-sim/fesvr/elfloader.h
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef _ELFLOADER_H
|
||||
#define _ELFLOADER_H
|
||||
|
||||
#include "elf.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class memif_t;
|
||||
std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry);
|
||||
|
||||
#endif
|
11
vendor/riscv-isa-sim/fesvr/fesvr.ac
vendored
Normal file
11
vendor/riscv-isa-sim/fesvr/fesvr.ac
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
AC_CHECK_LIB(pthread, pthread_create, [], [AC_MSG_ERROR([libpthread is required])])
|
||||
|
||||
AC_CHECK_MEMBER(struct statx.stx_ino,
|
||||
AC_DEFINE_UNQUOTED(HAVE_STATX, 1, [Define to 1 if struct statx exists.]),
|
||||
,
|
||||
)
|
||||
|
||||
AC_CHECK_MEMBER(struct statx.stx_mnt_id,
|
||||
AC_DEFINE_UNQUOTED(HAVE_STATX_MNT_ID, 1, [Define to 1 if struct statx has stx_mnt_id.]),
|
||||
,
|
||||
)
|
41
vendor/riscv-isa-sim/fesvr/fesvr.mk.in
vendored
Normal file
41
vendor/riscv-isa-sim/fesvr/fesvr.mk.in
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
fesvr_hdrs = \
|
||||
byteorder.h \
|
||||
elf.h \
|
||||
elfloader.h \
|
||||
htif.h \
|
||||
dtm.h \
|
||||
memif.h \
|
||||
syscall.h \
|
||||
context.h \
|
||||
htif_pthread.h \
|
||||
htif_hexwriter.h \
|
||||
option_parser.h \
|
||||
term.h \
|
||||
device.h \
|
||||
rfb.h \
|
||||
tsi.h \
|
||||
|
||||
fesvr_install_hdrs = $(fesvr_hdrs)
|
||||
|
||||
fesvr_install_config_hdr = yes
|
||||
|
||||
fesvr_install_lib = yes
|
||||
|
||||
fesvr_srcs = \
|
||||
elfloader.cc \
|
||||
htif.cc \
|
||||
memif.cc \
|
||||
dtm.cc \
|
||||
syscall.cc \
|
||||
device.cc \
|
||||
rfb.cc \
|
||||
context.cc \
|
||||
htif_pthread.cc \
|
||||
htif_hexwriter.cc \
|
||||
dummy.cc \
|
||||
option_parser.cc \
|
||||
term.cc \
|
||||
tsi.cc \
|
||||
|
||||
fesvr_install_prog_srcs = \
|
||||
elf2hex.cc \
|
26
vendor/riscv-isa-sim/fesvr/fesvr.pc.in
vendored
Normal file
26
vendor/riscv-isa-sim/fesvr/fesvr.pc.in
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
#=========================================================================
|
||||
# Modular C++ Build System Subproject Package Config
|
||||
#=========================================================================
|
||||
# Please read the documenation in 'mcppbs-uguide.txt' for more details
|
||||
# on how the Modular C++ Build System works.
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Generic variables
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
prefix=@prefix@
|
||||
include_dir=${prefix}/include/fesvr
|
||||
lib_dir=${prefix}/lib
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Keywords
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
Name : fesvr
|
||||
Version : @PACKAGE_VERSION@
|
||||
Description : Frontend Server C/C++ API
|
||||
Requires : @fesvr_pkcdeps@
|
||||
Cflags : -I${include_dir} @CPPFLAGS@ @fesvr_extra_cppflags@
|
||||
Libs : -L${lib_dir} @LDFLAGS@ @fesvr_extra_ldflags@ \
|
||||
-lfesvr @fesvr_extra_libs@
|
||||
|
415
vendor/riscv-isa-sim/fesvr/htif.cc
vendored
Normal file
415
vendor/riscv-isa-sim/fesvr/htif.cc
vendored
Normal file
|
@ -0,0 +1,415 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "htif.h"
|
||||
#include "rfb.h"
|
||||
#include "elfloader.h"
|
||||
#include "platform.h"
|
||||
#include "byteorder.h"
|
||||
#include "trap.h"
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
|
||||
/* Attempt to determine the execution prefix automatically. autoconf
|
||||
* sets PREFIX, and pconfigure sets __PCONFIGURE__PREFIX. */
|
||||
#if !defined(PREFIX) && defined(__PCONFIGURE__PREFIX)
|
||||
# define PREFIX __PCONFIGURE__PREFIX
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_ARCH
|
||||
# define TARGET_ARCH "riscv64-unknown-elf"
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_DIR
|
||||
# define TARGET_DIR "/" TARGET_ARCH "/bin/"
|
||||
#endif
|
||||
|
||||
static volatile bool signal_exit = false;
|
||||
static void handle_signal(int sig)
|
||||
{
|
||||
if (sig == SIGABRT || signal_exit) // someone set up us the bomb!
|
||||
exit(-1);
|
||||
signal_exit = true;
|
||||
signal(sig, &handle_signal);
|
||||
}
|
||||
|
||||
htif_t::htif_t()
|
||||
: mem(this), entry(DRAM_BASE), sig_addr(0), sig_len(0),
|
||||
tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false),
|
||||
syscall_proxy(this)
|
||||
{
|
||||
signal(SIGINT, &handle_signal);
|
||||
signal(SIGTERM, &handle_signal);
|
||||
signal(SIGABRT, &handle_signal); // we still want to call static destructors
|
||||
}
|
||||
|
||||
htif_t::htif_t(int argc, char** argv) : htif_t()
|
||||
{
|
||||
//Set line size as 16 by default.
|
||||
line_size = 16;
|
||||
parse_arguments(argc, argv);
|
||||
register_devices();
|
||||
}
|
||||
|
||||
htif_t::htif_t(const std::vector<std::string>& args) : htif_t()
|
||||
{
|
||||
int argc = args.size() + 1;
|
||||
char * argv[argc];
|
||||
argv[0] = (char *) "htif";
|
||||
for (unsigned int i = 0; i < args.size(); i++) {
|
||||
argv[i+1] = (char *) args[i].c_str();
|
||||
}
|
||||
//Set line size as 16 by default.
|
||||
line_size = 16;
|
||||
parse_arguments(argc, argv);
|
||||
register_devices();
|
||||
}
|
||||
|
||||
htif_t::~htif_t()
|
||||
{
|
||||
for (auto d : dynamic_devices)
|
||||
delete d;
|
||||
}
|
||||
|
||||
void htif_t::start()
|
||||
{
|
||||
if (!targs.empty() && targs[0] != "none")
|
||||
load_program();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
static void bad_address(const std::string& situation, reg_t addr)
|
||||
{
|
||||
std::cerr << "Access exception occurred while " << situation << ":\n";
|
||||
std::cerr << "Memory address 0x" << std::hex << addr << " is invalid\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
std::map<std::string, uint64_t> htif_t::load_payload(const std::string& payload, reg_t* entry)
|
||||
{
|
||||
std::string path;
|
||||
if (access(payload.c_str(), F_OK) == 0)
|
||||
path = payload;
|
||||
else if (payload.find('/') == std::string::npos)
|
||||
{
|
||||
std::string test_path = PREFIX TARGET_DIR + payload;
|
||||
if (access(test_path.c_str(), F_OK) == 0)
|
||||
path = test_path;
|
||||
}
|
||||
|
||||
if (path.empty())
|
||||
throw std::runtime_error(
|
||||
"could not open " + payload +
|
||||
" (did you misspell it? If VCS, did you forget +permissive/+permissive-off?)");
|
||||
|
||||
// temporarily construct a memory interface that skips writing bytes
|
||||
// that have already been preloaded through a sideband
|
||||
class preload_aware_memif_t : public memif_t {
|
||||
public:
|
||||
preload_aware_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {}
|
||||
|
||||
void write(addr_t taddr, size_t len, const void* src) override
|
||||
{
|
||||
if (!htif->is_address_preloaded(taddr, len))
|
||||
memif_t::write(taddr, len, src);
|
||||
}
|
||||
|
||||
private:
|
||||
htif_t* htif;
|
||||
} preload_aware_memif(this);
|
||||
|
||||
try {
|
||||
return load_elf(path.c_str(), &preload_aware_memif, entry);
|
||||
} catch (mem_trap_t& t) {
|
||||
bad_address("loading payload " + payload, t.get_tval());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void htif_t::load_program()
|
||||
{
|
||||
std::map<std::string, uint64_t> symbols = load_payload(targs[0], &entry);
|
||||
|
||||
if (symbols.count("tohost") && symbols.count("fromhost")) {
|
||||
tohost_addr = symbols["tohost"];
|
||||
fromhost_addr = symbols["fromhost"];
|
||||
} else {
|
||||
fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n");
|
||||
}
|
||||
|
||||
// detect torture tests so we can print the memory signature at the end
|
||||
if (symbols.count("begin_signature") && symbols.count("end_signature"))
|
||||
{
|
||||
sig_addr = symbols["begin_signature"];
|
||||
sig_len = symbols["end_signature"] - sig_addr;
|
||||
}
|
||||
|
||||
for (auto payload : payloads)
|
||||
{
|
||||
reg_t dummy_entry;
|
||||
load_payload(payload, &dummy_entry);
|
||||
}
|
||||
|
||||
for (auto i : symbols)
|
||||
{
|
||||
auto it = addr2symbol.find(i.second);
|
||||
if ( it == addr2symbol.end())
|
||||
addr2symbol[i.second] = i.first;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char* htif_t::get_symbol(uint64_t addr)
|
||||
{
|
||||
auto it = addr2symbol.find(addr);
|
||||
|
||||
if(it == addr2symbol.end())
|
||||
return nullptr;
|
||||
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
void htif_t::stop()
|
||||
{
|
||||
if (!sig_file.empty() && sig_len) // print final torture test signature
|
||||
{
|
||||
std::vector<uint8_t> buf(sig_len);
|
||||
mem.read(sig_addr, sig_len, buf.data());
|
||||
|
||||
std::ofstream sigs(sig_file);
|
||||
assert(sigs && "can't open signature file!");
|
||||
sigs << std::setfill('0') << std::hex;
|
||||
|
||||
for (addr_t i = 0; i < sig_len; i += line_size)
|
||||
{
|
||||
for (addr_t j = line_size; j > 0; j--)
|
||||
if (i+j <= sig_len)
|
||||
sigs << std::setw(2) << (uint16_t)buf[i+j-1];
|
||||
else
|
||||
sigs << std::setw(2) << (uint16_t)0;
|
||||
sigs << '\n';
|
||||
}
|
||||
|
||||
sigs.close();
|
||||
}
|
||||
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
void htif_t::clear_chunk(addr_t taddr, size_t len)
|
||||
{
|
||||
char zeros[chunk_max_size()];
|
||||
memset(zeros, 0, chunk_max_size());
|
||||
|
||||
for (size_t pos = 0; pos < len; pos += chunk_max_size())
|
||||
write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), zeros);
|
||||
}
|
||||
|
||||
int htif_t::run()
|
||||
{
|
||||
start();
|
||||
|
||||
auto enq_func = [](std::queue<reg_t>* q, uint64_t x) { q->push(x); };
|
||||
std::queue<reg_t> fromhost_queue;
|
||||
std::function<void(reg_t)> fromhost_callback =
|
||||
std::bind(enq_func, &fromhost_queue, std::placeholders::_1);
|
||||
|
||||
if (tohost_addr == 0) {
|
||||
while (true)
|
||||
idle();
|
||||
}
|
||||
|
||||
while (!signal_exit && exitcode == 0)
|
||||
{
|
||||
uint64_t tohost;
|
||||
|
||||
try {
|
||||
if ((tohost = from_target(mem.read_uint64(tohost_addr))) != 0)
|
||||
mem.write_uint64(tohost_addr, target_endian<uint64_t>::zero);
|
||||
} catch (mem_trap_t& t) {
|
||||
bad_address("accessing tohost", t.get_tval());
|
||||
}
|
||||
|
||||
try {
|
||||
if (tohost != 0) {
|
||||
command_t cmd(mem, tohost, fromhost_callback);
|
||||
device_list.handle_command(cmd);
|
||||
} else {
|
||||
idle();
|
||||
}
|
||||
|
||||
device_list.tick();
|
||||
} catch (mem_trap_t& t) {
|
||||
std::stringstream tohost_hex;
|
||||
tohost_hex << std::hex << tohost;
|
||||
bad_address("host was accessing memory on behalf of target (tohost = 0x" + tohost_hex.str() + ")", t.get_tval());
|
||||
}
|
||||
|
||||
try {
|
||||
if (!fromhost_queue.empty() && !mem.read_uint64(fromhost_addr)) {
|
||||
mem.write_uint64(fromhost_addr, to_target(fromhost_queue.front()));
|
||||
fromhost_queue.pop();
|
||||
}
|
||||
} catch (mem_trap_t& t) {
|
||||
bad_address("accessing fromhost", t.get_tval());
|
||||
}
|
||||
}
|
||||
|
||||
stop();
|
||||
|
||||
return exit_code();
|
||||
}
|
||||
|
||||
bool htif_t::done()
|
||||
{
|
||||
return stopped;
|
||||
}
|
||||
|
||||
int htif_t::exit_code()
|
||||
{
|
||||
return exitcode >> 1;
|
||||
}
|
||||
|
||||
void htif_t::parse_arguments(int argc, char ** argv)
|
||||
{
|
||||
optind = 0; // reset optind as HTIF may run getopt _after_ others
|
||||
while (1) {
|
||||
static struct option long_options[] = { HTIF_LONG_OPTIONS };
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "-h", long_options, &option_index);
|
||||
|
||||
if (c == -1) break;
|
||||
retry:
|
||||
switch (c) {
|
||||
case 'h': usage(argv[0]);
|
||||
throw std::invalid_argument("User queried htif_t help text");
|
||||
case HTIF_LONG_OPTIONS_OPTIND:
|
||||
if (optarg) dynamic_devices.push_back(new rfb_t(atoi(optarg)));
|
||||
else dynamic_devices.push_back(new rfb_t);
|
||||
break;
|
||||
case HTIF_LONG_OPTIONS_OPTIND + 1:
|
||||
// [TODO] Remove once disks are supported again
|
||||
throw std::invalid_argument("--disk/+disk unsupported (use a ramdisk)");
|
||||
dynamic_devices.push_back(new disk_t(optarg));
|
||||
break;
|
||||
case HTIF_LONG_OPTIONS_OPTIND + 2:
|
||||
sig_file = optarg;
|
||||
break;
|
||||
case HTIF_LONG_OPTIONS_OPTIND + 3:
|
||||
syscall_proxy.set_chroot(optarg);
|
||||
break;
|
||||
case HTIF_LONG_OPTIONS_OPTIND + 4:
|
||||
payloads.push_back(optarg);
|
||||
break;
|
||||
case HTIF_LONG_OPTIONS_OPTIND + 5:
|
||||
line_size = atoi(optarg);
|
||||
|
||||
break;
|
||||
case '?':
|
||||
if (!opterr)
|
||||
break;
|
||||
throw std::invalid_argument("Unknown argument (did you mean to enable +permissive parsing?)");
|
||||
case 1: {
|
||||
std::string arg = optarg;
|
||||
if (arg == "+h" || arg == "+help") {
|
||||
c = 'h';
|
||||
optarg = nullptr;
|
||||
}
|
||||
else if (arg == "+rfb") {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND;
|
||||
optarg = nullptr;
|
||||
}
|
||||
else if (arg.find("+rfb=") == 0) {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND;
|
||||
optarg = optarg + 5;
|
||||
}
|
||||
else if (arg.find("+disk=") == 0) {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND + 1;
|
||||
optarg = optarg + 6;
|
||||
}
|
||||
else if (arg.find("+signature=") == 0) {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND + 2;
|
||||
optarg = optarg + 11;
|
||||
}
|
||||
else if (arg.find("+chroot=") == 0) {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND + 3;
|
||||
optarg = optarg + 8;
|
||||
}
|
||||
else if (arg.find("+payload=") == 0) {
|
||||
c = HTIF_LONG_OPTIONS_OPTIND + 4;
|
||||
optarg = optarg + 9;
|
||||
}
|
||||
else if(arg.find("+signature-granularity=")==0){
|
||||
c = HTIF_LONG_OPTIONS_OPTIND + 5;
|
||||
optarg = optarg + 23;
|
||||
}
|
||||
else if (arg.find("+permissive-off") == 0) {
|
||||
if (opterr)
|
||||
throw std::invalid_argument("Found +permissive-off when not parsing permissively");
|
||||
opterr = 1;
|
||||
break;
|
||||
}
|
||||
else if (arg.find("+permissive") == 0) {
|
||||
if (!opterr)
|
||||
throw std::invalid_argument("Found +permissive when already parsing permissively");
|
||||
opterr = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (!opterr)
|
||||
break;
|
||||
else {
|
||||
optind--;
|
||||
goto done_processing;
|
||||
}
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done_processing:
|
||||
while (optind < argc)
|
||||
targs.push_back(argv[optind++]);
|
||||
if (!targs.size()) {
|
||||
usage(argv[0]);
|
||||
throw std::invalid_argument("No binary specified (Did you forget it? Did you forget '+permissive-off' if running with +permissive?)");
|
||||
}
|
||||
}
|
||||
|
||||
void htif_t::register_devices()
|
||||
{
|
||||
device_list.register_device(&syscall_proxy);
|
||||
device_list.register_device(&bcd);
|
||||
for (auto d : dynamic_devices)
|
||||
device_list.register_device(d);
|
||||
}
|
||||
|
||||
void htif_t::usage(const char * program_name)
|
||||
{
|
||||
printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n ",
|
||||
program_name);
|
||||
fputs("\
|
||||
Run a BINARY on the Rocket Chip emulator.\n\
|
||||
\n\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
\n\
|
||||
EMULATOR OPTIONS\n\
|
||||
Consult emulator.cc if using Verilator or VCS documentation if using VCS\n\
|
||||
for available options.\n\
|
||||
EMUALTOR VERILOG PLUSARGS\n\
|
||||
Consult generated-src*/*.plusArgs for available options\n\
|
||||
", stdout);
|
||||
fputs("\n" HTIF_USAGE_OPTIONS, stdout);
|
||||
}
|
156
vendor/riscv-isa-sim/fesvr/htif.h
vendored
Normal file
156
vendor/riscv-isa-sim/fesvr/htif.h
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef __HTIF_H
|
||||
#define __HTIF_H
|
||||
|
||||
#include "memif.h"
|
||||
#include "syscall.h"
|
||||
#include "device.h"
|
||||
#include "byteorder.h"
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
|
||||
class htif_t : public chunked_memif_t
|
||||
{
|
||||
public:
|
||||
htif_t();
|
||||
htif_t(int argc, char** argv);
|
||||
htif_t(const std::vector<std::string>& args);
|
||||
virtual ~htif_t();
|
||||
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
|
||||
int run();
|
||||
bool done();
|
||||
int exit_code();
|
||||
|
||||
virtual memif_t& memif() { return mem; }
|
||||
|
||||
template<typename T> inline T from_target(target_endian<T> n) const
|
||||
{
|
||||
#ifdef RISCV_ENABLE_DUAL_ENDIAN
|
||||
memif_endianness_t endianness = get_target_endianness();
|
||||
assert(endianness == memif_endianness_little || endianness == memif_endianness_big);
|
||||
|
||||
return endianness == memif_endianness_big? n.from_be() : n.from_le();
|
||||
#else
|
||||
return n.from_le();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> inline target_endian<T> to_target(T n) const
|
||||
{
|
||||
#ifdef RISCV_ENABLE_DUAL_ENDIAN
|
||||
memif_endianness_t endianness = get_target_endianness();
|
||||
assert(endianness == memif_endianness_little || endianness == memif_endianness_big);
|
||||
|
||||
return endianness == memif_endianness_big? target_endian<T>::to_be(n) : target_endian<T>::to_le(n);
|
||||
#else
|
||||
return target_endian<T>::to_le(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void reset() = 0;
|
||||
|
||||
virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0;
|
||||
virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0;
|
||||
virtual void clear_chunk(addr_t taddr, size_t len);
|
||||
|
||||
virtual size_t chunk_align() = 0;
|
||||
virtual size_t chunk_max_size() = 0;
|
||||
|
||||
virtual std::map<std::string, uint64_t> load_payload(const std::string& payload, reg_t* entry);
|
||||
virtual void load_program();
|
||||
virtual void idle() {}
|
||||
|
||||
const std::vector<std::string>& host_args() { return hargs; }
|
||||
|
||||
reg_t get_entry_point() { return entry; }
|
||||
|
||||
// indicates that the initial program load can skip writing this address
|
||||
// range to memory, because it has already been loaded through a sideband
|
||||
virtual bool is_address_preloaded(addr_t taddr, size_t len) { return false; }
|
||||
|
||||
// Given an address, return symbol from addr2symbol map
|
||||
const char* get_symbol(uint64_t addr);
|
||||
|
||||
private:
|
||||
void parse_arguments(int argc, char ** argv);
|
||||
void register_devices();
|
||||
void usage(const char * program_name);
|
||||
|
||||
memif_t mem;
|
||||
reg_t entry;
|
||||
bool writezeros;
|
||||
std::vector<std::string> hargs;
|
||||
std::vector<std::string> targs;
|
||||
std::string sig_file;
|
||||
unsigned int line_size;
|
||||
addr_t sig_addr; // torture
|
||||
addr_t sig_len; // torture
|
||||
addr_t tohost_addr;
|
||||
addr_t fromhost_addr;
|
||||
int exitcode;
|
||||
bool stopped;
|
||||
|
||||
device_list_t device_list;
|
||||
syscall_t syscall_proxy;
|
||||
bcd_t bcd;
|
||||
std::vector<device_t*> dynamic_devices;
|
||||
std::vector<std::string> payloads;
|
||||
|
||||
const std::vector<std::string>& target_args() { return targs; }
|
||||
|
||||
std::map<uint64_t, std::string> addr2symbol;
|
||||
|
||||
friend class memif_t;
|
||||
friend class syscall_t;
|
||||
};
|
||||
|
||||
/* Alignment guide for emulator.cc options:
|
||||
-x, --long-option Description with max 80 characters --------------->\n\
|
||||
+plus-arg-equivalent\n\
|
||||
*/
|
||||
#define HTIF_USAGE_OPTIONS \
|
||||
"HOST OPTIONS\n\
|
||||
-h, --help Display this help and exit\n\
|
||||
+h, +help\n\
|
||||
+permissive The host will ignore any unparsed options up until\n\
|
||||
+permissive-off (Only needed for VCS)\n\
|
||||
+permissive-off Stop ignoring options. This is mandatory if using\n\
|
||||
+permissive (Only needed for VCS)\n\
|
||||
--rfb=DISPLAY Add new remote frame buffer on display DISPLAY\n\
|
||||
+rfb=DISPLAY to be accessible on 5900 + DISPLAY (default = 0)\n\
|
||||
--signature=FILE Write torture test signature to FILE\n\
|
||||
+signature=FILE\n\
|
||||
--signature-granularity=VAL Size of each line in signature.\n\
|
||||
+signature-granularity=VAL\n\
|
||||
--chroot=PATH Use PATH as location of syscall-servicing binaries\n\
|
||||
+chroot=PATH\n\
|
||||
--payload=PATH Load PATH memory as an additional ELF payload\n\
|
||||
+payload=PATH\n\
|
||||
\n\
|
||||
HOST OPTIONS (currently unsupported)\n\
|
||||
--disk=DISK Add DISK device. Use a ramdisk since this isn't\n\
|
||||
+disk=DISK supported\n\
|
||||
\n\
|
||||
TARGET (RISC-V BINARY) OPTIONS\n\
|
||||
These are the options passed to the program executing on the emulated RISC-V\n\
|
||||
microprocessor.\n"
|
||||
|
||||
#define HTIF_LONG_OPTIONS_OPTIND 1024
|
||||
#define HTIF_LONG_OPTIONS \
|
||||
{"help", no_argument, 0, 'h' }, \
|
||||
{"rfb", optional_argument, 0, HTIF_LONG_OPTIONS_OPTIND }, \
|
||||
{"disk", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 1 }, \
|
||||
{"signature", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 2 }, \
|
||||
{"chroot", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 3 }, \
|
||||
{"payload", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 4 }, \
|
||||
{"signature-granularity", optional_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 5 }, \
|
||||
{0, 0, 0, 0}
|
||||
|
||||
#endif // __HTIF_H
|
76
vendor/riscv-isa-sim/fesvr/htif_hexwriter.cc
vendored
Normal file
76
vendor/riscv-isa-sim/fesvr/htif_hexwriter.cc
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include "htif_hexwriter.h"
|
||||
|
||||
htif_hexwriter_t::htif_hexwriter_t(size_t b, size_t w, size_t d)
|
||||
: base(b), width(w), depth(d)
|
||||
{
|
||||
}
|
||||
|
||||
void htif_hexwriter_t::read_chunk(addr_t taddr, size_t len, void* vdst)
|
||||
{
|
||||
taddr -= base;
|
||||
|
||||
assert(len % chunk_align() == 0);
|
||||
assert(taddr < width*depth);
|
||||
assert(taddr+len <= width*depth);
|
||||
|
||||
uint8_t* dst = (uint8_t*)vdst;
|
||||
while(len)
|
||||
{
|
||||
if(mem[taddr/width].size() == 0)
|
||||
mem[taddr/width].resize(width,0);
|
||||
|
||||
for(size_t j = 0; j < width; j++)
|
||||
dst[j] = mem[taddr/width][j];
|
||||
|
||||
len -= width;
|
||||
taddr += width;
|
||||
dst += width;
|
||||
}
|
||||
}
|
||||
|
||||
void htif_hexwriter_t::write_chunk(addr_t taddr, size_t len, const void* vsrc)
|
||||
{
|
||||
taddr -= base;
|
||||
|
||||
assert(len % chunk_align() == 0);
|
||||
assert(taddr < width*depth);
|
||||
assert(taddr+len <= width*depth);
|
||||
|
||||
const uint8_t* src = (const uint8_t*)vsrc;
|
||||
while(len)
|
||||
{
|
||||
if(mem[taddr/width].size() == 0)
|
||||
mem[taddr/width].resize(width,0);
|
||||
|
||||
for(size_t j = 0; j < width; j++)
|
||||
mem[taddr/width][j] = src[j];
|
||||
|
||||
len -= width;
|
||||
taddr += width;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& o, const htif_hexwriter_t& h)
|
||||
{
|
||||
std::ios_base::fmtflags flags = o.setf(std::ios::hex,std::ios::basefield);
|
||||
|
||||
for(size_t addr = 0; addr < h.depth; addr++)
|
||||
{
|
||||
std::map<addr_t,std::vector<char> >::const_iterator i = h.mem.find(addr);
|
||||
if(i == h.mem.end())
|
||||
for(size_t j = 0; j < h.width; j++)
|
||||
o << "00";
|
||||
else
|
||||
for(size_t j = 0; j < h.width; j++)
|
||||
o << ((i->second[h.width-j-1] >> 4) & 0xF) << (i->second[h.width-j-1] & 0xF);
|
||||
o << std::endl;
|
||||
}
|
||||
|
||||
o.setf(flags);
|
||||
|
||||
return o;
|
||||
}
|
32
vendor/riscv-isa-sim/fesvr/htif_hexwriter.h
vendored
Normal file
32
vendor/riscv-isa-sim/fesvr/htif_hexwriter.h
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef __HTIF_HEXWRITER_H
|
||||
#define __HTIF_HEXWRITER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "memif.h"
|
||||
|
||||
class htif_hexwriter_t : public chunked_memif_t
|
||||
{
|
||||
public:
|
||||
htif_hexwriter_t(size_t b, size_t w, size_t d);
|
||||
|
||||
protected:
|
||||
size_t base;
|
||||
size_t width;
|
||||
size_t depth;
|
||||
std::map<addr_t,std::vector<char> > mem;
|
||||
|
||||
void read_chunk(addr_t taddr, size_t len, void* dst);
|
||||
void write_chunk(addr_t taddr, size_t len, const void* src);
|
||||
void clear_chunk(addr_t taddr, size_t len) {}
|
||||
|
||||
size_t chunk_max_size() { return width; }
|
||||
size_t chunk_align() { return width; }
|
||||
|
||||
friend std::ostream& operator<< (std::ostream&, const htif_hexwriter_t&);
|
||||
};
|
||||
|
||||
#endif // __HTIF_HEXWRITER_H
|
66
vendor/riscv-isa-sim/fesvr/htif_pthread.cc
vendored
Normal file
66
vendor/riscv-isa-sim/fesvr/htif_pthread.cc
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "htif_pthread.h"
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
void htif_pthread_t::thread_main(void* arg)
|
||||
{
|
||||
htif_pthread_t* htif = static_cast<htif_pthread_t*>(arg);
|
||||
htif->run();
|
||||
while (true)
|
||||
htif->target->switch_to();
|
||||
}
|
||||
|
||||
htif_pthread_t::htif_pthread_t(int argc, char** argv)
|
||||
: htif_t(argc, argv)
|
||||
{
|
||||
target = context_t::current();
|
||||
host.init(thread_main, this);
|
||||
}
|
||||
|
||||
htif_pthread_t::~htif_pthread_t()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t htif_pthread_t::read(void* buf, size_t max_size)
|
||||
{
|
||||
while (th_data.size() == 0)
|
||||
target->switch_to();
|
||||
|
||||
size_t s = std::min(max_size, th_data.size());
|
||||
std::copy(th_data.begin(), th_data.begin() + s, (char*)buf);
|
||||
th_data.erase(th_data.begin(), th_data.begin() + s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
ssize_t htif_pthread_t::write(const void* buf, size_t size)
|
||||
{
|
||||
ht_data.insert(ht_data.end(), (const char*)buf, (const char*)buf + size);
|
||||
return size;
|
||||
}
|
||||
|
||||
void htif_pthread_t::send(const void* buf, size_t size)
|
||||
{
|
||||
th_data.insert(th_data.end(), (const char*)buf, (const char*)buf + size);
|
||||
}
|
||||
|
||||
void htif_pthread_t::recv(void* buf, size_t size)
|
||||
{
|
||||
while (!this->recv_nonblocking(buf, size))
|
||||
;
|
||||
}
|
||||
|
||||
bool htif_pthread_t::recv_nonblocking(void* buf, size_t size)
|
||||
{
|
||||
if (ht_data.size() < size)
|
||||
{
|
||||
host.switch_to();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::copy(ht_data.begin(), ht_data.begin() + size, (char*)buf);
|
||||
ht_data.erase(ht_data.begin(), ht_data.begin() + size);
|
||||
return true;
|
||||
}
|
38
vendor/riscv-isa-sim/fesvr/htif_pthread.h
vendored
Normal file
38
vendor/riscv-isa-sim/fesvr/htif_pthread.h
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef _HTIF_PTHREAD_H
|
||||
#define _HTIF_PTHREAD_H
|
||||
|
||||
#include "htif.h"
|
||||
#include "context.h"
|
||||
#include <deque>
|
||||
|
||||
class htif_pthread_t : public htif_t
|
||||
{
|
||||
public:
|
||||
htif_pthread_t(int argc, char** argv);
|
||||
virtual ~htif_pthread_t();
|
||||
|
||||
// target inteface
|
||||
void send(const void* buf, size_t size);
|
||||
void recv(void* buf, size_t size);
|
||||
bool recv_nonblocking(void* buf, size_t size);
|
||||
|
||||
protected:
|
||||
// host interface
|
||||
virtual ssize_t read(void* buf, size_t max_size);
|
||||
virtual ssize_t write(const void* buf, size_t size);
|
||||
|
||||
virtual size_t chunk_align() { return 64; }
|
||||
virtual size_t chunk_max_size() { return 1024; }
|
||||
|
||||
private:
|
||||
context_t host;
|
||||
context_t* target;
|
||||
std::deque<char> th_data;
|
||||
std::deque<char> ht_data;
|
||||
|
||||
static void thread_main(void* htif);
|
||||
};
|
||||
|
||||
#endif
|
183
vendor/riscv-isa-sim/fesvr/memif.cc
vendored
Normal file
183
vendor/riscv-isa-sim/fesvr/memif.cc
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdexcept>
|
||||
#include "memif.h"
|
||||
|
||||
void memif_t::read(addr_t addr, size_t len, void* bytes)
|
||||
{
|
||||
size_t align = cmemif->chunk_align();
|
||||
if (len && (addr & (align-1)))
|
||||
{
|
||||
size_t this_len = std::min(len, align - size_t(addr & (align-1)));
|
||||
uint8_t chunk[align];
|
||||
|
||||
cmemif->read_chunk(addr & ~(align-1), align, chunk);
|
||||
memcpy(bytes, chunk + (addr & (align-1)), this_len);
|
||||
|
||||
bytes = (char*)bytes + this_len;
|
||||
addr += this_len;
|
||||
len -= this_len;
|
||||
}
|
||||
|
||||
if (len & (align-1))
|
||||
{
|
||||
size_t this_len = len & (align-1);
|
||||
size_t start = len - this_len;
|
||||
uint8_t chunk[align];
|
||||
|
||||
cmemif->read_chunk(addr + start, align, chunk);
|
||||
memcpy((char*)bytes + start, chunk, this_len);
|
||||
|
||||
len -= this_len;
|
||||
}
|
||||
|
||||
// now we're aligned
|
||||
for (size_t pos = 0; pos < len; pos += cmemif->chunk_max_size())
|
||||
cmemif->read_chunk(addr + pos, std::min(cmemif->chunk_max_size(), len - pos), (char*)bytes + pos);
|
||||
}
|
||||
|
||||
void memif_t::write(addr_t addr, size_t len, const void* bytes)
|
||||
{
|
||||
size_t align = cmemif->chunk_align();
|
||||
if (len && (addr & (align-1)))
|
||||
{
|
||||
size_t this_len = std::min(len, align - size_t(addr & (align-1)));
|
||||
uint8_t chunk[align];
|
||||
|
||||
cmemif->read_chunk(addr & ~(align-1), align, chunk);
|
||||
memcpy(chunk + (addr & (align-1)), bytes, this_len);
|
||||
cmemif->write_chunk(addr & ~(align-1), align, chunk);
|
||||
|
||||
bytes = (char*)bytes + this_len;
|
||||
addr += this_len;
|
||||
len -= this_len;
|
||||
}
|
||||
|
||||
if (len & (align-1))
|
||||
{
|
||||
size_t this_len = len & (align-1);
|
||||
size_t start = len - this_len;
|
||||
uint8_t chunk[align];
|
||||
|
||||
cmemif->read_chunk(addr + start, align, chunk);
|
||||
memcpy(chunk, (char*)bytes + start, this_len);
|
||||
cmemif->write_chunk(addr + start, align, chunk);
|
||||
|
||||
len -= this_len;
|
||||
}
|
||||
|
||||
// now we're aligned
|
||||
bool all_zero = len != 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
all_zero &= ((const char*)bytes)[i] == 0;
|
||||
|
||||
if (all_zero) {
|
||||
cmemif->clear_chunk(addr, len);
|
||||
} else {
|
||||
size_t max_chunk = cmemif->chunk_max_size();
|
||||
for (size_t pos = 0; pos < len; pos += max_chunk)
|
||||
cmemif->write_chunk(addr + pos, std::min(max_chunk, len - pos), (char*)bytes + pos);
|
||||
}
|
||||
}
|
||||
|
||||
#define MEMIF_READ_FUNC \
|
||||
if(addr & (sizeof(val)-1)) \
|
||||
throw std::runtime_error("misaligned address"); \
|
||||
this->read(addr, sizeof(val), &val); \
|
||||
return val
|
||||
|
||||
#define MEMIF_WRITE_FUNC \
|
||||
if(addr & (sizeof(val)-1)) \
|
||||
throw std::runtime_error("misaligned address"); \
|
||||
this->write(addr, sizeof(val), &val)
|
||||
|
||||
target_endian<uint8_t> memif_t::read_uint8(addr_t addr)
|
||||
{
|
||||
target_endian<uint8_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
target_endian<int8_t> memif_t::read_int8(addr_t addr)
|
||||
{
|
||||
target_endian<int8_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_uint8(addr_t addr, target_endian<uint8_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_int8(addr_t addr, target_endian<int8_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
target_endian<uint16_t> memif_t::read_uint16(addr_t addr)
|
||||
{
|
||||
target_endian<uint16_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
target_endian<int16_t> memif_t::read_int16(addr_t addr)
|
||||
{
|
||||
target_endian<int16_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_uint16(addr_t addr, target_endian<uint16_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_int16(addr_t addr, target_endian<int16_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
target_endian<uint32_t> memif_t::read_uint32(addr_t addr)
|
||||
{
|
||||
target_endian<uint32_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
target_endian<int32_t> memif_t::read_int32(addr_t addr)
|
||||
{
|
||||
target_endian<int32_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_uint32(addr_t addr, target_endian<uint32_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_int32(addr_t addr, target_endian<int32_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
target_endian<uint64_t> memif_t::read_uint64(addr_t addr)
|
||||
{
|
||||
target_endian<uint64_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
target_endian<int64_t> memif_t::read_int64(addr_t addr)
|
||||
{
|
||||
target_endian<int64_t> val;
|
||||
MEMIF_READ_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_uint64(addr_t addr, target_endian<uint64_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
||||
|
||||
void memif_t::write_int64(addr_t addr, target_endian<int64_t> val)
|
||||
{
|
||||
MEMIF_WRITE_FUNC;
|
||||
}
|
82
vendor/riscv-isa-sim/fesvr/memif.h
vendored
Normal file
82
vendor/riscv-isa-sim/fesvr/memif.h
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef __MEMIF_H
|
||||
#define __MEMIF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "byteorder.h"
|
||||
|
||||
typedef uint64_t reg_t;
|
||||
typedef int64_t sreg_t;
|
||||
typedef reg_t addr_t;
|
||||
|
||||
typedef enum {
|
||||
memif_endianness_undecided,
|
||||
memif_endianness_little,
|
||||
memif_endianness_big
|
||||
} memif_endianness_t;
|
||||
|
||||
class chunked_memif_t
|
||||
{
|
||||
public:
|
||||
virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0;
|
||||
virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0;
|
||||
virtual void clear_chunk(addr_t taddr, size_t len) = 0;
|
||||
|
||||
virtual size_t chunk_align() = 0;
|
||||
virtual size_t chunk_max_size() = 0;
|
||||
|
||||
virtual void set_target_endianness(memif_endianness_t endianness) {}
|
||||
virtual memif_endianness_t get_target_endianness() const {
|
||||
return memif_endianness_undecided;
|
||||
}
|
||||
};
|
||||
|
||||
class memif_t
|
||||
{
|
||||
public:
|
||||
memif_t(chunked_memif_t* _cmemif) : cmemif(_cmemif) {}
|
||||
virtual ~memif_t(){}
|
||||
|
||||
// read and write byte arrays
|
||||
virtual void read(addr_t addr, size_t len, void* bytes);
|
||||
virtual void write(addr_t addr, size_t len, const void* bytes);
|
||||
|
||||
// read and write 8-bit words
|
||||
virtual target_endian<uint8_t> read_uint8(addr_t addr);
|
||||
virtual target_endian<int8_t> read_int8(addr_t addr);
|
||||
virtual void write_uint8(addr_t addr, target_endian<uint8_t> val);
|
||||
virtual void write_int8(addr_t addr, target_endian<int8_t> val);
|
||||
|
||||
// read and write 16-bit words
|
||||
virtual target_endian<uint16_t> read_uint16(addr_t addr);
|
||||
virtual target_endian<int16_t> read_int16(addr_t addr);
|
||||
virtual void write_uint16(addr_t addr, target_endian<uint16_t> val);
|
||||
virtual void write_int16(addr_t addr, target_endian<int16_t> val);
|
||||
|
||||
// read and write 32-bit words
|
||||
virtual target_endian<uint32_t> read_uint32(addr_t addr);
|
||||
virtual target_endian<int32_t> read_int32(addr_t addr);
|
||||
virtual void write_uint32(addr_t addr, target_endian<uint32_t> val);
|
||||
virtual void write_int32(addr_t addr, target_endian<int32_t> val);
|
||||
|
||||
// read and write 64-bit words
|
||||
virtual target_endian<uint64_t> read_uint64(addr_t addr);
|
||||
virtual target_endian<int64_t> read_int64(addr_t addr);
|
||||
virtual void write_uint64(addr_t addr, target_endian<uint64_t> val);
|
||||
virtual void write_int64(addr_t addr, target_endian<int64_t> val);
|
||||
|
||||
// endianness
|
||||
virtual void set_target_endianness(memif_endianness_t endianness) {
|
||||
cmemif->set_target_endianness(endianness);
|
||||
}
|
||||
virtual memif_endianness_t get_target_endianness() const {
|
||||
return cmemif->get_target_endianness();
|
||||
}
|
||||
|
||||
protected:
|
||||
chunked_memif_t* cmemif;
|
||||
};
|
||||
|
||||
#endif // __MEMIF_H
|
51
vendor/riscv-isa-sim/fesvr/option_parser.cc
vendored
Normal file
51
vendor/riscv-isa-sim/fesvr/option_parser.cc
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "option_parser.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
void option_parser_t::option(char c, const char* s, int arg, std::function<void(const char*)> action)
|
||||
{
|
||||
opts.push_back(option_t(c, s, arg, action));
|
||||
}
|
||||
|
||||
const char* const* option_parser_t::parse(const char* const* argv0)
|
||||
{
|
||||
assert(argv0);
|
||||
const char* const* argv = argv0 + 1;
|
||||
for (const char* opt; (opt = *argv) != NULL && opt[0] == '-'; argv++)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto it = opts.begin(); !found && it != opts.end(); it++)
|
||||
{
|
||||
size_t slen = it->str ? strlen(it->str) : 0;
|
||||
bool chr_match = opt[1] != '-' && it->chr && opt[1] == it->chr;
|
||||
bool str_match = opt[1] == '-' && slen && strncmp(opt+2, it->str, slen) == 0;
|
||||
if (chr_match || (str_match && (opt[2+slen] == '=' || opt[2+slen] == '\0')))
|
||||
{
|
||||
const char* optarg =
|
||||
chr_match ? (opt[2] ? &opt[2] : NULL) :
|
||||
opt[2+slen] ? &opt[3+slen] :
|
||||
it->arg ? *(++argv) : NULL;
|
||||
if (optarg && !it->arg)
|
||||
error("no argument allowed for option", *argv0, opt);
|
||||
if (!optarg && it->arg)
|
||||
error("argument required for option", *argv0, opt);
|
||||
it->func(optarg);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
error("unrecognized option", *argv0, opt);
|
||||
}
|
||||
return argv;
|
||||
}
|
||||
|
||||
void option_parser_t::error(const char* msg, const char* argv0, const char* arg)
|
||||
{
|
||||
fprintf(stderr, "%s: %s %s\n", argv0, msg, arg ? arg : "");
|
||||
if (helpmsg) helpmsg();
|
||||
exit(1);
|
||||
}
|
31
vendor/riscv-isa-sim/fesvr/option_parser.h
vendored
Normal file
31
vendor/riscv-isa-sim/fesvr/option_parser.h
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef _OPTION_PARSER_H
|
||||
#define _OPTION_PARSER_H
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
class option_parser_t
|
||||
{
|
||||
public:
|
||||
option_parser_t() : helpmsg(0) {}
|
||||
void help(void (*helpm)(void)) { helpmsg = helpm; }
|
||||
void option(char c, const char* s, int arg, std::function<void(const char*)> action);
|
||||
const char* const* parse(const char* const* argv0);
|
||||
private:
|
||||
struct option_t
|
||||
{
|
||||
char chr;
|
||||
const char* str;
|
||||
int arg;
|
||||
std::function<void(const char*)> func;
|
||||
option_t(char chr, const char* str, int arg, std::function<void(const char*)> func)
|
||||
: chr(chr), str(str), arg(arg), func(func) {}
|
||||
};
|
||||
std::vector<option_t> opts;
|
||||
void (*helpmsg)(void);
|
||||
void error(const char* msg, const char* argv0, const char* arg);
|
||||
};
|
||||
|
||||
#endif
|
230
vendor/riscv-isa-sim/fesvr/rfb.cc
vendored
Normal file
230
vendor/riscv-isa-sim/fesvr/rfb.cc
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
#include "rfb.h"
|
||||
#include "memif.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sched.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
using namespace std::placeholders;
|
||||
|
||||
rfb_t::rfb_t(int display)
|
||||
: sockfd(-1), afd(-1),
|
||||
memif(0), addr(0), width(0), height(0), bpp(0), display(display),
|
||||
thread(pthread_self()), fb1(0), fb2(0), read_pos(0),
|
||||
lock(PTHREAD_MUTEX_INITIALIZER)
|
||||
{
|
||||
register_command(0, std::bind(&rfb_t::handle_configure, this, _1), "configure");
|
||||
register_command(1, std::bind(&rfb_t::handle_set_address, this, _1), "set_address");
|
||||
}
|
||||
|
||||
void* rfb_thread_main(void* arg)
|
||||
{
|
||||
((rfb_t*)arg)->thread_main();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rfb_t::thread_main()
|
||||
{
|
||||
pthread_mutex_lock(&lock);
|
||||
|
||||
int port = 5900 + display;
|
||||
sockfd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
throw std::runtime_error("could not acquire tcp socket");
|
||||
|
||||
struct sockaddr_in saddr, caddr;
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
saddr.sin_port = htons(port);
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
|
||||
throw std::runtime_error("could not bind to port " + std::to_string(port));
|
||||
if (listen(sockfd, 0) < 0)
|
||||
throw std::runtime_error("could not listen on port " + std::to_string(port));
|
||||
|
||||
socklen_t clen = sizeof(caddr);
|
||||
afd = accept(sockfd, (struct sockaddr*)&caddr, &clen);
|
||||
if (afd < 0)
|
||||
throw std::runtime_error("could not accept connection");
|
||||
|
||||
std::string version = "RFB 003.003\n";
|
||||
write(version);
|
||||
if (read() != version)
|
||||
throw std::runtime_error("bad client version");
|
||||
|
||||
write(str(uint32_t(htonl(1))));
|
||||
|
||||
read(); // clientinit
|
||||
|
||||
std::string serverinit;
|
||||
serverinit += str(uint16_t(htons(width)));
|
||||
serverinit += str(uint16_t(htons(height)));
|
||||
serverinit += pixel_format();
|
||||
std::string name = "RISC-V";
|
||||
serverinit += str(uint32_t(htonl(name.length())));
|
||||
serverinit += name;
|
||||
write(serverinit);
|
||||
|
||||
pthread_mutex_unlock(&lock);
|
||||
|
||||
while (memif == NULL)
|
||||
sched_yield();
|
||||
|
||||
while (memif != NULL)
|
||||
{
|
||||
std::string s = read();
|
||||
if (s.length() < 4)
|
||||
break; //throw std::runtime_error("bad command");
|
||||
|
||||
switch (s[0])
|
||||
{
|
||||
case 0: set_pixel_format(s); break;
|
||||
case 2: set_encodings(s); break;
|
||||
case 3: break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lock);
|
||||
close(afd);
|
||||
close(sockfd);
|
||||
afd = -1;
|
||||
sockfd = -1;
|
||||
pthread_mutex_unlock(&lock);
|
||||
|
||||
thread_main();
|
||||
}
|
||||
|
||||
rfb_t::~rfb_t()
|
||||
{
|
||||
memif = 0;
|
||||
if (!pthread_equal(pthread_self(), thread))
|
||||
pthread_join(thread, 0);
|
||||
delete [] fb1;
|
||||
delete [] fb2;
|
||||
}
|
||||
|
||||
void rfb_t::set_encodings(const std::string& s)
|
||||
{
|
||||
uint16_t n = htons(*(uint16_t*)&s[2]);
|
||||
for (size_t b = s.length(); b < 4U+4U*n; b += read().length());
|
||||
}
|
||||
|
||||
void rfb_t::set_pixel_format(const std::string& s)
|
||||
{
|
||||
if (s.length() != 20 || s.substr(4, 16) != pixel_format())
|
||||
throw std::runtime_error("bad pixel format");
|
||||
}
|
||||
|
||||
void rfb_t::fb_update(const std::string& s)
|
||||
{
|
||||
std::string u;
|
||||
u += str(uint8_t(0));
|
||||
u += str(uint8_t(0));
|
||||
u += str(uint16_t(htons(1)));
|
||||
u += str(uint16_t(htons(0)));
|
||||
u += str(uint16_t(htons(0)));
|
||||
u += str(uint16_t(htons(width)));
|
||||
u += str(uint16_t(htons(height)));
|
||||
u += str(uint32_t(htonl(0)));
|
||||
u += std::string((char*)fb1, fb_bytes());
|
||||
|
||||
try
|
||||
{
|
||||
write(u);
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void rfb_t::tick()
|
||||
{
|
||||
if (fb_bytes() == 0 || memif == NULL)
|
||||
return;
|
||||
|
||||
memif->read(addr + read_pos, FB_ALIGN, const_cast<char*>(fb2 + read_pos));
|
||||
read_pos = (read_pos + FB_ALIGN) % fb_bytes();
|
||||
if (read_pos == 0)
|
||||
{
|
||||
std::swap(fb1, fb2);
|
||||
if (pthread_mutex_trylock(&lock) == 0)
|
||||
{
|
||||
fb_update("");
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string rfb_t::pixel_format()
|
||||
{
|
||||
int red_bits = 8, green_bits = 8, blue_bits = 8;
|
||||
int bpp = red_bits + green_bits + blue_bits;
|
||||
while (bpp & (bpp-1)) bpp++;
|
||||
|
||||
std::string fmt;
|
||||
fmt += str(uint8_t(bpp));
|
||||
fmt += str(uint8_t(red_bits + green_bits + blue_bits));
|
||||
fmt += str(uint8_t(0)); // little-endian
|
||||
fmt += str(uint8_t(1)); // true color
|
||||
fmt += str(uint16_t(htons((1<<red_bits)-1)));
|
||||
fmt += str(uint16_t(htons((1<<green_bits)-1)));
|
||||
fmt += str(uint16_t(htons((1<<blue_bits)-1)));
|
||||
fmt += str(uint8_t(blue_bits+green_bits));
|
||||
fmt += str(uint8_t(blue_bits));
|
||||
fmt += str(uint8_t(0));
|
||||
fmt += str(uint16_t(0)); // pad
|
||||
fmt += str(uint8_t(0)); // pad
|
||||
return fmt;
|
||||
}
|
||||
|
||||
void rfb_t::write(const std::string& s)
|
||||
{
|
||||
if ((size_t)::write(afd, s.c_str(), s.length()) != s.length())
|
||||
throw std::runtime_error("could not write");
|
||||
}
|
||||
|
||||
std::string rfb_t::read()
|
||||
{
|
||||
char buf[2048];
|
||||
ssize_t len = ::read(afd, buf, sizeof(buf));
|
||||
if (len < 0)
|
||||
throw std::runtime_error("could not read");
|
||||
if (len == sizeof(buf))
|
||||
throw std::runtime_error("received oversized packet");
|
||||
return std::string(buf, len);
|
||||
}
|
||||
|
||||
void rfb_t::handle_configure(command_t cmd)
|
||||
{
|
||||
if (fb1)
|
||||
throw std::runtime_error("you must only set the rfb configuration once");
|
||||
|
||||
width = cmd.payload();
|
||||
height = cmd.payload() >> 16;
|
||||
|
||||
bpp = cmd.payload() >> 32;
|
||||
if (bpp != 32)
|
||||
throw std::runtime_error("rfb requires 32 bpp true color");
|
||||
|
||||
if (fb_bytes() % FB_ALIGN != 0)
|
||||
throw std::runtime_error("rfb size must be a multiple of " + std::to_string(FB_ALIGN));
|
||||
|
||||
fb1 = new char[fb_bytes()];
|
||||
fb2 = new char[fb_bytes()];
|
||||
if (pthread_create(&thread, 0, rfb_thread_main, this))
|
||||
throw std::runtime_error("could not create thread");
|
||||
cmd.respond(1);
|
||||
}
|
||||
|
||||
void rfb_t::handle_set_address(command_t cmd)
|
||||
{
|
||||
addr = cmd.payload();
|
||||
if (addr % FB_ALIGN != 0)
|
||||
throw std::runtime_error("rfb address must be " + std::to_string(FB_ALIGN) + "-byte aligned");
|
||||
memif = &cmd.memif();
|
||||
cmd.respond(1);
|
||||
}
|
53
vendor/riscv-isa-sim/fesvr/rfb.h
vendored
Normal file
53
vendor/riscv-isa-sim/fesvr/rfb.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef _RFB_H
|
||||
#define _RFB_H
|
||||
|
||||
#include "device.h"
|
||||
#include "memif.h"
|
||||
#include <pthread.h>
|
||||
|
||||
// remote frame buffer
|
||||
class rfb_t : public device_t
|
||||
{
|
||||
public:
|
||||
rfb_t(int display = 0);
|
||||
~rfb_t();
|
||||
void tick();
|
||||
std::string name() { return "RISC-V"; }
|
||||
const char* identity() { return "rfb"; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
std::string str(T x)
|
||||
{
|
||||
return std::string((char*)&x, sizeof(x));
|
||||
}
|
||||
size_t fb_bytes() { return size_t(width) * height * bpp/8; }
|
||||
void thread_main();
|
||||
friend void* rfb_thread_main(void*);
|
||||
std::string pixel_format();
|
||||
void fb_update(const std::string& s);
|
||||
void set_encodings(const std::string& s);
|
||||
void set_pixel_format(const std::string& s);
|
||||
void write(const std::string& s);
|
||||
std::string read();
|
||||
void handle_configure(command_t cmd);
|
||||
void handle_set_address(command_t cmd);
|
||||
|
||||
int sockfd;
|
||||
int afd;
|
||||
memif_t* memif;
|
||||
reg_t addr;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t bpp;
|
||||
int display;
|
||||
pthread_t thread;
|
||||
volatile char* volatile fb1;
|
||||
volatile char* volatile fb2;
|
||||
size_t read_pos;
|
||||
pthread_mutex_t lock;
|
||||
|
||||
static const int FB_ALIGN = 256;
|
||||
};
|
||||
|
||||
#endif
|
502
vendor/riscv-isa-sim/fesvr/syscall.cc
vendored
Normal file
502
vendor/riscv-isa-sim/fesvr/syscall.cc
vendored
Normal file
|
@ -0,0 +1,502 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#include "syscall.h"
|
||||
#include "htif.h"
|
||||
#include "byteorder.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <termios.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
using namespace std::placeholders;
|
||||
|
||||
#define RISCV_AT_FDCWD -100
|
||||
|
||||
struct riscv_stat
|
||||
{
|
||||
target_endian<uint64_t> dev;
|
||||
target_endian<uint64_t> ino;
|
||||
target_endian<uint32_t> mode;
|
||||
target_endian<uint32_t> nlink;
|
||||
target_endian<uint32_t> uid;
|
||||
target_endian<uint32_t> gid;
|
||||
target_endian<uint64_t> rdev;
|
||||
target_endian<uint64_t> __pad1;
|
||||
target_endian<uint64_t> size;
|
||||
target_endian<uint32_t> blksize;
|
||||
target_endian<uint32_t> __pad2;
|
||||
target_endian<uint64_t> blocks;
|
||||
target_endian<uint64_t> atime;
|
||||
target_endian<uint64_t> __pad3;
|
||||
target_endian<uint64_t> mtime;
|
||||
target_endian<uint64_t> __pad4;
|
||||
target_endian<uint64_t> ctime;
|
||||
target_endian<uint64_t> __pad5;
|
||||
target_endian<uint32_t> __unused4;
|
||||
target_endian<uint32_t> __unused5;
|
||||
|
||||
riscv_stat(const struct stat& s, htif_t* htif)
|
||||
: dev(htif->to_target<uint64_t>(s.st_dev)),
|
||||
ino(htif->to_target<uint64_t>(s.st_ino)),
|
||||
mode(htif->to_target<uint32_t>(s.st_mode)),
|
||||
nlink(htif->to_target<uint32_t>(s.st_nlink)),
|
||||
uid(htif->to_target<uint32_t>(s.st_uid)),
|
||||
gid(htif->to_target<uint32_t>(s.st_gid)),
|
||||
rdev(htif->to_target<uint64_t>(s.st_rdev)), __pad1(),
|
||||
size(htif->to_target<uint64_t>(s.st_size)),
|
||||
blksize(htif->to_target<uint32_t>(s.st_blksize)), __pad2(),
|
||||
blocks(htif->to_target<uint64_t>(s.st_blocks)),
|
||||
atime(htif->to_target<uint64_t>(s.st_atime)), __pad3(),
|
||||
mtime(htif->to_target<uint64_t>(s.st_mtime)), __pad4(),
|
||||
ctime(htif->to_target<uint64_t>(s.st_ctime)), __pad5(),
|
||||
__unused4(), __unused5() {}
|
||||
};
|
||||
|
||||
|
||||
struct riscv_statx_timestamp {
|
||||
target_endian<int64_t> tv_sec;
|
||||
target_endian<uint32_t> tv_nsec;
|
||||
target_endian<int32_t> __reserved;
|
||||
};
|
||||
|
||||
#ifdef HAVE_STATX
|
||||
struct riscv_statx
|
||||
{
|
||||
target_endian<uint32_t> mask;
|
||||
target_endian<uint32_t> blksize;
|
||||
target_endian<uint64_t> attributes;
|
||||
target_endian<uint32_t> nlink;
|
||||
target_endian<uint32_t> uid;
|
||||
target_endian<uint32_t> gid;
|
||||
target_endian<uint16_t> mode;
|
||||
target_endian<uint16_t> __spare0[1];
|
||||
target_endian<uint64_t> ino;
|
||||
target_endian<uint64_t> size;
|
||||
target_endian<uint64_t> blocks;
|
||||
target_endian<uint64_t> attributes_mask;
|
||||
struct riscv_statx_timestamp atime;
|
||||
struct riscv_statx_timestamp btime;
|
||||
struct riscv_statx_timestamp ctime;
|
||||
struct riscv_statx_timestamp mtime;
|
||||
target_endian<uint32_t> rdev_major;
|
||||
target_endian<uint32_t> rdev_minor;
|
||||
target_endian<uint32_t> dev_major;
|
||||
target_endian<uint32_t> dev_minor;
|
||||
#ifdef HAVE_STATX_MNT_ID
|
||||
target_endian<uint64_t> mnt_id;
|
||||
target_endian<uint64_t> __spare2;
|
||||
target_endian<uint64_t> __spare3[12];
|
||||
#else
|
||||
target_endian<uint64_t> __spare2[14];
|
||||
#endif
|
||||
|
||||
riscv_statx(const struct statx& s, htif_t* htif)
|
||||
: mask(htif->to_target<uint32_t>(s.stx_mask)),
|
||||
blksize(htif->to_target<uint32_t>(s.stx_blksize)),
|
||||
attributes(htif->to_target<uint64_t>(s.stx_attributes)),
|
||||
nlink(htif->to_target<uint32_t>(s.stx_nlink)),
|
||||
uid(htif->to_target<uint32_t>(s.stx_uid)),
|
||||
gid(htif->to_target<uint32_t>(s.stx_gid)),
|
||||
mode(htif->to_target<uint16_t>(s.stx_mode)), __spare0(),
|
||||
ino(htif->to_target<uint64_t>(s.stx_ino)),
|
||||
size(htif->to_target<uint64_t>(s.stx_size)),
|
||||
blocks(htif->to_target<uint64_t>(s.stx_blocks)),
|
||||
attributes_mask(htif->to_target<uint64_t>(s.stx_attributes_mask)),
|
||||
atime {
|
||||
htif->to_target<int64_t>(s.stx_atime.tv_sec),
|
||||
htif->to_target<uint32_t>(s.stx_atime.tv_nsec)
|
||||
},
|
||||
btime {
|
||||
htif->to_target<int64_t>(s.stx_btime.tv_sec),
|
||||
htif->to_target<uint32_t>(s.stx_btime.tv_nsec)
|
||||
},
|
||||
ctime {
|
||||
htif->to_target<int64_t>(s.stx_ctime.tv_sec),
|
||||
htif->to_target<uint32_t>(s.stx_ctime.tv_nsec)
|
||||
},
|
||||
mtime {
|
||||
htif->to_target<int64_t>(s.stx_mtime.tv_sec),
|
||||
htif->to_target<uint32_t>(s.stx_mtime.tv_nsec)
|
||||
},
|
||||
rdev_major(htif->to_target<uint32_t>(s.stx_rdev_major)),
|
||||
rdev_minor(htif->to_target<uint32_t>(s.stx_rdev_minor)),
|
||||
dev_major(htif->to_target<uint32_t>(s.stx_dev_major)),
|
||||
dev_minor(htif->to_target<uint32_t>(s.stx_dev_minor)),
|
||||
#ifdef HAVE_STATX_MNT_ID
|
||||
mnt_id(htif->to_target<uint64_t>(s.stx_mnt_id)),
|
||||
__spare2(), __spare3()
|
||||
#else
|
||||
__spare2()
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
syscall_t::syscall_t(htif_t* htif)
|
||||
: htif(htif), memif(&htif->memif()), table(2048)
|
||||
{
|
||||
table[17] = &syscall_t::sys_getcwd;
|
||||
table[25] = &syscall_t::sys_fcntl;
|
||||
table[34] = &syscall_t::sys_mkdirat;
|
||||
table[35] = &syscall_t::sys_unlinkat;
|
||||
table[37] = &syscall_t::sys_linkat;
|
||||
table[38] = &syscall_t::sys_renameat;
|
||||
table[46] = &syscall_t::sys_ftruncate;
|
||||
table[48] = &syscall_t::sys_faccessat;
|
||||
table[49] = &syscall_t::sys_chdir;
|
||||
table[56] = &syscall_t::sys_openat;
|
||||
table[57] = &syscall_t::sys_close;
|
||||
table[62] = &syscall_t::sys_lseek;
|
||||
table[63] = &syscall_t::sys_read;
|
||||
table[64] = &syscall_t::sys_write;
|
||||
table[67] = &syscall_t::sys_pread;
|
||||
table[68] = &syscall_t::sys_pwrite;
|
||||
table[79] = &syscall_t::sys_fstatat;
|
||||
table[80] = &syscall_t::sys_fstat;
|
||||
table[93] = &syscall_t::sys_exit;
|
||||
table[291] = &syscall_t::sys_statx;
|
||||
table[1039] = &syscall_t::sys_lstat;
|
||||
table[2011] = &syscall_t::sys_getmainvars;
|
||||
|
||||
register_command(0, std::bind(&syscall_t::handle_syscall, this, _1), "syscall");
|
||||
|
||||
int stdin_fd = dup(0), stdout_fd0 = dup(1), stdout_fd1 = dup(1);
|
||||
if (stdin_fd < 0 || stdout_fd0 < 0 || stdout_fd1 < 0)
|
||||
throw std::runtime_error("could not dup stdin/stdout");
|
||||
|
||||
fds.alloc(stdin_fd); // stdin -> stdin
|
||||
fds.alloc(stdout_fd0); // stdout -> stdout
|
||||
fds.alloc(stdout_fd1); // stderr -> stdout
|
||||
}
|
||||
|
||||
std::string syscall_t::do_chroot(const char* fn)
|
||||
{
|
||||
if (!chroot.empty() && *fn == '/')
|
||||
return chroot + fn;
|
||||
return fn;
|
||||
}
|
||||
|
||||
std::string syscall_t::undo_chroot(const char* fn)
|
||||
{
|
||||
if (chroot.empty())
|
||||
return fn;
|
||||
if (strncmp(fn, chroot.c_str(), chroot.size()) == 0
|
||||
&& (chroot.back() == '/' || fn[chroot.size()] == '/'))
|
||||
return fn + chroot.size() - (chroot.back() == '/');
|
||||
return "/";
|
||||
}
|
||||
|
||||
void syscall_t::handle_syscall(command_t cmd)
|
||||
{
|
||||
if (cmd.payload() & 1) // test pass/fail
|
||||
{
|
||||
htif->exitcode = cmd.payload();
|
||||
if (htif->exit_code())
|
||||
std::cerr << "*** FAILED *** (tohost = " << htif->exit_code() << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
else // proxied system call
|
||||
dispatch(cmd.payload());
|
||||
|
||||
cmd.respond(1);
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_exit(reg_t code, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
htif->exitcode = code << 1 | 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static reg_t sysret_errno(sreg_t ret)
|
||||
{
|
||||
return ret == -1 ? -errno : ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_read(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> buf(len);
|
||||
ssize_t ret = read(fds.lookup(fd), buf.data(), len);
|
||||
reg_t ret_errno = sysret_errno(ret);
|
||||
if (ret > 0)
|
||||
memif->write(pbuf, ret, buf.data());
|
||||
return ret_errno;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_pread(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> buf(len);
|
||||
ssize_t ret = pread(fds.lookup(fd), buf.data(), len, off);
|
||||
reg_t ret_errno = sysret_errno(ret);
|
||||
if (ret > 0)
|
||||
memif->write(pbuf, ret, buf.data());
|
||||
return ret_errno;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_write(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> buf(len);
|
||||
memif->read(pbuf, len, buf.data());
|
||||
reg_t ret = sysret_errno(write(fds.lookup(fd), buf.data(), len));
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_pwrite(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> buf(len);
|
||||
memif->read(pbuf, len, buf.data());
|
||||
reg_t ret = sysret_errno(pwrite(fds.lookup(fd), buf.data(), len, off));
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_close(reg_t fd, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
if (close(fds.lookup(fd)) < 0)
|
||||
return sysret_errno(-1);
|
||||
fds.dealloc(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_lseek(reg_t fd, reg_t ptr, reg_t dir, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
return sysret_errno(lseek(fds.lookup(fd), ptr, dir));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_fstat(reg_t fd, reg_t pbuf, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
struct stat buf;
|
||||
reg_t ret = sysret_errno(fstat(fds.lookup(fd), &buf));
|
||||
if (ret != (reg_t)-1)
|
||||
{
|
||||
riscv_stat rbuf(buf, htif);
|
||||
memif->write(pbuf, sizeof(rbuf), &rbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_fcntl(reg_t fd, reg_t cmd, reg_t arg, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
return sysret_errno(fcntl(fds.lookup(fd), cmd, arg));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_ftruncate(reg_t fd, reg_t len, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
return sysret_errno(ftruncate(fds.lookup(fd), len));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_lstat(reg_t pname, reg_t len, reg_t pbuf, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
|
||||
struct stat buf;
|
||||
reg_t ret = sysret_errno(lstat(do_chroot(name.data()).c_str(), &buf));
|
||||
if (ret != (reg_t)-1)
|
||||
{
|
||||
riscv_stat rbuf(buf, htif);
|
||||
memif->write(pbuf, sizeof(rbuf), &rbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_statx(reg_t fd, reg_t pname, reg_t len, reg_t flags, reg_t mask, reg_t pbuf, reg_t a6)
|
||||
{
|
||||
#ifndef HAVE_STATX
|
||||
return -ENOSYS;
|
||||
#else
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
|
||||
struct statx buf;
|
||||
reg_t ret = sysret_errno(statx(fds.lookup(fd), do_chroot(name.data()).c_str(), flags, mask, &buf));
|
||||
if (ret != (reg_t)-1)
|
||||
{
|
||||
riscv_statx rbuf(buf, htif);
|
||||
memif->write(pbuf, sizeof(rbuf), &rbuf);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define AT_SYSCALL(syscall, fd, name, ...) \
|
||||
(syscall(fds.lookup(fd), int(fd) == RISCV_AT_FDCWD ? do_chroot(name).c_str() : (name), __VA_ARGS__))
|
||||
|
||||
reg_t syscall_t::sys_openat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t mode, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
int fd = sysret_errno(AT_SYSCALL(openat, dirfd, name.data(), flags, mode));
|
||||
if (fd < 0)
|
||||
return sysret_errno(-1);
|
||||
return fds.alloc(fd);
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_fstatat(reg_t dirfd, reg_t pname, reg_t len, reg_t pbuf, reg_t flags, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
|
||||
struct stat buf;
|
||||
reg_t ret = sysret_errno(AT_SYSCALL(fstatat, dirfd, name.data(), &buf, flags));
|
||||
if (ret != (reg_t)-1)
|
||||
{
|
||||
riscv_stat rbuf(buf, htif);
|
||||
memif->write(pbuf, sizeof(rbuf), &rbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_faccessat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
return sysret_errno(AT_SYSCALL(faccessat, dirfd, name.data(), mode, 0));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_renameat(reg_t odirfd, reg_t popath, reg_t olen, reg_t ndirfd, reg_t pnpath, reg_t nlen, reg_t a6)
|
||||
{
|
||||
std::vector<char> opath(olen), npath(nlen);
|
||||
memif->read(popath, olen, opath.data());
|
||||
memif->read(pnpath, nlen, npath.data());
|
||||
return sysret_errno(renameat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(opath.data()).c_str() : opath.data(),
|
||||
fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(npath.data()).c_str() : npath.data()));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_linkat(reg_t odirfd, reg_t poname, reg_t olen, reg_t ndirfd, reg_t pnname, reg_t nlen, reg_t flags)
|
||||
{
|
||||
std::vector<char> oname(olen), nname(nlen);
|
||||
memif->read(poname, olen, oname.data());
|
||||
memif->read(pnname, nlen, nname.data());
|
||||
return sysret_errno(linkat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(oname.data()).c_str() : oname.data(),
|
||||
fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(nname.data()).c_str() : nname.data(),
|
||||
flags));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_unlinkat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
return sysret_errno(AT_SYSCALL(unlinkat, dirfd, name.data(), flags));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_mkdirat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> name(len);
|
||||
memif->read(pname, len, name.data());
|
||||
return sysret_errno(AT_SYSCALL(mkdirat, dirfd, name.data(), mode));
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_getcwd(reg_t pbuf, reg_t size, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<char> buf(size);
|
||||
char* ret = getcwd(buf.data(), size);
|
||||
if (ret == NULL)
|
||||
return sysret_errno(-1);
|
||||
std::string tmp = undo_chroot(buf.data());
|
||||
if (size <= tmp.size())
|
||||
return -ENOMEM;
|
||||
memif->write(pbuf, tmp.size() + 1, tmp.data());
|
||||
return tmp.size() + 1;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
std::vector<std::string> args = htif->target_args();
|
||||
std::vector<target_endian<uint64_t>> words(args.size() + 3);
|
||||
words[0] = htif->to_target<uint64_t>(args.size());
|
||||
words[args.size()+1] = target_endian<uint64_t>::zero; // argv[argc] = NULL
|
||||
words[args.size()+2] = target_endian<uint64_t>::zero; // envp[0] = NULL
|
||||
|
||||
size_t sz = (args.size() + 3) * sizeof(words[0]);
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
{
|
||||
words[i+1] = htif->to_target<uint64_t>(sz + pbuf);
|
||||
sz += args[i].length() + 1;
|
||||
}
|
||||
|
||||
std::vector<char> bytes(sz);
|
||||
memcpy(bytes.data(), words.data(), sizeof(words[0]) * words.size());
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
strcpy(&bytes[htif->from_target(words[i+1]) - pbuf], args[i].c_str());
|
||||
|
||||
if (bytes.size() > limit)
|
||||
return -ENOMEM;
|
||||
|
||||
memif->write(pbuf, bytes.size(), bytes.data());
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg_t syscall_t::sys_chdir(reg_t path, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
|
||||
{
|
||||
size_t size = 0;
|
||||
while (memif->read_uint8(path + size++))
|
||||
;
|
||||
std::vector<char> buf(size);
|
||||
for (size_t offset = 0;; offset++)
|
||||
{
|
||||
buf[offset] = memif->read_uint8(path + offset);
|
||||
if (!buf[offset])
|
||||
break;
|
||||
}
|
||||
return sysret_errno(chdir(buf.data()));
|
||||
}
|
||||
|
||||
void syscall_t::dispatch(reg_t mm)
|
||||
{
|
||||
target_endian<reg_t> magicmem[8];
|
||||
memif->read(mm, sizeof(magicmem), magicmem);
|
||||
|
||||
reg_t n = htif->from_target(magicmem[0]);
|
||||
if (n >= table.size() || !table[n])
|
||||
throw std::runtime_error("bad syscall #" + std::to_string(n));
|
||||
|
||||
magicmem[0] = htif->to_target((this->*table[n])(htif->from_target(magicmem[1]), htif->from_target(magicmem[2]), htif->from_target(magicmem[3]), htif->from_target(magicmem[4]), htif->from_target(magicmem[5]), htif->from_target(magicmem[6]), htif->from_target(magicmem[7])));
|
||||
|
||||
memif->write(mm, sizeof(magicmem), magicmem);
|
||||
}
|
||||
|
||||
reg_t fds_t::alloc(int fd)
|
||||
{
|
||||
reg_t i;
|
||||
for (i = 0; i < fds.size(); i++)
|
||||
if (fds[i] == -1)
|
||||
break;
|
||||
|
||||
if (i == fds.size())
|
||||
fds.resize(i+1);
|
||||
|
||||
fds[i] = fd;
|
||||
return i;
|
||||
}
|
||||
|
||||
void fds_t::dealloc(reg_t fd)
|
||||
{
|
||||
fds[fd] = -1;
|
||||
}
|
||||
|
||||
int fds_t::lookup(reg_t fd)
|
||||
{
|
||||
if (int(fd) == RISCV_AT_FDCWD)
|
||||
return AT_FDCWD;
|
||||
return fd >= fds.size() ? -1 : fds[fd];
|
||||
}
|
||||
|
||||
void syscall_t::set_chroot(const char* where)
|
||||
{
|
||||
char buf1[PATH_MAX], buf2[PATH_MAX];
|
||||
|
||||
if (getcwd(buf1, sizeof(buf1)) == NULL
|
||||
|| chdir(where) != 0
|
||||
|| getcwd(buf2, sizeof(buf2)) == NULL
|
||||
|| chdir(buf1) != 0)
|
||||
{
|
||||
fprintf(stderr, "could not chroot to %s\n", where);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
chroot = buf2;
|
||||
}
|
73
vendor/riscv-isa-sim/fesvr/syscall.h
vendored
Normal file
73
vendor/riscv-isa-sim/fesvr/syscall.h
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
#ifndef __SYSCALL_H
|
||||
#define __SYSCALL_H
|
||||
|
||||
#include "device.h"
|
||||
#include "memif.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class syscall_t;
|
||||
typedef reg_t (syscall_t::*syscall_func_t)(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
|
||||
class htif_t;
|
||||
class memif_t;
|
||||
|
||||
class fds_t
|
||||
{
|
||||
public:
|
||||
reg_t alloc(int fd);
|
||||
void dealloc(reg_t fd);
|
||||
int lookup(reg_t fd);
|
||||
private:
|
||||
std::vector<int> fds;
|
||||
};
|
||||
|
||||
class syscall_t : public device_t
|
||||
{
|
||||
public:
|
||||
syscall_t(htif_t*);
|
||||
|
||||
void set_chroot(const char* where);
|
||||
|
||||
private:
|
||||
const char* identity() { return "syscall_proxy"; }
|
||||
|
||||
htif_t* htif;
|
||||
memif_t* memif;
|
||||
std::vector<syscall_func_t> table;
|
||||
fds_t fds;
|
||||
|
||||
void handle_syscall(command_t cmd);
|
||||
void dispatch(addr_t mm);
|
||||
|
||||
std::string chroot;
|
||||
std::string do_chroot(const char* fn);
|
||||
std::string undo_chroot(const char* fn);
|
||||
|
||||
reg_t sys_exit(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_openat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_read(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_pread(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_write(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_pwrite(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_close(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_lseek(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_fstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_lstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_statx(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_fstatat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_faccessat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_fcntl(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_ftruncate(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_renameat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_linkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_unlinkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_mkdirat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_getcwd(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_getmainvars(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
reg_t sys_chdir(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
|
||||
};
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue