Get spike from cvv repo (#1544)

* Change target on install-spike
* Delete vendor/riscv/riscv-isa-sim
This commit is contained in:
MarioOpenHWGroup 2023-10-18 17:39:40 +02:00 committed by GitHub
parent 20c6556e4c
commit 3e72504d97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1630 changed files with 1 additions and 85107 deletions

View file

@ -1,9 +0,0 @@
build/
*.gch
autom4te.cache/
.*.swp
*.o
*.d
.gdb_history
.#*
*~

View file

@ -1,36 +0,0 @@
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.

View file

@ -1,24 +0,0 @@
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.

View file

@ -1,521 +0,0 @@
#=========================================================================
# 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 := $(mcppbs-CFLAGS) $(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 $$< -c -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)
rm -f $$@
$(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
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

View file

@ -1,314 +0,0 @@
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
- Zfh and Zfhmin half-precision floating-point extensions, v1.0
- Zfinx extension, v1.0
- Zmmul integer multiplication extension, v1.0
- Zicbom, Zicbop, Zicboz cache-block maintenance extensions, 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
- Sdext extension, v1.0-STABLE
- Sdtrig extension, v1.0-STABLE
- 4 triggers support type={2, 3, 4, 5, 6, 15} (mcontrol, icount, itrigger, etrigger, mcontrol6, disabled)
- Smepmp extension v1.0
- Smstateen extension, v1.0
- Sscofpmf v0.5.2
- Zca extension, v1.0
- Zcb extension, v1.0
- Zcf extension, v1.0
- Zcd extension, v1.0
- Zcmp extension, v1.0
- Zcmt extension, v1.0
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
{
. = 0x10110000;
.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 -m0x10100000: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
adapter driver remote_bitbang
remote_bitbang host localhost
remote_bitbang port 9824
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0xdeadbeef
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 0x10110064: 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
...
```

View file

@ -1 +0,0 @@
#define SPIKE_VERSION "1.1.1-dev"

View file

@ -1,302 +0,0 @@
#=========================================================================
# 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"
])
])
])

View file

@ -1,25 +0,0 @@
# 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

View file

@ -1,58 +0,0 @@
# 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.

View file

@ -1,34 +0,0 @@
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 ;

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,8 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,8 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,7 +0,0 @@
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)

View file

@ -1,18 +0,0 @@
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 = .;
}

View file

@ -1,66 +0,0 @@
#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 \
addi x1, x1, 4; \
li x1, 1; \
write_tohost: \
sw x1, tohost, t1; \
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

View file

@ -1,50 +0,0 @@
# ===========================================================================
# 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

View file

@ -1,44 +0,0 @@
# ===========================================================================
# 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

View file

@ -1,110 +0,0 @@
# ===========================================================================
# 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
])

View file

@ -1,303 +0,0 @@
# ===========================================================================
# 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"
])

View file

@ -1,111 +0,0 @@
# ===========================================================================
# 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
])

View file

@ -1,53 +0,0 @@
# ===========================================================================
# 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

View file

@ -1,53 +0,0 @@
# ===========================================================================
# 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

View file

@ -1,37 +0,0 @@
# ===========================================================================
# 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

View file

@ -1,133 +0,0 @@
/* 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
/* define if the Boost::Regex library is available */
#undef HAVE_BOOST_REGEX
/* 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 support for running target in either endianness */
#undef RISCV_ENABLE_DUAL_ENDIAN
/* 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 --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

File diff suppressed because it is too large Load diff

View file

@ -1,126 +0,0 @@
#=========================================================================
# 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

View file

@ -1,43 +0,0 @@
#include "insn_macros.h"
#include "extension.h"
#include "decode_macros.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){0xFC000073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush});
insns.push_back((insn_desc_t){0xFC200073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush, custom_cflush});
insns.push_back((insn_desc_t){0xFC100073, 0xFFF07FFF, custom_cflush, custom_cflush, custom_cflush, custom_cflush, 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; })

View file

@ -1,12 +0,0 @@
customext_subproject_deps = \
spike_main \
riscv \
disasm \
softfloat \
customext_srcs = \
dummy_rocc.cc \
cflush.cc \
cvxif.cc \
customext_install_shared_lib = yes

View file

@ -1,242 +0,0 @@
// Copyright (C) 2022 Thales DIS Design Services SAS
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0.
//
// Original Author: Zbigniew CHAMSKI <zbigniew.chamski@thalesgroup.com>
#define DECODE_MACRO_USAGE_LOGGED 1
#include "decode_macros.h"
#include "cvxif.h"
#include "mmu.h"
#include <cstring>
// Define custom insns templates.
// The insn-level wrapper is 'c##n' (default implementation,
// writeback disabled), the default implementation
// is 'custom##n': illegal instruction, return 0.
// The writeback controller 'cvxif_extn_t::do_writeback_p'
// is in charge of determining if writeback is required or not.
// Expected instruction encoding is 4 bytes.
#define customX(n) \
static reg_t c##n(processor_t* p, insn_t insn, reg_t pc) \
{ \
cvxif_t* cvxif = static_cast<cvxif_t*>(p->get_extension()); \
cvxif_insn_t custom_insn; \
custom_insn.i = insn; \
reg_t xd = cvxif->default_custom##n(custom_insn); \
if (cvxif->do_writeback_p(custom_insn)) \
WRITE_RD(xd); \
return pc+4; \
} \
\
reg_t default_custom##n(cvxif_insn_t insn) \
{ \
return custom##n(insn); \
}
// This class instantiates the CV-X-IF interface.
class cvxif_t : public cvxif_extn_t
{
public:
const char* name() { return "cvxif_spike"; }
bool do_writeback_p(cvxif_insn_t copro_insn)
{
// INSN_R personality serves to simplify access to standard encoding fields.
cvxif_r_insn_t insn_r = copro_insn.r_type;
if (insn_r.opcode != 0x7b /* MATCH_CUSTOM3 */)
return false;
else switch (insn_r.funct3)
{
case FUNC3_0:
//CUS_NOP have rd equal to zero
return (insn_r.rd != 0x0);
case FUNC3_1:
//Only CUS_ADD
return true;
case FUNC3_2:
//Only CUS_EXC
return false;
default:
// All other cases: writeback is assumed REQUIRED.
return false;
}
}
// Custom0 instructions: default behaviour.
reg_t custom0(cvxif_insn_t incoming_insn)
{
illegal_instruction();
return -1;
}
// Custom1 instructions: default behaviour.
reg_t custom1(cvxif_insn_t incoming_insn)
{
illegal_instruction();
return -1;
}
// Custom2 instructions: default behaviour.
reg_t custom2(cvxif_insn_t incoming_insn)
{
illegal_instruction();
return -1;
}
// Custom3 instructions: provide an explicit implementation of decode+exec.
reg_t custom3(cvxif_insn_t incoming_insn)
{
// Assume R-type insn: it shares opcode and funct3 fields with other CVXIF insn formats.
cvxif_r_insn_t r_insn = incoming_insn.r_type;
// INSN_T simplifies access to register values.
insn_t insn = incoming_insn.i;
switch (r_insn.funct3)
{
case FUNC3_0:
switch (r_insn.funct7 & 0x1) {
case NO_RS3:
switch (r_insn.funct7 & 0x7e) {
case CUS_NOP:
break;
case CUS_U_ADD:
if (p -> get_state() -> prv != PRV_U) {
illegal_instruction();
}
return (reg_t) ((reg_t) RS1 + (reg_t) RS2 + (reg_t) RS3);
case CUS_S_ADD:
if (p -> get_state() -> prv != PRV_S) {
illegal_instruction();
}
return (reg_t) ((reg_t) RS1 + (reg_t) RS2);
case CUS_ADD_MULTI:
return (reg_t) ((reg_t) RS1 + (reg_t) RS2);
default:
illegal_instruction();
}
break;
case RS3_IN:
//Actually only CUS_ADD_RS3 using rs3, we don't need to add another switch case
if (p -> get_nb_register_source() != 3) {
illegal_instruction();
}
return (reg_t) ((reg_t) RS1 + (reg_t) RS2 + (reg_t) RS3);
default:
illegal_instruction();
}
break;
case FUNC3_1:
switch(r_insn.funct7) {
case 0:
return (reg_t) ((reg_t) RS1 + (reg_t) RS2);
break;
default:
illegal_instruction();
}
case FUNC3_2:
switch (r_insn.funct7) {
case (0x60):
if (r_insn.rs2 != 0 || r_insn.rd != 0){
illegal_instruction();
} else {
raise_exception(insn, (reg_t) (r_insn.rs1));
}
break;
default:
illegal_instruction();
}
default:
illegal_instruction();
}
// FORNOW: Return 0xf......f to simplify debugging.
return (reg_t) -1;
}
cvxif_t()
{
}
void raise_exception(insn_t insn, reg_t exc_index)
{
switch (exc_index) {
case CAUSE_MISALIGNED_FETCH:
throw trap_instruction_address_misaligned((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_FETCH_ACCESS:
throw trap_instruction_access_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_BREAKPOINT:
throw trap_breakpoint((p ? p->get_state()->v : false), 1);
case CAUSE_MISALIGNED_LOAD:
// Use 0x1 as perfectly unaligned address;-)
throw trap_load_address_misaligned((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_LOAD_ACCESS:
// Use 0x1 as invalid address.
throw trap_load_access_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_MISALIGNED_STORE:
// Use 0x1 as perfectly unaligned address;-)
throw trap_store_address_misaligned((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_STORE_ACCESS:
// Use 0x1 as invalid address.
throw trap_store_access_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_USER_ECALL:
throw trap_user_ecall();
case CAUSE_SUPERVISOR_ECALL:
throw trap_supervisor_ecall();
case CAUSE_VIRTUAL_SUPERVISOR_ECALL:
throw trap_virtual_supervisor_ecall();
case CAUSE_MACHINE_ECALL:
throw trap_machine_ecall();
case CAUSE_FETCH_PAGE_FAULT:
throw trap_instruction_page_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_LOAD_PAGE_FAULT:
// Use 0x1 as always-faulting address.
throw trap_load_page_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_STORE_PAGE_FAULT:
// Use 0x1 as always-faulting address.
throw trap_store_page_fault((p ? p->get_state()->v : false), 1, 0, 0);
case CAUSE_FETCH_GUEST_PAGE_FAULT:
throw trap_instruction_guest_page_fault(0, 0, 0);
case CAUSE_LOAD_GUEST_PAGE_FAULT:
throw trap_load_guest_page_fault(0, 0, 0);
case CAUSE_VIRTUAL_INSTRUCTION:
throw trap_virtual_instruction(0);
case CAUSE_STORE_GUEST_PAGE_FAULT:
throw trap_store_guest_page_fault(0, 0, 0);
default:
throw trap_unknown_instruction(exc_index, (reg_t)0);
}
}
// Define templates of new instructions.
customX(0)
customX(1)
customX(2)
customX(3)
// Set instruction handlers for customN opcode patterns.
// NOTE: This method may need revisiting if multiple custom extensions are to be loaded
// simultaneously in the future.
std::vector<insn_desc_t> get_instructions()
{
std::vector<insn_desc_t> insns;
insns.push_back((insn_desc_t){0x0b, 0x7f, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, c0});
insns.push_back((insn_desc_t){0x2b, 0x7f, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, c1});
insns.push_back((insn_desc_t){0x5b, 0x7f, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, c2});
insns.push_back((insn_desc_t){0x7b, 0x7f, &c3, &c3, &c3, &c3, &c3, &c3, &c3, c3});
return insns;
}
private:
// State variables go here.
};
REGISTER_EXTENSION(cvxif, []() { return new cvxif_t; })

View file

@ -1,111 +0,0 @@
// Copyright (C) 2022 Thales DIS Design Services SAS
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0.
//
// Original Author: Zbigniew CHAMSKI <zbigniew.chamski@thalesgroup.com>
//
// The following is a RISC-V program to test the functionality of the
// basic CVXIF accelerator interface on the Core-V side.
// Compile using "riscv-none-elf-gcc -O2 cvxif_test.elf cvxif_test.c"
// with -march=/-mabi= settings appropriate for your project.
// Run using "spike -l --extension=cvxif cvxif_test.elf", adding
// an --isa= setting appropriate for your project.
//
// Upon simulating the compiled program, the trace should contain five
// instances of custom3 instructions (the third one being decoded as
// 'unknown').
// The last occurrence of 'custom3' instruction in the trace, encoded as
// 0x8002007b, should be immediately followed by exception
// 'trap_load_address_misaligned' with a tval equal to 0x1 and the
// execution should terminate correctly with exit code 0.
//
// In 64-bit mode, the trace of the last occurrence of custom3
// instruction should be equivalent to
//
// core 0: 0x0000000080002686 (0x8002007b) custom3 (args unknown)
// core 0: exception trap_load_address_misaligned, epc 0x0000000080002686
// core 0: tval 0x0000000000000001
//
// The corresponding trace in 32-bit mode should be equivalent to
//
// core 0: 0x8000205a (0x8002007b) custom3 (args unknown)
// core 0: exception trap_load_address_misaligned, epc 0x8000205a
// core 0: tval 0x00000001
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// Values of MCAUSE corresponding to exceptions coming from the coprocessor I/F
#define CAUSE_MISALIGNED_LOAD 0x4
#define CAUSE_LOAD_ACCESS 0x5
#define CAUSE_MISALIGNED_STORE 0x6
#define CAUSE_STORE_ACCESS 0x7
#define CAUSE_LOAD_PAGE_FAULT 0xd
#define CAUSE_STORE_PAGE_FAULT 0xf
#define CAUSE_COPROCESSOR_EXCEPTION 0x20
// Value of TVAL to pass around.
#define COPRO_TVAL_TEST 0x1a
// Macro to read a CSR (from spike's "encoding.h")
#define read_csr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
int main() {
// "unsigned long int" is always XLEN bits wide.
unsigned long int x = 123, y = 456, z = 0, t = 0;
static unsigned long int amem = 111, bmem = 0;
unsigned long a;
// Add x + y into z. Funct7 == 0, funct3 == 0x0.
asm volatile (".insn r CUSTOM_3, 0, 0, %0, %1, %2" : "=r"(z) : "r"(x), "r"(y));
if (z != 123 + 456)
{
// printf("FAILURE!!!\n");
return 1;
}
// Add three operands in a single R4-type add.
// Leverage current values of x, y and z (z == x + y).
asm volatile (".insn r CUSTOM_3, 0, 0x1, %0, %1, %2, %3" : "=r"(t) : "r"(x), "r"(y), "r"(z));
if (t != x + y + z)
{
// printf("FAILURE");
return 2;
}
// Load 'a' from 'amem'. CUSTOM_LD: opcode == CUSTOM_3, insn_type == I, funct3 == 0x1.
asm volatile (".insn i CUSTOM_3, 0x1, %0, %1" : "=r"(a) : "m"(amem), "I"(0));
if (a != 111)
{
// printf("FAILURE!!!\n");
return 3;
}
// Store 'a' in 'bmem'. CUSTOM_SD: opcode == CUSTOM_3, insn_type == S, funct3 == 0x2.
asm volatile (".insn s CUSTOM_3, 0x2, %0, %1" : : "r"(a), "m"(bmem));
if (bmem != 111)
{
// printf("FAILURE!!!\n");
return 4;
}
// Generate a misaligned load exception (mcause == 0x4).
asm volatile (".insn r CUSTOM_3, 0x0, 0x40, x0, x4, x0" : : );
// If we get here, then the exception test failed ==> exit with general failure code.
exit(1337);
}
// Override default trap handler.
uintptr_t handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])
{
if (cause == CAUSE_MISALIGNED_LOAD)
// Successfully terminate.
exit(0);
else
// Fail with explicit retcode.
exit(5);
}

View file

@ -1,47 +0,0 @@
#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 UNUSED 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_t>(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; })

View file

@ -1,29 +0,0 @@
// 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");
}

View file

@ -1,5 +0,0 @@
/debug_rom
/debug_rom32
/debug_rom64
/debug_rom32.h
/debug_rom64.h

View file

@ -1,24 +0,0 @@
# 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

View file

@ -1,79 +0,0 @@
// 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_DSCRATCH0, 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_DSCRATCH0
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_DSCRATCH0 // 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_DSCRATCH0 // 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.

View file

@ -1,13 +0,0 @@
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;

View file

@ -1,15 +0,0 @@
OUTPUT_ARCH( "riscv" )
ENTRY( entry )
SECTIONS
{
.whereto 0x300 :
{
*(.whereto)
}
. = 0x800;
.text :
{
*(.text)
}
_end = .;
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +0,0 @@
disasm_srcs = \
disasm.cc \
regnames.cc \
disasm_install_lib = yes

View file

@ -1,33 +0,0 @@
// 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";
}

View file

@ -1,291 +0,0 @@
// 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;
}

View file

@ -1,66 +0,0 @@
/* 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 */

View file

@ -1,12 +0,0 @@
fdt_subproject_deps = \
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 \

View file

@ -1,101 +0,0 @@
// 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));
}

View file

@ -1,38 +0,0 @@
// 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);
}

View file

@ -1,881 +0,0 @@
// 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;
}

View file

@ -1,898 +0,0 @@
// 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;
}
}
}

View file

@ -1,476 +0,0 @@
// 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;
}

View file

@ -1,59 +0,0 @@
// 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>";
}

View file

@ -1,376 +0,0 @@
// 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;
}

View file

@ -1,94 +0,0 @@
// 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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,95 +0,0 @@
/* 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 */

View file

@ -1,51 +0,0 @@
/* 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 */

View file

@ -1,94 +0,0 @@
// 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

View file

@ -1,115 +0,0 @@
#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 = 1024 * 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;
}

View file

@ -1,54 +0,0 @@
#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

View file

@ -1,154 +0,0 @@
#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)
{
}
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();
}

View file

@ -1,119 +0,0 @@
#ifndef _DEVICE_H
#define _DEVICE_H
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <functional>
#include <cstdint>
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

View file

@ -1,641 +0,0 @@
#include "dtm.h"
#include "riscv/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_AARSIZE_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 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(DM_DMCONTROL);
write (DM_DMCONTROL, set_field(dmcontrol, DM_DMCONTROL_HASEL, hartsel));
current_hart = hartsel;
}
int dtm_t::enumerate_harts() {
int max_hart = (1 << DM_DMCONTROL_HASEL_LENGTH) - 1;
write(DM_DMCONTROL, set_field(read(DM_DMCONTROL), DM_DMCONTROL_HASEL, max_hart));
read(DM_DMSTATUS);
max_hart = get_field(read(DM_DMCONTROL), DM_DMCONTROL_HASEL);
int hartsel;
for (hartsel = 0; hartsel <= max_hart; hartsel++) {
select_hart(hartsel);
int dmstatus = read(DM_DMSTATUS);
if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT))
break;
}
return hartsel;
}
void dtm_t::halt(int hartsel)
{
if (running) {
write(DM_DMCONTROL, DM_DMCONTROL_DMACTIVE);
// Read dmstatus to avoid back-to-back writes to dmcontrol.
read(DM_DMSTATUS);
}
int dmcontrol = DM_DMCONTROL_HALTREQ | DM_DMCONTROL_DMACTIVE;
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, hartsel);
write(DM_DMCONTROL, dmcontrol);
int dmstatus;
do {
dmstatus = read(DM_DMSTATUS);
} while(get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0);
dmcontrol &= ~DM_DMCONTROL_HALTREQ;
write(DM_DMCONTROL, dmcontrol);
// Read dmstatus to avoid back-to-back writes to dmcontrol.
read(DM_DMSTATUS);
current_hart = hartsel;
}
void dtm_t::resume(int hartsel)
{
int dmcontrol = DM_DMCONTROL_RESUMEREQ | DM_DMCONTROL_DMACTIVE;
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, hartsel);
write(DM_DMCONTROL, dmcontrol);
int dmstatus;
do {
dmstatus = read(DM_DMSTATUS);
} while (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0);
dmcontrol &= ~DM_DMCONTROL_RESUMEREQ;
write(DM_DMCONTROL, dmcontrol);
// Read dmstatus to avoid back-to-back writes to dmcontrol.
read(DM_DMSTATUS);
current_hart = hartsel;
if (running) {
write(DM_DMCONTROL, DM_DMCONTROL_DMACTIVE);
// Read dmstatus to avoid back-to-back writes to dmcontrol.
read(DM_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(DM_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(DM_DATA0 + i, data[i]);
}
}
write(DM_COMMAND, command);
// Wait for not busy and then check for error.
uint32_t abstractcs;
do {
abstractcs = read(DM_ABSTRACTCS);
} while (abstractcs & DM_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(DM_DATA0 + i);
}
}
return get_field(abstractcs, DM_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(DM_ABSTRACTAUTO, 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
}
memcpy(data, curr, xlen/8);
curr += xlen/8;
if (xlen == 64) {
write(DM_DATA0 + 1, data[1]);
}
write(DM_DATA0, data[0]); //Triggers a command w/ autoexec.
do {
abstractcs = read(DM_ABSTRACTCS);
} while (abstractcs & DM_ABSTRACTCS_BUSY);
if ( get_field(abstractcs, DM_ABSTRACTCS_CMDERR)) {
die(get_field(abstractcs, DM_ABSTRACTCS_CMDERR));
}
}
if ((len * 8 / xlen) > 1) {
write(DM_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(DM_ABSTRACTCS, DM_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(DM_DATA0);//adata[0];
if (xlen == 64)
res |= read(DM_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(DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR);
cmderr = run_abstract_command(command | AC_AR_SIZE(64), prog, 0, data, 0);
if (cmderr == 0){
return 64;
}
write(DM_ABSTRACTCS, DM_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(DM_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(DM_DMCONTROL, DM_DMCONTROL_DMACTIVE);
// Poll until the debugger agrees it's enabled.
while ((read(DM_DMCONTROL) & DM_DMCONTROL_DMACTIVE) == 0) ;
// These are checked every time we run an abstract command.
uint32_t abstractcs = read(DM_ABSTRACTCS);
ram_words = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE);
data_words = get_field(abstractcs, DM_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(DM_HARTINFO);
assert(get_field(hartinfo, DM_HARTINFO_NSCRATCH) > 0);
assert(get_field(hartinfo, DM_HARTINFO_DATAACCESS));
data_base = get_field(hartinfo, DM_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();
}

View file

@ -1,117 +0,0 @@
#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;
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);
uint32_t get_data_base() { return data_base; };
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;
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

View file

@ -1,4 +0,0 @@
// See LICENSE for license details.
// help out poor, C-centric autoconf
extern "C" void libfesvr_is_present() {}

View file

@ -1,134 +0,0 @@
// 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

View file

@ -1,47 +0,0 @@
// 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;
}

View file

@ -1,128 +0,0 @@
// See LICENSE for license details.
#include "config.h"
#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, unsigned required_xlen = 0)
{
int fd = open(fn, O_RDONLY);
struct stat s;
if (fd == -1)
throw std::invalid_argument(std::string("Specified ELF can't be opened: ") + strerror(errno));
if (fstat(fd, &s) < 0)
abort();
size_t size = s.st_size;
char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED)
throw std::invalid_argument(std::string("Specified ELF can't be mapped: ") + strerror(errno));
close(fd);
assert(size >= sizeof(Elf64_Ehdr));
const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf;
assert(IS_ELF32(*eh64) || IS_ELF64(*eh64));
unsigned xlen = IS_ELF32(*eh64) ? 32 : 64;
if (required_xlen != 0 && required_xlen != xlen) {
throw incompat_xlen(required_xlen, xlen);
}
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)) {
if (memif->get_target_endianness() != endianness_little) {
throw std::invalid_argument("Specified ELF is little endian, but system uses a big-endian memory system. Rerun without --big-endian");
}
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
if (memif->get_target_endianness() != endianness_big) {
throw std::invalid_argument("Specified ELF is big endian, but system uses a little-endian memory system. Rerun with --big-endian");
}
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;
}

View file

@ -1,13 +0,0 @@
// 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, unsigned required_xlen = 0);
#endif

View file

@ -1,11 +0,0 @@
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.]),
,
)

View file

@ -1,40 +0,0 @@
fesvr_install_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_config_hdr = yes
fesvr_install_lib = yes
fesvr_install_shared_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 \

View file

@ -1,26 +0,0 @@
#=========================================================================
# 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@

View file

@ -1,455 +0,0 @@
// See LICENSE for license details.
#include "config.h"
#include "htif.h"
#include "rfb.h"
#include "elfloader.h"
#include "platform.h"
#include "byteorder.h"
#include "trap.h"
#include "../riscv/common.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") {
try {
load_program();
} catch (const incompat_xlen & err) {
fprintf(stderr, "Error: cannot execute %d-bit program on RV%d hart\n", err.actual_xlen, err.expected_xlen);
exit(1);
}
}
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;
else
throw std::runtime_error(
"could not open " + payload + "; searched paths:\n" +
"\t. (current directory)\n" +
"\t" + PREFIX TARGET_DIR + " (based on configured --prefix and --with-target)"
);
}
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, expected_xlen);
} 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);
}
class nop_memif_t : public memif_t {
public:
nop_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {}
void read(addr_t UNUSED addr, size_t UNUSED len, void UNUSED *bytes) override {}
void write(addr_t UNUSED taddr, size_t UNUSED len, const void UNUSED *src) override {}
private:
htif_t* htif;
} nop_memif(this);
reg_t nop_entry;
for (auto &s : symbol_elfs) {
std::map<std::string, uint64_t> other_symbols = load_elf(s.c_str(), &nop_memif, &nop_entry,
expected_xlen);
symbols.merge(other_symbols);
}
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 HTIF_LONG_OPTIONS_OPTIND + 6:
targs.push_back(optarg);
break;
case HTIF_LONG_OPTIONS_OPTIND + 7:
symbol_elfs.push_back(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("+target-argument=") == 0) {
c = HTIF_LONG_OPTIONS_OPTIND + 6;
optarg = optarg + 17;
}
else if (arg.find("+symbol-elf=") == 0) {
c = HTIF_LONG_OPTIONS_OPTIND + 7;
optarg = optarg + 12;
}
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);
}

View file

@ -1,155 +0,0 @@
// 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();
void set_expected_xlen(unsigned int m) { expected_xlen = m; }
virtual memif_t& memif() { return mem; }
template<typename T> inline T from_target(target_endian<T> n) const
{
endianness_t endianness = get_target_endianness();
assert(endianness == endianness_little || endianness == endianness_big);
return endianness == endianness_big? n.from_be() : n.from_le();
}
template<typename T> inline target_endian<T> to_target(T n) const
{
endianness_t endianness = get_target_endianness();
assert(endianness == endianness_little || endianness == endianness_big);
return endianness == endianness_big? target_endian<T>::to_be(n) : target_endian<T>::to_le(n);
}
addr_t get_tohost_addr() { return tohost_addr; }
addr_t get_fromhost_addr() { return fromhost_addr; }
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; }
const std::vector<std::string>& target_args() { return targs; }
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, size_t) { 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);
unsigned int expected_xlen = 0;
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;
std::vector<std::string> symbol_elfs;
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\
--symbol-elf=PATH Populate the symbol table with the ELF file at PATH\n\
+symbol-elf=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", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 5 }, \
{"target-argument", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 6 }, \
{"symbol-elf", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 7 }, \
{0, 0, 0, 0}
#endif // __HTIF_H

View file

@ -1,76 +0,0 @@
// 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;
}

View file

@ -1,32 +0,0 @@
// 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, size_t) {}
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

View file

@ -1,66 +0,0 @@
// 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;
}

View file

@ -1,38 +0,0 @@
// 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

View file

@ -1,183 +0,0 @@
// 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;
}

View file

@ -1,83 +0,0 @@
// See LICENSE for license details.
#ifndef __MEMIF_H
#define __MEMIF_H
#include <stdint.h>
#include <stddef.h>
#include <stdexcept>
#include "byteorder.h"
#include "../riscv/cfg.h"
typedef uint64_t reg_t;
typedef int64_t sreg_t;
typedef reg_t addr_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 endianness_t get_target_endianness() const {
return endianness_little;
}
virtual ~chunked_memif_t() = default;
};
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 endianness_t get_target_endianness() const {
return cmemif->get_target_endianness();
}
protected:
chunked_memif_t* cmemif;
};
class incompat_xlen : public std::exception {
public:
const unsigned expected_xlen;
const unsigned actual_xlen;
incompat_xlen(unsigned _expected_xlen, unsigned _actual_xlen) : expected_xlen(_expected_xlen), actual_xlen(_actual_xlen) {}
};
#endif // __MEMIF_H

View file

@ -1,51 +0,0 @@
// 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);
}

View file

@ -1,31 +0,0 @@
// 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

View file

@ -1,230 +0,0 @@
#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()
{
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);
}

View file

@ -1,53 +0,0 @@
#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();
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

View file

@ -1,514 +0,0 @@
// See LICENSE for license details.
#include "config.h"
#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
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
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_index.push_back(fds.alloc(stdin_fd)); // stdin -> stdin
fds_index.push_back(fds.alloc(stdout_fd0)); // stdout -> stdout
fds_index.push_back(fds.alloc(stdout_fd1)); // stderr -> stdout
}
syscall_t::~syscall_t() {
for (auto i: fds_index) {
close(fds.lookup(i));
fds.dealloc(i);
}
}
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;
}

View file

@ -1,75 +0,0 @@
// 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*);
~syscall_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;
std::vector<reg_t> fds_index;
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

View file

@ -1,53 +0,0 @@
#include "term.h"
#include <termios.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>
#include <stdlib.h>
class canonical_termios_t
{
public:
canonical_termios_t()
: restore_tios(false)
{
if (tcgetattr(0, &old_tios) == 0)
{
struct termios new_tios = old_tios;
new_tios.c_lflag &= ~(ICANON | ECHO);
if (tcsetattr(0, TCSANOW, &new_tios) == 0)
restore_tios = true;
}
}
~canonical_termios_t()
{
if (restore_tios)
tcsetattr(0, TCSANOW, &old_tios);
}
private:
struct termios old_tios;
bool restore_tios;
};
static canonical_termios_t tios; // exit() will clean up for us
int canonical_terminal_t::read()
{
struct pollfd pfd;
pfd.fd = 0;
pfd.events = POLLIN;
int ret = poll(&pfd, 1, 0);
if (ret <= 0 || !(pfd.revents & POLLIN))
return -1;
unsigned char ch;
ret = ::read(0, &ch, 1);
return ret <= 0 ? -1 : ch;
}
void canonical_terminal_t::write(char ch)
{
if (::write(1, &ch, 1) != 1)
abort();
}

View file

@ -1,11 +0,0 @@
#ifndef _TERM_H
#define _TERM_H
class canonical_terminal_t
{
public:
static int read();
static void write(char);
};
#endif

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