1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 16:16:16 +04:00

Add riscv-pk from ucore_os_lab

This commit is contained in:
WangRunji 2018-07-04 16:22:20 +08:00
parent c0193e69e6
commit 5ccd84e934
59 changed files with 15259 additions and 0 deletions

11
riscv-pk/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
#=========================================================================
# Git Ignore Files
#=========================================================================
# We explicitly ignore a default build directory and the autoconf
# generated autom4te.cache directory. This makes it easy to do a clean
# build under the source directory and still have it appear clean to git.
build/
autom4te.cache/
*.swp
*~

24
riscv-pk/LICENSE Normal file
View File

@ -0,0 +1,24 @@
Copyright (c) 2013, 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.

455
riscv-pk/Makefile.in Normal file
View File

@ -0,0 +1,455 @@
#=========================================================================
# 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
# 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@
enable_stow := @enable_stow@
ifeq ($(enable_stow),yes)
stow_pkg_dir := $(prefix)/pkgs
INSTALLDIR ?= $(DESTDIR)/$(stow_pkg_dir)/$(project_name)-$(project_ver)
else
INSTALLDIR ?= $(DESTDIR)/$(prefix)/@install_subdir@
endif
install_hdrs_dir := $(INSTALLDIR)/include/$(project_name)
install_libs_dir := $(INSTALLDIR)/lib/$(project_name)
install_exes_dir := $(INSTALLDIR)/bin
#-------------------------------------------------------------------------
# List of subprojects
#-------------------------------------------------------------------------
sprojs := @subprojects@
sprojs_enabled := @subprojects_enabled@
sprojs_include := -I. $(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)
CC := @CC@
READELF := @READELF@
OBJCOPY := @OBJCOPY@
CFLAGS := @CFLAGS@ $(CFLAGS) -DBBL_PAYLOAD=\"bbl_payload\" -DBBL_LOGO_FILE=\"bbl_logo_file\"
BBL_PAYLOAD := @BBL_PAYLOAD@
COMPILE := $(CC) -MMD -MP $(CFLAGS) \
$(sprojs_include)
# Linker
# - LDFLAGS : Flags for the linker (eg. -L)
# - LIBS : Library flags (eg. -l)
LD := $(CC)
LDFLAGS := @LDFLAGS@ -nostartfiles -nostdlib -static $(LDFLAGS)
LIBS := @LIBS@
LINK := $(LD) $(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 444
INSTALL_LIB := $(INSTALL) -m 644
INSTALL_EXE := $(INSTALL) -m 555
STOW := @stow@
#-------------------------------------------------------------------------
# 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)_c_srcs)),)
$(2)_c_srcs += _$(1).c
$(2)_junk += _$(1).c
endif
_$(1).c :
echo "int _$(2)( int arg ) { return arg; }" > $$@
# Build the object files for this subproject
$(2)_c_objs := $$(patsubst %.c, %.o, $$($(2)_c_srcs))
$(2)_asm_objs := $$(patsubst %.S, %.o, $$($(2)_asm_srcs))
$(2)_c_deps := $$(patsubst %.o, %.d, $$($(2)_c_objs))
$$($(2)_c_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_asm_objs) : %.o : %.S
$(COMPILE) -c $$<
$(2)_junk += $$($(2)_c_objs) $$($(2)_c_deps) $$($(2)_asm_objs)
# Build a library for this subproject
lib$(1).a : $$($(2)_c_objs) $$($(2)_asm_objs)
$(AR) rcv $$@ $$^
$(RANLIB) $$@
$(2)_junk += lib$(1).a
# 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 unit tests
$(2)_test_objs := $$(patsubst %.c, %.o, $$($(2)_test_srcs))
$(2)_test_deps := $$(patsubst %.o, %.d, $$($(2)_test_objs))
$(2)_test_exes := $$(patsubst %.t.c, %-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 := -L. $$(patsubst %, -l%, $$($(2)_test_libs))
$$($(2)_test_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_test_exes) : %-utst : %.t.o $$($(2)_test_libnames)
$(LINK) -o $$@ $$< $$($(2)_test_libarg) $(LIBS)
$(2)_c_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 %.c, %.o, $$($(2)_prog_srcs))
$(2)_prog_deps := $$(patsubst %.o, %.d, $$($(2)_prog_objs))
$(2)_prog_exes := $$(patsubst %.c, %, $$($(2)_prog_srcs))
$(2)_prog_libs := $(1) $$($(2)_reverse_deps)
$(2)_prog_libnames := $$(patsubst %, lib%.a, $$($(2)_prog_libs))
$(2)_prog_libarg := -L. $$(patsubst %, -l%, $$($(2)_prog_libs))
$$($(2)_prog_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_prog_exes) : % : %.o $$($(2)_prog_libnames)
$(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS)
$(2)_c_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 %.c, %.o, $$($(2)_install_prog_srcs))
$(2)_install_prog_deps := $$(patsubst %.o, %.d, $$($(2)_install_prog_objs))
$(2)_install_prog_exes := $$(patsubst %.c, %, $$($(2)_install_prog_srcs))
$$($(2)_install_prog_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames)
$(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) -T $(src_dir)/$(2)/$(2).lds
$(2)_c_deps += $$($(2)_install_prog_deps)
$(2)_junk += \
$$($(2)_install_prog_objs) $$($(2)_install_prog_deps) \
$$($(2)_install_prog_exes)
# Subproject specific targets
all-$(1) : lib$(1).a $$($(2)_install_prog_exes)
check-$(1) : $$($(2)_test_outs)
echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $$^; echo
clean-$(1) :
rm -rf $$($(2)_junk)
.PHONY : all-$(1) check-$(1) clean-$(1)
# Update running variables
libs += lib$(1).a
objs += $$($(2)_c_objs)
srcs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_c_srcs))
hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs))
junk += $$($(2)_junk)
deps += $$($(2)_c_deps)
test_outs += $$($(2)_test_outs)
install_hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs))
install_libs += lib$(1).a
install_exes += $$($(2)_install_prog_exes)
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
#-------------------------------------------------------------------------
check : $(test_outs)
echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $^; echo
.PHONY : check
#-------------------------------------------------------------------------
# Installation
#-------------------------------------------------------------------------
install-hdrs : $(install_hdrs)
$(MKINSTALLDIRS) $(install_hdrs_dir)
for file in $(install_hdrs); \
do \
$(INSTALL_HDR) $$file $(install_hdrs_dir); \
done
install-libs : $(install_libs)
$(MKINSTALLDIRS) $(install_libs_dir)
for file in $(install_libs); \
do \
$(INSTALL_LIB) $$file $(install_libs_dir); \
done
install-exes : $(install_exes)
$(MKINSTALLDIRS) $(install_exes_dir)
for file in $(install_exes); \
do \
$(INSTALL_EXE) $$file $(install_exes_dir); \
done
install : install-hdrs install-libs install-exes
ifeq ($(enable_stow),yes)
$(MKINSTALLDIRS) $(stow_pkg_dir)
cd $(stow_pkg_dir) && \
$(STOW) --delete $(project_name)-* && \
$(STOW) $(project_name)-$(project_ver)
endif
.PHONY : install install-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

40
riscv-pk/README.md Normal file
View File

@ -0,0 +1,40 @@
RISC-V Proxy Kernel and Boot Loader
=====================================
About
---------
The RISC-V Proxy Kernel, `pk`, is a lightweight application execution
environment that can host statically-linked RISC-V ELF binaries. It is
designed to support tethered RISC-V implementations with limited I/O
capability and and thus handles I/O-related system calls by proxying them to
a host computer.
This package also contains the Berkeley Boot Loader, `bbl`, which is a
supervisor execution environment for tethered RISC-V systems. It is
designed to host the RISC-V Linux port.
Build Steps
---------------
We assume that the RISCV environment variable is set to the RISC-V tools
install path, and that the riscv-gnu-toolchain package is installed.
Please note that building the binaries directly inside the source
directory is not supported; you need to use a separate build directory.
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV --host=riscv64-unknown-elf
$ make
$ make install
Alternatively, the GNU/Linux toolchain may be used to build this package,
by setting `--host=riscv64-unknown-linux-gnu`.
By default, 64-bit (RV64) versions of `pk` and `bbl` are built. To
built 32-bit (RV32) versions, supply a `--enable-32bit` flag to the
configure command.
The `install` step installs 64-bit build products into
`$RISCV/riscv64-unknown-elf`, and 32-bit versions into
`$RISCV/riscv32-unknown-elf`.

333
riscv-pk/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,333 @@
#=========================================================================
# 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
# Deterimine if native build and set prefix appropriately
AS_IF([ test ${enable_stow} = "yes" ],
[
AC_CHECK_PROGS([stow],[stow],[no])
AS_IF([ test ${stow} = "no" ],
[
AC_MSG_ERROR([Cannot use --enable-stow since stow is not available])
])
# Check if native or non-native build
AS_IF([ test "${build}" = "${host}" ],
[
# build == host so this is a native build. Make sure --prefix not
# set and $STOW_PREFIX is set, then set prefix=$STOW_PREFIX.
AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_PREFIX}" ],
[
prefix="${STOW_PREFIX}"
AC_MSG_NOTICE([Using \$STOW_PREFIX from environment])
AC_MSG_NOTICE([prefix=${prefix}])
])
],[
# build != host so this is a non-native build. Make sure --prefix
# not set and $STOW_ROOT is set, then set
# prefix=$STOW_ROOT/${host_alias}.
AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_ROOT}" ],
[
prefix="${STOW_ROOT}/${host_alias}"
AC_MSG_NOTICE([Using \$STOW_ROOT from environment])
AC_MSG_NOTICE([prefix=${prefix}])
])
])
])
])
#-------------------------------------------------------------------------
# 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"
])
])
])
#-------------------------------------------------------------------------
# AX_DEFAULT_CONFIGURE_ARG
#-------------------------------------------------------------------------
# Simple little macro which adds a configure commane line option to an
# internal autoconf shell variable. Not sure how safe this is, but it
# seems to work fine.
#
# Author : Christopher Batten
# Date : August 20, 2009
AC_DEFUN([AX_DEFAULT_CONFIGURE_ARG],
[
AC_MSG_NOTICE([adding default configure arg: $1])
ac_configure_args="$1 ${ac_configure_args}"
])

12
riscv-pk/bbl/bbl.ac Normal file
View File

@ -0,0 +1,12 @@
AC_ARG_ENABLE([logo], AS_HELP_STRING([--enable-logo], [Enable boot logo]))
AS_IF([test "x$enable_logo" == "xyes"], [
AC_DEFINE([PK_ENABLE_LOGO],,[Define if the RISC-V logo is to be displayed])
])
AC_ARG_WITH([payload], AS_HELP_STRING([--with-payload], [Set ELF payload for bbl]),
[AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])],
[AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])])
AC_ARG_WITH([logo], AS_HELP_STRING([--with-logo], [Specify a better logo]),
[AC_SUBST([BBL_LOGO_FILE], $with_logo, [Logo for bbl])],
[AC_SUBST([BBL_LOGO_FILE], [riscv_logo.txt], [Logo for bbl])])

67
riscv-pk/bbl/bbl.c Normal file
View File

@ -0,0 +1,67 @@
#include "bbl.h"
#include "mtrap.h"
#include "atomic.h"
#include "vm.h"
#include "bits.h"
#include "config.h"
#include "fdt.h"
#include <string.h>
static const void* entry_point;
long disabled_hart_mask;
static uintptr_t dtb_output()
{
extern char _payload_end;
uintptr_t end = (uintptr_t) &_payload_end;
return (end + MEGAPAGE_SIZE - 1) / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
static void filter_dtb(uintptr_t source)
{
uintptr_t dest = dtb_output();
uint32_t size = fdt_size(source);
memcpy((void*)dest, (void*)source, size);
// Remove information from the chained FDT
filter_harts(dest, &disabled_hart_mask);
filter_plic(dest);
filter_compat(dest, "riscv,clint0");
filter_compat(dest, "riscv,debug-013");
}
void boot_other_hart(uintptr_t unused __attribute__((unused)))
{
const void* entry;
do {
entry = entry_point;
mb();
} while (!entry);
long hartid = read_csr(mhartid);
if ((1 << hartid) & disabled_hart_mask) {
while (1) {
__asm__ volatile("wfi");
#ifdef __riscv_div
__asm__ volatile("div x0, x0, x0");
#endif
}
}
enter_supervisor_mode(entry, hartid, dtb_output());
}
void boot_loader(uintptr_t dtb)
{
extern char _payload_start;
filter_dtb(dtb);
#ifdef PK_ENABLE_LOGO
print_logo();
#endif
#ifdef PK_PRINT_DEVICE_TREE
fdt_print(dtb_output());
#endif
mb();
entry_point = &_payload_start;
boot_other_hart(0);
}

15
riscv-pk/bbl/bbl.h Normal file
View File

@ -0,0 +1,15 @@
// See LICENSE for license details.
#ifndef _BBL_H
#define _BBL_H
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
void print_logo();
#endif // !__ASSEMBLER__
#endif

111
riscv-pk/bbl/bbl.lds Normal file
View File

@ -0,0 +1,111 @@
OUTPUT_ARCH( "riscv" )
ENTRY( reset_vector )
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0x80000000;
_ftext = .;
PROVIDE( eprol = . );
.text :
{
*(.text.init)
}
/* text: Program code section */
.text :
{
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
}
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* HTIF, isolated onto separate page */
/*--------------------------------------------------------------------*/
. = ALIGN(0x1000);
.htif :
{
PROVIDE( __htif_base = .);
*(.htif)
}
. = ALIGN(0x1000);
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.srodata*)
*(.gnu.linkonce.d.*)
*(.comment)
}
/* End of initialized data segment */
. = ALIGN(4);
PROVIDE( edata = . );
_edata = .;
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = .;
_fbss = .;
/* sbss: Uninitialized writeable small data section */
. = .;
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.sbss*)
*(.gnu.linkonce.b.*)
*(COMMON)
}
.sbi :
{
*(.sbi)
}
.payload :
{
*(.payload)
}
_end = .;
}

29
riscv-pk/bbl/bbl.mk.in Normal file
View File

@ -0,0 +1,29 @@
bbl_subproject_deps = \
util \
machine \
dummy_payload \
bbl_hdrs = \
bbl.h \
bbl_c_srcs = \
logo.c \
bbl_asm_srcs = \
payload.S \
raw_logo.S \
payload.o: bbl_payload
bbl_payload: $(BBL_PAYLOAD)
if $(READELF) -h $< 2> /dev/null > /dev/null; then $(OBJCOPY) -O binary $< $@; else cp $< $@; fi
raw_logo.o: bbl_logo_file
bbl_logo_file: @BBL_LOGO_FILE@
cat $^ | sed 's/$$/\r/' > $@
bbl_test_srcs =
bbl_install_prog_srcs = \
bbl.c \

9
riscv-pk/bbl/logo.c Normal file
View File

@ -0,0 +1,9 @@
#include <string.h>
#include "mtrap.h"
extern const char logo[];
void print_logo()
{
putstring(logo);
}

9
riscv-pk/bbl/payload.S Normal file
View File

@ -0,0 +1,9 @@
#include "encoding.h"
.section ".payload","a",@progbits
.align RISCV_PGSHIFT + RISCV_PGLEVEL_BITS
.globl _payload_start, _payload_end
_payload_start:
.incbin BBL_PAYLOAD
_payload_end:

7
riscv-pk/bbl/raw_logo.S Normal file
View File

@ -0,0 +1,7 @@
#include "encoding.h"
.section .rodata
.globl logo
logo:
.incbin BBL_LOGO_FILE
.byte 0

View File

@ -0,0 +1,23 @@
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvv
rr vvvvvvvvvvvvvvvvvvvvvv
rr vvvvvvvvvvvvvvvvvvvvvvvv rr
rrrr vvvvvvvvvvvvvvvvvvvvvvvvvv rrrr
rrrrrr vvvvvvvvvvvvvvvvvvvvvv rrrrrr
rrrrrrrr vvvvvvvvvvvvvvvvvv rrrrrrrr
rrrrrrrrrr vvvvvvvvvvvvvv rrrrrrrrrr
rrrrrrrrrrrr vvvvvvvvvv rrrrrrrrrrrr
rrrrrrrrrrrrrr vvvvvv rrrrrrrrrrrrrr
rrrrrrrrrrrrrrrr vv rrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrr
INSTRUCTION SETS WANT TO BE FREE

52
riscv-pk/config.h.in Normal file
View File

@ -0,0 +1,52 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef BBL_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef DUMMY_PAYLOAD_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef MACHINE_ENABLED
/* 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 PK_ENABLED
/* Define if floating-point emulation is enabled */
#undef PK_ENABLE_FP_EMULATION
/* Define if the RISC-V logo is to be displayed */
#undef PK_ENABLE_LOGO
/* Define if virtual memory support is enabled */
#undef PK_ENABLE_VM
/* Define if the DTS is to be displayed */
#undef PK_PRINT_DEVICE_TREE
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef SOFTFLOAT_ENABLED
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef UTIL_ENABLED

5775
riscv-pk/configure vendored Executable file

File diff suppressed because it is too large Load Diff

138
riscv-pk/configure.ac Normal file
View File

@ -0,0 +1,138 @@
#=========================================================================
# 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 Proxy Kernel])
m4_define( proj_maintainer, [Andrew Waterman])
m4_define( proj_abbreviation, [riscv-pk])
#-------------------------------------------------------------------------
# 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_CONFIG_SRCDIR([pk/pk.h])
AC_CONFIG_AUX_DIR([scripts])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
#-------------------------------------------------------------------------
# Checks for programs
#-------------------------------------------------------------------------
AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL([AR],[ar])
AC_CHECK_TOOL([RANLIB],[ranlib])
AC_CHECK_TOOL([READELF],[readelf])
AC_CHECK_TOOL([OBJCOPY],[objcopy])
#-------------------------------------------------------------------------
# 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
#-------------------------------------------------------------------------
# Register RISCV environment variable
#-------------------------------------------------------------------------
AC_ARG_VAR(RISCV, [top-level RISC-V install directory])
#-------------------------------------------------------------------------
# Set compiler flags
#-------------------------------------------------------------------------
default_CFLAGS="-Wall -Werror -D__NO_INLINE__ -mcmodel=medany -O2 -std=gnu99 -Wno-unused -Wno-attributes -fno-delete-null-pointer-checks"
AC_ARG_ENABLE([32bit],
AS_HELP_STRING([--enable-32bit], [Build a 32-bit pk]),
BUILD_32BIT=$enableval,
BUILD_32BIT=no)
case "${BUILD_32BIT}" in
yes|default)
echo "Building 32-bit pk"
CFLAGS="$default_CFLAGS -m32"
LDFLAGS="-m32"
install_subdir="riscv32-unknown-elf"
;;
*)
CFLAGS="$default_CFLAGS"
LDFLAGS=
install_subdir="riscv64-unknown-elf"
;;
esac
AC_ARG_ENABLE([print-device-tree], AS_HELP_STRING([--enable-print-device-tree], [Print DTS when booting]))
AS_IF([test "x$enable_print_device_tree" == "xyes"], [
AC_DEFINE([PK_PRINT_DEVICE_TREE],,[Define if the DTS is to be displayed])
])
AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST([LIBS], ["-lgcc"])
AC_SUBST(install_subdir)
#-------------------------------------------------------------------------
# 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([ pk, bbl, dummy_payload, machine, util ])
#-------------------------------------------------------------------------
# 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_OUTPUT

View File

@ -0,0 +1,22 @@
#include "mcall.h"
.section ".text.init"
.globl _start
_start:
la s0, str
1:
lbu a0, (s0)
beqz a0, 1f
li a7, SBI_CONSOLE_PUTCHAR
ecall
add s0, s0, 1
j 1b
1:
li a7, SBI_SHUTDOWN
ecall
.data
str:
.asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure\n\
bbl with the flag --with-payload=PATH, then rebuild bbl.\n"

View File

View File

View File

@ -0,0 +1,7 @@
ENTRY(_start)
SECTIONS {
. = -0x80000000;
.text.init : { *(.text.init) }
}

View File

@ -0,0 +1,13 @@
dummy_payload_subproject_deps = \
dummy_payload_hdrs = \
dummy_payload_c_srcs = \
dummy_payload_asm_srcs = \
dummy_entry.S \
dummy_payload_test_srcs =
dummy_payload_install_prog_srcs = \
dummy_payload.c \

78
riscv-pk/machine/atomic.h Normal file
View File

@ -0,0 +1,78 @@
// See LICENSE for license details.
#ifndef _RISCV_ATOMIC_H
#define _RISCV_ATOMIC_H
#include "config.h"
#include "encoding.h"
// Currently, interrupts are always disabled in M-mode.
#define disable_irqsave() (0)
#define enable_irqrestore(flags) ((void) (flags))
typedef struct { int lock; } spinlock_t;
#define SPINLOCK_INIT {0}
#define mb() asm volatile ("fence" ::: "memory")
#define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val)
#define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr))
#ifdef __riscv_atomic
# define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc)
# define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc)
# define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp)
# define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp)
#else
# define atomic_binop(ptr, inc, op) ({ \
long flags = disable_irqsave(); \
typeof(*(ptr)) res = atomic_read(ptr); \
atomic_set(ptr, op); \
enable_irqrestore(flags); \
res; })
# define atomic_add(ptr, inc) atomic_binop(ptr, inc, res + (inc))
# define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc))
# define atomic_swap(ptr, inc) atomic_binop(ptr, inc, (inc))
# define atomic_cas(ptr, cmp, swp) ({ \
long flags = disable_irqsave(); \
typeof(*(ptr)) res = *(volatile typeof(*(ptr)) *)(ptr); \
if (res == (cmp)) *(volatile typeof(ptr))(ptr) = (swp); \
enable_irqrestore(flags); \
res; })
#endif
static inline int spinlock_trylock(spinlock_t* lock)
{
int res = atomic_swap(&lock->lock, -1);
mb();
return res;
}
static inline void spinlock_lock(spinlock_t* lock)
{
do
{
while (atomic_read(&lock->lock))
;
} while (spinlock_trylock(lock));
}
static inline void spinlock_unlock(spinlock_t* lock)
{
mb();
atomic_set(&lock->lock,0);
}
static inline long spinlock_lock_irqsave(spinlock_t* lock)
{
long flags = disable_irqsave();
spinlock_lock(lock);
return flags;
}
static inline void spinlock_unlock_irqrestore(spinlock_t* lock, long flags)
{
spinlock_unlock(lock);
enable_irqrestore(flags);
}
#endif

35
riscv-pk/machine/bits.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _RISCV_BITS_H
#define _RISCV_BITS_H
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
#define ROUNDDOWN(a, b) ((a)/(b)*(b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x)
#define XSTR(x) #x
#if __riscv_xlen == 64
# define SLL32 sllw
# define STORE sd
# define LOAD ld
# define LWU lwu
# define LOG_REGBYTES 3
#else
# define SLL32 sll
# define STORE sw
# define LOAD lw
# define LWU lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#endif

View File

@ -0,0 +1,4 @@
#ifndef DISABLED_HART_MASK_H
#define DISABLED_HART_MASK_H
extern long disabled_hart_mask;
#endif

View File

@ -0,0 +1,234 @@
#include "emulation.h"
//#include "fp_emulation.h"
#include "config.h"
#include "unprivileged_memory.h"
#include "mtrap.h"
#include <limits.h>
static DECLARE_EMULATION_FUNC(emulate_rvc)
{
#ifdef __riscv_compressed
// the only emulable RVC instructions are FP loads and stores.
# if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
write_csr(mepc, mepc + 2);
// if FPU is disabled, punt back to the OS
if (unlikely((mstatus & MSTATUS_FS) == 0))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
if ((insn & MASK_C_FLD) == MATCH_C_FLD) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LD_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_load_trap(regs, mcause, mepc);
SET_F64_RD(RVC_RS2S(insn) << SH_RD, regs, load_uint64_t((void *)addr, mepc));
} else if ((insn & MASK_C_FLDSP) == MATCH_C_FLDSP) {
uintptr_t addr = GET_SP(regs) + RVC_LDSP_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_load_trap(regs, mcause, mepc);
SET_F64_RD(insn, regs, load_uint64_t((void *)addr, mepc));
} else if ((insn & MASK_C_FSD) == MATCH_C_FSD) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LD_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_store_trap(regs, mcause, mepc);
store_uint64_t((void *)addr, GET_F64_RS2(RVC_RS2S(insn) << SH_RS2, regs), mepc);
} else if ((insn & MASK_C_FSDSP) == MATCH_C_FSDSP) {
uintptr_t addr = GET_SP(regs) + RVC_SDSP_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_store_trap(regs, mcause, mepc);
store_uint64_t((void *)addr, GET_F64_RS2(RVC_RS2(insn) << SH_RS2, regs), mepc);
} else
# if __riscv_xlen == 32
if ((insn & MASK_C_FLW) == MATCH_C_FLW) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LW_IMM(insn);
if (unlikely(addr % 4))
return misaligned_load_trap(regs, mcause, mepc);
SET_F32_RD(RVC_RS2S(insn) << SH_RD, regs, load_int32_t((void *)addr, mepc));
} else if ((insn & MASK_C_FLWSP) == MATCH_C_FLWSP) {
uintptr_t addr = GET_SP(regs) + RVC_LWSP_IMM(insn);
if (unlikely(addr % 4))
return misaligned_load_trap(regs, mcause, mepc);
SET_F32_RD(insn, regs, load_int32_t((void *)addr, mepc));
} else if ((insn & MASK_C_FSW) == MATCH_C_FSW) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LW_IMM(insn);
if (unlikely(addr % 4))
return misaligned_store_trap(regs, mcause, mepc);
store_uint32_t((void *)addr, GET_F32_RS2(RVC_RS2S(insn) << SH_RS2, regs), mepc);
} else if ((insn & MASK_C_FSWSP) == MATCH_C_FSWSP) {
uintptr_t addr = GET_SP(regs) + RVC_SWSP_IMM(insn);
if (unlikely(addr % 4))
return misaligned_store_trap(regs, mcause, mepc);
store_uint32_t((void *)addr, GET_F32_RS2(RVC_RS2(insn) << SH_RS2, regs), mepc);
} else
# endif
# endif
#endif
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
}
void illegal_insn_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
asm (".pushsection .rodata\n"
"illegal_insn_trap_table:\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
" .word emulate_float_load\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
" .word emulate_float_store\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_muldiv)
" .word emulate_mul_div\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
#if !defined(__riscv_muldiv) && __riscv_xlen >= 64
" .word emulate_mul_div32\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
#ifdef PK_ENABLE_FP_EMULATION
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fp\n"
#else
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word emulate_system_opcode\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .popsection");
uintptr_t mstatus = read_csr(mstatus);
insn_t insn = read_csr(mbadaddr);
if (unlikely((insn & 3) != 3)) {
if (insn == 0)
insn = get_insn(mepc, &mstatus);
if ((insn & 3) != 3)
return emulate_rvc(regs, mcause, mepc, mstatus, insn);
}
write_csr(mepc, mepc + 4);
extern uint32_t illegal_insn_trap_table[];
uint32_t* pf = (void*)illegal_insn_trap_table + (insn & 0x7c);
emulation_func f = (emulation_func)(uintptr_t)*pf;
f(regs, mcause, mepc, mstatus, insn);
}
__attribute__((noinline))
DECLARE_EMULATION_FUNC(truly_illegal_insn)
{
return redirect_trap(mepc, mstatus, insn);
}
static inline int emulate_read_csr(int num, uintptr_t mstatus, uintptr_t* result)
{
uintptr_t counteren = -1;
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
counteren = read_csr(scounteren);
switch (num)
{
case CSR_TIME:
if (!((counteren >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*result = *mtime;
return 0;
#if __riscv_xlen == 32
case CSR_TIMEH:
if (!((counteren >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*result = *mtime >> 32;
return 0;
#endif
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
case CSR_FRM:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FRM();
return 0;
case CSR_FFLAGS:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FFLAGS();
return 0;
case CSR_FCSR:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FCSR();
return 0;
#endif
}
return -1;
}
static inline int emulate_write_csr(int num, uintptr_t value, uintptr_t mstatus)
{
switch (num)
{
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
case CSR_FRM: SET_FRM(value); return 0;
case CSR_FFLAGS: SET_FFLAGS(value); return 0;
case CSR_FCSR: SET_FCSR(value); return 0;
#endif
}
return -1;
}
DECLARE_EMULATION_FUNC(emulate_system_opcode)
{
int rs1_num = (insn >> 15) & 0x1f;
uintptr_t rs1_val = GET_RS1(insn, regs);
int csr_num = (uint32_t)insn >> 20;
uintptr_t csr_val, new_csr_val;
if (emulate_read_csr(csr_num, mstatus, &csr_val))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
int do_write = rs1_num;
#if 0
switch (GET_RM(insn))
{
case 0: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
case 1: new_csr_val = rs1_val; do_write = 1; break;
case 2: new_csr_val = csr_val | rs1_val; break;
case 3: new_csr_val = csr_val & ~rs1_val; break;
case 4: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
case 5: new_csr_val = rs1_num; do_write = 1; break;
case 6: new_csr_val = csr_val | rs1_num; break;
case 7: new_csr_val = csr_val & ~rs1_num; break;
}
#endif
if (do_write && emulate_write_csr(csr_num, new_csr_val, mstatus))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, csr_val);
}

View File

@ -0,0 +1,51 @@
#ifndef _RISCV_EMULATION_H
#define _RISCV_EMULATION_H
#include "encoding.h"
#include "bits.h"
#include <stdint.h>
typedef uintptr_t insn_t;
typedef void (*emulation_func)(uintptr_t*, uintptr_t, uintptr_t, uintptr_t, insn_t);
#define DECLARE_EMULATION_FUNC(name) void name(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn)
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr);
DECLARE_EMULATION_FUNC(truly_illegal_insn);
DECLARE_EMULATION_FUNC(emulate_rvc_0);
DECLARE_EMULATION_FUNC(emulate_rvc_2);
#define SH_RD 7
#define SH_RS1 15
#define SH_RS2 20
#define SH_RS2C 2
#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1))
#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | (RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 1) << 6))
#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 2) << 6))
#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 2) << 6))
#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 3) << 6))
#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | (RV_X(x, 7, 2) << 6))
#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 7, 3) << 6))
#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3))
#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3))
#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5)
#define SHIFT_RIGHT(x, y) ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
#define GET_REG(insn, pos, regs) ({ \
int mask = (1 << (5+LOG_REGBYTES)) - (1 << LOG_REGBYTES); \
(uintptr_t*)((uintptr_t)regs + (SHIFT_RIGHT(insn, (pos) - LOG_REGBYTES) & (mask))); \
})
#define GET_RS1(insn, regs) (*GET_REG(insn, SH_RS1, regs))
#define GET_RS2(insn, regs) (*GET_REG(insn, SH_RS2, regs))
#define GET_RS1S(insn, regs) (*GET_REG(RVC_RS1S(insn), 0, regs))
#define GET_RS2S(insn, regs) (*GET_REG(RVC_RS2S(insn), 0, regs))
#define GET_RS2C(insn, regs) (*GET_REG(insn, SH_RS2C, regs))
#define GET_SP(regs) (*GET_REG(2, 0, regs))
#define SET_RD(insn, regs, val) (*GET_REG(insn, SH_RD, regs) = (val))
#define IMM_I(insn) ((int32_t)(insn) >> 20)
#define IMM_S(insn) (((int32_t)(insn) >> 25 << 5) | (int32_t)(((insn) >> 7) & 0x1f))
#define MASK_FUNCT3 0x7000
#endif

1471
riscv-pk/machine/encoding.h Normal file

File diff suppressed because it is too large Load Diff

740
riscv-pk/machine/fdt.c Normal file
View File

@ -0,0 +1,740 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "fdt.h"
#include "mtrap.h"
static inline uint32_t bswap(uint32_t x)
{
uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16;
return z;
}
static inline int isstring(char c)
{
if (c >= 'A' && c <= 'Z')
return 1;
if (c >= 'a' && c <= 'z')
return 1;
if (c >= '0' && c <= '9')
return 1;
if (c == '\0' || c == ' ' || c == ',' || c == '-')
return 1;
return 0;
}
static uint32_t *fdt_scan_helper(
uint32_t *lex,
const char *strings,
struct fdt_scan_node *node,
const struct fdt_cb *cb)
{
struct fdt_scan_node child;
struct fdt_scan_prop prop;
int last = 0;
child.parent = node;
// these are the default cell counts, as per the FDT spec
child.address_cells = 2;
child.size_cells = 1;
prop.node = node;
while (1) {
switch (bswap(lex[0])) {
case FDT_NOP: {
lex += 1;
break;
}
case FDT_PROP: {
assert (!last);
prop.name = strings + bswap(lex[2]);
prop.len = bswap(lex[1]);
prop.value = lex + 3;
if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); }
if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); }
lex += 3 + (prop.len+3)/4;
cb->prop(&prop, cb->extra);
break;
}
case FDT_BEGIN_NODE: {
uint32_t *lex_next;
if (!last && node && cb->done) cb->done(node, cb->extra);
last = 1;
child.name = (const char *)(lex+1);
if (cb->open) cb->open(&child, cb->extra);
lex_next = fdt_scan_helper(
lex + 2 + strlen(child.name)/4,
strings, &child, cb);
if (cb->close && cb->close(&child, cb->extra) == -1)
while (lex != lex_next) *lex++ = bswap(FDT_NOP);
lex = lex_next;
break;
}
case FDT_END_NODE: {
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex + 1;
}
default: { // FDT_END
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex;
}
}
}
}
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return;
const char *strings = (const char *)(fdt + bswap(header->off_dt_strings));
uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct));
fdt_scan_helper(lex, strings, 0, cb);
}
uint32_t fdt_size(uintptr_t fdt)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return 0;
return bswap(header->totalsize);
}
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->address_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->size_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str)
{
const char *list = (const char *)prop->value;
const char *end = list + prop->len;
int index = 0;
while (end - list > 0) {
if (!strcmp(list, str)) return index;
++index;
list += strlen(list) + 1;
}
return -1;
}
//////////////////////////////////////////// MEMORY SCAN /////////////////////////////////////////
struct mem_scan {
int memory;
const uint32_t *reg_value;
int reg_len;
};
static void mem_open(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void mem_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) {
scan->memory = 1;
} else if (!strcmp(prop->name, "reg")) {
scan->reg_value = prop->value;
scan->reg_len = prop->len;
}
}
static void mem_done(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
const uint32_t *value = scan->reg_value;
const uint32_t *end = value + scan->reg_len/4;
uintptr_t self = (uintptr_t)mem_done;
if (!scan->memory) return;
assert (scan->reg_value && scan->reg_len % 4 == 0);
while (end - value > 0) {
uint64_t base, size;
value = fdt_get_address(node->parent, value, &base);
value = fdt_get_size (node->parent, value, &size);
if (base <= self && self <= base + size) { mem_size = size; }
}
assert (end == value);
}
void query_mem(uintptr_t fdt)
{
struct fdt_cb cb;
struct mem_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = mem_open;
cb.prop = mem_prop;
cb.done = mem_done;
cb.extra = &scan;
mem_size = 0;
fdt_scan(fdt, &cb);
assert (mem_size > 0);
}
///////////////////////////////////////////// HART SCAN //////////////////////////////////////////
static uint32_t hart_phandles[MAX_HARTS];
uint64_t hart_mask;
struct hart_scan {
const struct fdt_scan_node *cpu;
int hart;
const struct fdt_scan_node *controller;
int cells;
uint32_t phandle;
};
static void hart_open(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (!scan->cpu) {
scan->hart = -1;
}
if (!scan->controller) {
scan->cells = 0;
scan->phandle = 0;
}
}
static void hart_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) {
assert (!scan->cpu);
scan->cpu = prop->node;
} else if (!strcmp(prop->name, "interrupt-controller")) {
assert (!scan->controller);
scan->controller = prop->node;
} else if (!strcmp(prop->name, "#interrupt-cells")) {
scan->cells = bswap(prop->value[0]);
} else if (!strcmp(prop->name, "phandle")) {
scan->phandle = bswap(prop->value[0]);
} else if (!strcmp(prop->name, "reg")) {
uint64_t reg;
fdt_get_address(prop->node->parent, prop->value, &reg);
scan->hart = reg;
}
}
static void hart_done(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (scan->cpu == node) {
assert (scan->hart >= 0);
}
if (scan->controller == node && scan->cpu) {
assert (scan->phandle > 0);
assert (scan->cells == 1);
if (scan->hart < MAX_HARTS) {
hart_phandles[scan->hart] = scan->phandle;
hart_mask |= 1 << scan->hart;
hls_init(scan->hart);
}
}
}
static int hart_close(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (scan->cpu == node) scan->cpu = 0;
if (scan->controller == node) scan->controller = 0;
return 0;
}
void query_harts(uintptr_t fdt)
{
struct fdt_cb cb;
struct hart_scan scan;
memset(&cb, 0, sizeof(cb));
memset(&scan, 0, sizeof(scan));
cb.open = hart_open;
cb.prop = hart_prop;
cb.done = hart_done;
cb.close= hart_close;
cb.extra = &scan;
fdt_scan(fdt, &cb);
// The current hart should have been detected
assert ((hart_mask >> read_csr(mhartid)) != 0);
}
///////////////////////////////////////////// CLINT SCAN /////////////////////////////////////////
struct clint_scan
{
int compat;
uint64_t reg;
const uint32_t *int_value;
int int_len;
int done;
};
static void clint_open(const struct fdt_scan_node *node, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
scan->compat = 0;
scan->reg = 0;
scan->int_value = 0;
}
static void clint_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,clint0") >= 0) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
} else if (!strcmp(prop->name, "interrupts-extended")) {
scan->int_value = prop->value;
scan->int_len = prop->len;
}
}
static void clint_done(const struct fdt_scan_node *node, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
const uint32_t *value = scan->int_value;
const uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
assert (scan->reg != 0);
assert (scan->int_value && scan->int_len % 16 == 0);
assert (!scan->done); // only one clint
scan->done = 1;
mtime = (void*)((uintptr_t)scan->reg + 0xbff8);
for (int index = 0; end - value > 0; ++index) {
uint32_t phandle = bswap(value[0]);
int hart;
for (hart = 0; hart < MAX_HARTS; ++hart)
if (hart_phandles[hart] == phandle)
break;
if (hart < MAX_HARTS) {
hls_t *hls = OTHER_HLS(hart);
hls->ipi = (void*)((uintptr_t)scan->reg + index * 4);
hls->timecmp = (void*)((uintptr_t)scan->reg + 0x4000 + (index * 8));
}
value += 4;
}
}
void query_clint(uintptr_t fdt)
{
struct fdt_cb cb;
struct clint_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = clint_open;
cb.prop = clint_prop;
cb.done = clint_done;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
assert (scan.done);
}
///////////////////////////////////////////// PLIC SCAN /////////////////////////////////////////
struct plic_scan
{
int compat;
uint64_t reg;
uint32_t *int_value;
int int_len;
int done;
int ndev;
};
static void plic_open(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
scan->compat = 0;
scan->reg = 0;
scan->int_value = 0;
}
static void plic_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,plic0") >= 0) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
} else if (!strcmp(prop->name, "interrupts-extended")) {
scan->int_value = prop->value;
scan->int_len = prop->len;
} else if (!strcmp(prop->name, "riscv,ndev")) {
scan->ndev = bswap(prop->value[0]);
}
}
#define HART_BASE 0x200000
#define HART_SIZE 0x1000
#define ENABLE_BASE 0x2000
#define ENABLE_SIZE 0x80
static void plic_done(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
const uint32_t *value = scan->int_value;
const uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
assert (scan->reg != 0);
assert (scan->int_value && scan->int_len % 8 == 0);
assert (scan->ndev >= 0 && scan->ndev < 1024);
assert (!scan->done); // only one plic
scan->done = 1;
plic_priorities = (uint32_t*)(uintptr_t)scan->reg;
plic_ndevs = scan->ndev;
for (int index = 0; end - value > 0; ++index) {
uint32_t phandle = bswap(value[0]);
uint32_t cpu_int = bswap(value[1]);
int hart;
for (hart = 0; hart < MAX_HARTS; ++hart)
if (hart_phandles[hart] == phandle)
break;
if (hart < MAX_HARTS) {
hls_t *hls = OTHER_HLS(hart);
if (cpu_int == IRQ_M_EXT) {
hls->plic_m_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
hls->plic_m_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index);
} else if (cpu_int == IRQ_S_EXT) {
hls->plic_s_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
hls->plic_s_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index);
} else {
printm("PLIC wired hart %d to wrong interrupt %d", hart, cpu_int);
}
}
value += 2;
}
#if 0
printm("PLIC: prio %x devs %d\r\n", (uint32_t)(uintptr_t)plic_priorities, plic_ndevs);
for (int i = 0; i < MAX_HARTS; ++i) {
hls_t *hls = OTHER_HLS(i);
printm("CPU %d: %x %x %x %x\r\n", i, (uint32_t)(uintptr_t)hls->plic_m_ie, (uint32_t)(uintptr_t)hls->plic_m_thresh, (uint32_t)(uintptr_t)hls->plic_s_ie, (uint32_t)(uintptr_t)hls->plic_s_thresh);
}
#endif
}
void query_plic(uintptr_t fdt)
{
struct fdt_cb cb;
struct plic_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = plic_open;
cb.prop = plic_prop;
cb.done = plic_done;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
}
static void plic_redact(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
uint32_t *value = scan->int_value;
uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
scan->done = 1;
while (end - value > 0) {
if (bswap(value[1]) == IRQ_M_EXT) value[1] = bswap(-1);
value += 2;
}
}
void filter_plic(uintptr_t fdt)
{
struct fdt_cb cb;
struct plic_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = plic_open;
cb.prop = plic_prop;
cb.done = plic_redact;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// COMPAT SCAN ////////////////////////////////////////
struct compat_scan
{
const char *compat;
int depth;
int kill;
};
static void compat_open(const struct fdt_scan_node *node, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
++scan->depth;
}
static void compat_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, scan->compat) >= 0)
if (scan->depth < scan->kill)
scan->kill = scan->depth;
}
static int compat_close(const struct fdt_scan_node *node, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
if (scan->kill == scan->depth--) {
scan->kill = 999;
return -1;
} else {
return 0;
}
}
void filter_compat(uintptr_t fdt, const char *compat)
{
struct fdt_cb cb;
struct compat_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = compat_open;
cb.prop = compat_prop;
cb.close = compat_close;
cb.extra = &scan;
scan.compat = compat;
scan.depth = 0;
scan.kill = 999;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// HART FILTER ////////////////////////////////////////
struct hart_filter {
int compat;
int hart;
char *status;
char *mmu_type;
long *disabled_hart_mask;
};
static void hart_filter_open(const struct fdt_scan_node *node, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
filter->status = NULL;
filter->mmu_type = NULL;
filter->compat = 0;
filter->hart = -1;
}
static void hart_filter_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) {
filter->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
uint64_t reg;
fdt_get_address(prop->node->parent, prop->value, &reg);
filter->hart = reg;
} else if (!strcmp(prop->name, "status")) {
filter->status = (char*)prop->value;
} else if (!strcmp(prop->name, "mmu-type")) {
filter->mmu_type = (char*)prop->value;
}
}
static bool hart_filter_mask(const struct hart_filter *filter)
{
if (filter->mmu_type == NULL) return true;
if (strcmp(filter->status, "okay")) return true;
if (!strcmp(filter->mmu_type, "riscv,sv39")) return false;
if (!strcmp(filter->mmu_type, "riscv,sv48")) return false;
printm("hart_filter_mask saw unknown hart type: status=\"%s\", mmu_type=\"%s\"\n",
filter->status, filter->mmu_type);
return true;
}
static void hart_filter_done(const struct fdt_scan_node *node, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
if (!filter->compat) return;
assert (filter->status);
assert (filter->hart >= 0);
if (hart_filter_mask(filter)) {
strcpy(filter->status, "masked");
uint32_t *len = (uint32_t*)filter->status;
len[-2] = bswap(strlen("masked")+1);
*filter->disabled_hart_mask |= (1 << filter->hart);
}
}
void filter_harts(uintptr_t fdt, long *disabled_hart_mask)
{
struct fdt_cb cb;
struct hart_filter filter;
memset(&cb, 0, sizeof(cb));
cb.open = hart_filter_open;
cb.prop = hart_filter_prop;
cb.done = hart_filter_done;
cb.extra = &filter;
filter.disabled_hart_mask = disabled_hart_mask;
*disabled_hart_mask = 0;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// PRINT //////////////////////////////////////////////
#ifdef PK_PRINT_DEVICE_TREE
#define FDT_PRINT_MAX_DEPTH 32
struct fdt_print_info {
int depth;
const struct fdt_scan_node *stack[FDT_PRINT_MAX_DEPTH];
};
void fdt_print_printm(struct fdt_print_info *info, const char *format, ...)
{
va_list vl;
for (int i = 0; i < info->depth; ++i)
printm(" ");
va_start(vl, format);
vprintm(format, vl);
va_end(vl);
}
static void fdt_print_open(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
while (node->parent != NULL && info->stack[info->depth-1] != node->parent) {
info->depth--;
fdt_print_printm(info, "}\r\n");
}
fdt_print_printm(info, "%s {\r\n", node->name);
info->stack[info->depth] = node;
info->depth++;
}
static void fdt_print_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
int asstring = 1;
char *char_data = (char *)(prop->value);
fdt_print_printm(info, "%s", prop->name);
if (prop->len == 0) {
printm(";\r\n");
return;
} else {
printm(" = ");
}
/* It appears that dtc uses a hueristic to detect strings so I'm using a
* similar one here. */
for (int i = 0; i < prop->len; ++i) {
if (!isstring(char_data[i]))
asstring = 0;
if (i > 0 && char_data[i] == '\0' && char_data[i-1] == '\0')
asstring = 0;
}
if (asstring) {
for (size_t i = 0; i < prop->len; i += strlen(char_data + i) + 1) {
if (i != 0)
printm(", ");
printm("\"%s\"", char_data + i);
}
} else {
printm("<");
for (size_t i = 0; i < prop->len/4; ++i) {
if (i != 0)
printm(" ");
printm("0x%08x", bswap(prop->value[i]));
}
printm(">");
}
printm(";\r\n");
}
static void fdt_print_done(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
}
static int fdt_print_close(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
return 0;
}
void fdt_print(uintptr_t fdt)
{
struct fdt_print_info info;
struct fdt_cb cb;
info.depth = 0;
memset(&cb, 0, sizeof(cb));
cb.open = fdt_print_open;
cb.prop = fdt_print_prop;
cb.done = fdt_print_done;
cb.close = fdt_print_close;
cb.extra = &info;
fdt_scan(fdt, &cb);
while (info.depth > 0) {
info.depth--;
fdt_print_printm(&info, "}\r\n");
}
}
#endif

76
riscv-pk/machine/fdt.h Normal file
View File

@ -0,0 +1,76 @@
#ifndef FDT_H
#define FDT_H
#define FDT_MAGIC 0xd00dfeed
#define FDT_VERSION 17
struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version; /* <= 17 */
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
#define FDT_BEGIN_NODE 1
#define FDT_END_NODE 2
#define FDT_PROP 3
#define FDT_NOP 4
#define FDT_END 9
struct fdt_scan_node {
const struct fdt_scan_node *parent;
const char *name;
int address_cells;
int size_cells;
};
struct fdt_scan_prop {
const struct fdt_scan_node *node;
const char *name;
uint32_t *value;
int len; // in bytes of value
};
struct fdt_cb {
void (*open)(const struct fdt_scan_node *node, void *extra);
void (*prop)(const struct fdt_scan_prop *prop, void *extra);
void (*done)(const struct fdt_scan_node *node, void *extra); // last property was seen
int (*close)(const struct fdt_scan_node *node, void *extra); // -1 => delete the node + children
void *extra;
};
// Scan the contents of FDT
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb);
uint32_t fdt_size(uintptr_t fdt);
// Extract fields
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found
// Setup memory+clint+plic
void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
// Remove information from FDT
void filter_harts(uintptr_t fdt, long *disabled_hart_mask);
void filter_plic(uintptr_t fdt);
void filter_compat(uintptr_t fdt, const char *compat);
// The hartids of available harts
extern uint64_t hart_mask;
#ifdef PK_PRINT_DEVICE_TREE
// Prints the device tree to the console as a DTS
void fdt_print(uintptr_t fdt);
#endif
#endif

View File

@ -0,0 +1,58 @@
#include <string.h>
#include "finisher.h"
#include "fdt.h"
volatile uint32_t* finisher;
void finisher_exit(uint16_t code)
{
if (!finisher) return;
if (code == 0) {
*finisher = FINISHER_PASS;
} else {
*finisher = code << 16 | FINISHER_FAIL;
}
}
struct finisher_scan
{
int compat;
uint64_t reg;
};
static void finisher_open(const struct fdt_scan_node *node, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void finisher_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,test0")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void finisher_done(const struct fdt_scan_node *node, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
if (!scan->compat || !scan->reg || finisher) return;
finisher = (uint32_t*)(uintptr_t)scan->reg;
}
void query_finisher(uintptr_t fdt)
{
struct fdt_cb cb;
struct finisher_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = finisher_open;
cb.prop = finisher_prop;
cb.done = finisher_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -0,0 +1,13 @@
#ifndef _RISCV_FINISHER_H
#define _RISCV_FINISHER_H
#include <stdint.h>
#define FINISHER_REG_FINISH 0
#define FINISHER_FAIL 0x3333
#define FINISHER_PASS 0x5555
void finisher_exit(uint16_t code);
void query_finisher(uintptr_t fdt);
#endif

View File

@ -0,0 +1,3 @@
void __riscv_flush_icache(void) {
__asm__ volatile ("fence.i");
}

138
riscv-pk/machine/htif.c Normal file
View File

@ -0,0 +1,138 @@
#include "htif.h"
#include "atomic.h"
#include "mtrap.h"
#include "fdt.h"
#include <string.h>
extern uint64_t __htif_base;
volatile uint64_t tohost __attribute__((section(".htif")));
volatile uint64_t fromhost __attribute__((section(".htif")));
volatile int htif_console_buf;
static spinlock_t htif_lock = SPINLOCK_INIT;
uintptr_t htif;
#define TOHOST(base_int) (uint64_t *)(base_int + TOHOST_OFFSET)
#define FROMHOST(base_int) (uint64_t *)(base_int + FROMHOST_OFFSET)
#define TOHOST_OFFSET ((uintptr_t)tohost - (uintptr_t)__htif_base)
#define FROMHOST_OFFSET ((uintptr_t)fromhost - (uintptr_t)__htif_base)
static void __check_fromhost()
{
uint64_t fh = fromhost;
if (!fh)
return;
fromhost = 0;
// this should be from the console
assert(FROMHOST_DEV(fh) == 1);
switch (FROMHOST_CMD(fh)) {
case 0:
htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
break;
case 1:
break;
default:
assert(0);
}
}
static void __set_tohost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
{
while (tohost)
__check_fromhost();
tohost = TOHOST_CMD(dev, cmd, data);
}
int htif_console_getchar()
{
spinlock_lock(&htif_lock);
__check_fromhost();
int ch = htif_console_buf;
if (ch >= 0) {
htif_console_buf = -1;
__set_tohost(1, 0, 0);
}
spinlock_unlock(&htif_lock);
return ch - 1;
}
static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
{
spinlock_lock(&htif_lock);
__set_tohost(dev, cmd, data);
while (1) {
uint64_t fh = fromhost;
if (fh) {
if (FROMHOST_DEV(fh) == dev && FROMHOST_CMD(fh) == cmd) {
fromhost = 0;
break;
}
__check_fromhost();
}
}
spinlock_unlock(&htif_lock);
}
void htif_syscall(uintptr_t arg)
{
do_tohost_fromhost(0, 0, arg);
}
void htif_console_putchar(uint8_t ch)
{
spinlock_lock(&htif_lock);
__set_tohost(1, 1, ch);
spinlock_unlock(&htif_lock);
}
void htif_poweroff()
{
while (1) {
fromhost = 0;
tohost = 1;
}
}
struct htif_scan
{
int compat;
};
static void htif_open(const struct fdt_scan_node *node, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void htif_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ucb,htif0")) {
scan->compat = 1;
}
}
static void htif_done(const struct fdt_scan_node *node, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
if (!scan->compat) return;
htif = 1;
}
void query_htif(uintptr_t fdt)
{
struct fdt_cb cb;
struct htif_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = htif_open;
cb.prop = htif_prop;
cb.done = htif_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

25
riscv-pk/machine/htif.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _RISCV_HTIF_H
#define _RISCV_HTIF_H
#include <stdint.h>
#if __riscv_xlen == 64
# define TOHOST_CMD(dev, cmd, payload) \
(((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload))
#else
# define TOHOST_CMD(dev, cmd, payload) ({ \
if ((dev) || (cmd)) __builtin_trap(); \
(payload); })
#endif
#define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56)
#define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56)
#define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16)
extern uintptr_t htif;
void query_htif(uintptr_t dtb);
void htif_console_putchar(uint8_t);
int htif_console_getchar();
void htif_poweroff() __attribute__((noreturn));
void htif_syscall(uintptr_t);
#endif

View File

@ -0,0 +1,4 @@
AC_ARG_ENABLE([fp-emulation], AS_HELP_STRING([--disable-fp-emulation], [Disable floating-point emulation]))
AS_IF([test "x$enable_fp_emulation" != "xno"], [
AC_DEFINE([PK_ENABLE_FP_EMULATION],,[Define if floating-point emulation is enabled])
])

View File

@ -0,0 +1,30 @@
machine_hdrs = \
atomic.h \
bits.h \
fdt.h \
emulation.h \
encoding.h \
htif.h \
mcall.h \
mtrap.h \
uart.h \
uart16550.h \
finisher.h \
unprivileged_memory.h \
vm.h \
machine_c_srcs = \
fdt.c \
mtrap.c \
minit.c \
htif.c \
emulation.c \
muldiv_emulation.c \
uart.c \
uart16550.c \
finisher.c \
misaligned_ldst.c \
flush_icache.c \
machine_asm_srcs = \
mentry.S \

14
riscv-pk/machine/mcall.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _RISCV_SBI_H
#define _RISCV_SBI_H
#define SBI_SET_TIMER 0
#define SBI_CONSOLE_PUTCHAR 1
#define SBI_CONSOLE_GETCHAR 2
#define SBI_CLEAR_IPI 3
#define SBI_SEND_IPI 4
#define SBI_REMOTE_FENCE_I 5
#define SBI_REMOTE_SFENCE_VMA 6
#define SBI_REMOTE_SFENCE_VMA_ASID 7
#define SBI_SHUTDOWN 8
#endif

295
riscv-pk/machine/mentry.S Normal file
View File

@ -0,0 +1,295 @@
// See LICENSE for license details.
#include "mtrap.h"
#include "bits.h"
.data
.align 6
trap_table:
#define BAD_TRAP_VECTOR 0
.word bad_trap
.word pmp_trap
.word illegal_insn_trap
.word bad_trap
.word misaligned_load_trap
.word pmp_trap
.word misaligned_store_trap
.word pmp_trap
.word bad_trap
.word mcall_trap
.word bad_trap
.word bad_trap
.word bad_trap
#define TRAP_FROM_MACHINE_MODE_VECTOR 13
.word __trap_from_machine_mode
.word bad_trap
.word bad_trap
.option norvc
.section .text.init,"ax",@progbits
.globl reset_vector
reset_vector:
j do_reset
trap_vector:
csrrw sp, mscratch, sp
beqz sp, .Ltrap_from_machine_mode
STORE a0, 10*REGBYTES(sp)
STORE a1, 11*REGBYTES(sp)
csrr a1, mcause
bgez a1, .Lhandle_trap_in_machine_mode
# This is an interrupt. Discard the mcause MSB and decode the rest.
sll a1, a1, 1
# Is it a machine timer interrupt?
li a0, IRQ_M_TIMER * 2
bne a0, a1, 1f
# Yes. Simply clear MSIE and raise SSIP.
li a0, MIP_MTIP
csrc mie, a0
li a0, MIP_STIP
csrs mip, a0
.Lmret:
# Go back whence we came.
LOAD a0, 10*REGBYTES(sp)
LOAD a1, 11*REGBYTES(sp)
csrrw sp, mscratch, sp
mret
1:
# Is it an IPI?
li a0, IRQ_M_SOFT * 2
bne a0, a1, .Lbad_trap
# Yes. First, clear the MIPI bit.
LOAD a0, MENTRY_IPI_OFFSET(sp)
sw x0, (a0)
fence
# Now, decode the cause(s).
#ifdef __riscv_atomic
addi a0, sp, MENTRY_IPI_PENDING_OFFSET
amoswap.w a0, x0, (a0)
#else
lw a0, MENTRY_IPI_PENDING_OFFSET(a0)
sw x0, MENTRY_IPI_PENDING_OFFSET(a0)
#endif
and a1, a0, IPI_SOFT
beqz a1, 1f
csrs mip, MIP_SSIP
1:
andi a1, a0, IPI_FENCE_I
beqz a1, 1f
fence.i
1:
andi a1, a0, IPI_SFENCE_VMA
beqz a1, 1f
sfence.vma
1:
j .Lmret
.Lhandle_trap_in_machine_mode:
# Preserve the registers. Compute the address of the trap handler.
STORE ra, 1*REGBYTES(sp)
STORE gp, 3*REGBYTES(sp)
STORE tp, 4*REGBYTES(sp)
STORE t0, 5*REGBYTES(sp)
1:auipc t0, %pcrel_hi(trap_table) # t0 <- %hi(trap_table)
STORE t1, 6*REGBYTES(sp)
sll t1, a1, 2 # t1 <- mcause << 2
STORE t2, 7*REGBYTES(sp)
add t1, t0, t1 # t1 <- %hi(trap_table)[mcause]
STORE s0, 8*REGBYTES(sp)
LWU t1, %pcrel_lo(1b)(t1) # t1 <- trap_table[mcause]
STORE s1, 9*REGBYTES(sp)
mv a0, sp # a0 <- regs
STORE a2,12*REGBYTES(sp)
csrr a2, mepc # a2 <- mepc
STORE a3,13*REGBYTES(sp)
csrrw t0, mscratch, x0 # t0 <- user sp
STORE a4,14*REGBYTES(sp)
STORE a5,15*REGBYTES(sp)
STORE a6,16*REGBYTES(sp)
STORE a7,17*REGBYTES(sp)
STORE s2,18*REGBYTES(sp)
STORE s3,19*REGBYTES(sp)
STORE s4,20*REGBYTES(sp)
STORE s5,21*REGBYTES(sp)
STORE s6,22*REGBYTES(sp)
STORE s7,23*REGBYTES(sp)
STORE s8,24*REGBYTES(sp)
STORE s9,25*REGBYTES(sp)
STORE s10,26*REGBYTES(sp)
STORE s11,27*REGBYTES(sp)
STORE t3,28*REGBYTES(sp)
STORE t4,29*REGBYTES(sp)
STORE t5,30*REGBYTES(sp)
STORE t6,31*REGBYTES(sp)
STORE t0, 2*REGBYTES(sp) # sp
#ifndef __riscv_flen
lw tp, (sp) # Move the emulated FCSR from x0's save slot into tp.
#endif
STORE x0, (sp) # Zero x0's save slot.
# Invoke the handler.
jalr t1
#ifndef __riscv_flen
sw tp, (sp) # Move the emulated FCSR from tp into x0's save slot.
#endif
restore_mscratch:
# Restore mscratch, so future traps will know they didn't come from M-mode.
csrw mscratch, sp
restore_regs:
# Restore all of the registers.
LOAD ra, 1*REGBYTES(sp)
LOAD gp, 3*REGBYTES(sp)
LOAD tp, 4*REGBYTES(sp)
LOAD t0, 5*REGBYTES(sp)
LOAD t1, 6*REGBYTES(sp)
LOAD t2, 7*REGBYTES(sp)
LOAD s0, 8*REGBYTES(sp)
LOAD s1, 9*REGBYTES(sp)
LOAD a0,10*REGBYTES(sp)
LOAD a1,11*REGBYTES(sp)
LOAD a2,12*REGBYTES(sp)
LOAD a3,13*REGBYTES(sp)
LOAD a4,14*REGBYTES(sp)
LOAD a5,15*REGBYTES(sp)
LOAD a6,16*REGBYTES(sp)
LOAD a7,17*REGBYTES(sp)
LOAD s2,18*REGBYTES(sp)
LOAD s3,19*REGBYTES(sp)
LOAD s4,20*REGBYTES(sp)
LOAD s5,21*REGBYTES(sp)
LOAD s6,22*REGBYTES(sp)
LOAD s7,23*REGBYTES(sp)
LOAD s8,24*REGBYTES(sp)
LOAD s9,25*REGBYTES(sp)
LOAD s10,26*REGBYTES(sp)
LOAD s11,27*REGBYTES(sp)
LOAD t3,28*REGBYTES(sp)
LOAD t4,29*REGBYTES(sp)
LOAD t5,30*REGBYTES(sp)
LOAD t6,31*REGBYTES(sp)
LOAD sp, 2*REGBYTES(sp)
mret
.Ltrap_from_machine_mode:
csrr sp, mscratch
addi sp, sp, -INTEGER_CONTEXT_SIZE
STORE a0,10*REGBYTES(sp)
STORE a1,11*REGBYTES(sp)
li a1, TRAP_FROM_MACHINE_MODE_VECTOR
j .Lhandle_trap_in_machine_mode
.Lbad_trap:
li a1, BAD_TRAP_VECTOR
j .Lhandle_trap_in_machine_mode
.globl __redirect_trap
__redirect_trap:
# reset sp to top of M-mode stack
li t0, MACHINE_STACK_SIZE
add sp, sp, t0
neg t0, t0
and sp, sp, t0
addi sp, sp, -MENTRY_FRAME_SIZE
j restore_mscratch
__trap_from_machine_mode:
jal trap_from_machine_mode
j restore_regs
do_reset:
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
// save a0 and a1; arguments from previous boot loader stage:
// li x10, 0
// li x11, 0
li x12, 0
li x13, 0
li x14, 0
li x15, 0
li x16, 0
li x17, 0
li x18, 0
li x19, 0
li x20, 0
li x21, 0
li x22, 0
li x23, 0
li x24, 0
li x25, 0
li x26, 0
li x27, 0
li x28, 0
li x29, 0
li x30, 0
li x31, 0
csrw mscratch, x0
# write mtvec and make sure it sticks
la t0, trap_vector
csrw mtvec, t0
csrr t1, mtvec
1:bne t0, t1, 1b
la sp, stacks + RISCV_PGSIZE - MENTRY_FRAME_SIZE
csrr a3, mhartid
slli a2, a3, RISCV_PGSHIFT
add sp, sp, a2
# Boot on the first hart
beqz a3, init_first_hart
# set MSIE bit to receive IPI
li a2, MIP_MSIP
csrw mie, a2
.LmultiHart:
#if MAX_HARTS > 1
# wait for an IPI to signal that it's safe to boot
wfi
# masked harts never start
la a4, disabled_hart_mask
LOAD a4, 0(a4)
srl a4, a4, a3
andi a4, a4, 1
bnez a4, .LmultiHart
# only start if mip is set
csrr a2, mip
andi a2, a2, MIP_MSIP
beqz a2, .LmultiHart
# make sure our hart id is within a valid range
fence
li a2, MAX_HARTS
bltu a3, a2, init_other_hart
#endif
wfi
j .LmultiHart
.bss
.align RISCV_PGSHIFT
stacks:
.skip RISCV_PGSIZE * MAX_HARTS

199
riscv-pk/machine/minit.c Normal file
View File

@ -0,0 +1,199 @@
#include "mtrap.h"
#include "atomic.h"
#include "vm.h"
//#include "fp_emulation.h"
#include "bits.h"
#include "fdt.h"
#include "uart.h"
#include "uart16550.h"
#include "finisher.h"
#include "disabled_hart_mask.h"
#include "htif.h"
#include <string.h>
#include <limits.h>
pte_t* root_page_table;
uintptr_t mem_size;
volatile uint64_t* mtime;
volatile uint32_t* plic_priorities;
size_t plic_ndevs;
static void mstatus_init()
{
// Enable FPU
if (supports_extension('D') || supports_extension('F'))
write_csr(mstatus, MSTATUS_FS);
// Enable user/supervisor use of perf counters
if (supports_extension('S'))
write_csr(scounteren, -1);
write_csr(mcounteren, -1);
// Enable software interrupts
write_csr(mie, MIP_MSIP);
// Disable paging
if (supports_extension('S'))
write_csr(sptbr, 0);
}
// send S-mode interrupts and most exceptions straight to S-mode
static void delegate_traps()
{
if (!supports_extension('S'))
return;
uintptr_t interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
uintptr_t exceptions =
(1U << CAUSE_MISALIGNED_FETCH) |
(1U << CAUSE_FETCH_PAGE_FAULT) |
(1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_LOAD_PAGE_FAULT) |
(1U << CAUSE_STORE_PAGE_FAULT) |
(1U << CAUSE_USER_ECALL);
write_csr(mideleg, interrupts);
write_csr(medeleg, exceptions);
assert(read_csr(mideleg) == interrupts);
assert(read_csr(medeleg) == exceptions);
}
static void fp_init()
{
if (!supports_extension('D') && !supports_extension('F'))
return;
assert(read_csr(mstatus) & MSTATUS_FS);
#ifdef __riscv_flen
// for (int i = 0; i < 32; i++)
// init_fp_reg(i);
// write_csr(fcsr, 0);
#else
uintptr_t fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
clear_csr(misa, fd_mask);
assert(!(read_csr(misa) & fd_mask));
#endif
}
hls_t* hls_init(uintptr_t id)
{
hls_t* hls = OTHER_HLS(id);
memset(hls, 0, sizeof(*hls));
return hls;
}
static void memory_init()
{
mem_size = mem_size / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
static void hart_init()
{
mstatus_init();
fp_init();
delegate_traps();
}
static void plic_init()
{
for (size_t i = 1; i <= plic_ndevs; i++)
plic_priorities[i] = 1;
}
static void prci_test()
{
assert(!(read_csr(mip) & MIP_MSIP));
*HLS()->ipi = 1;
assert(read_csr(mip) & MIP_MSIP);
*HLS()->ipi = 0;
assert(!(read_csr(mip) & MIP_MTIP));
*HLS()->timecmp = 0;
assert(read_csr(mip) & MIP_MTIP);
*HLS()->timecmp = -1ULL;
}
static void hart_plic_init()
{
// clear pending interrupts
*HLS()->ipi = 0;
*HLS()->timecmp = -1ULL;
write_csr(mip, 0);
if (!plic_ndevs)
return;
size_t ie_words = plic_ndevs / sizeof(uintptr_t) + 1;
for (size_t i = 0; i < ie_words; i++)
HLS()->plic_s_ie[i] = ULONG_MAX;
*HLS()->plic_m_thresh = 1;
*HLS()->plic_s_thresh = 0;
}
static void wake_harts()
{
for (int hart = 0; hart < MAX_HARTS; ++hart)
if ((((~disabled_hart_mask & hart_mask) >> hart) & 1))
*OTHER_HLS(hart)->ipi = 1; // wakeup the hart
}
void init_first_hart(uintptr_t hartid, uintptr_t dtb)
{
// Confirm console as early as possible
query_uart(dtb);
query_uart16550(dtb);
query_htif(dtb);
hart_init();
hls_init(0); // this might get called again from parse_config_string
// Find the power button early as well so die() works
query_finisher(dtb);
query_mem(dtb);
query_harts(dtb);
query_clint(dtb);
query_plic(dtb);
wake_harts();
plic_init();
hart_plic_init();
//prci_test();
memory_init();
boot_loader(dtb);
}
void init_other_hart(uintptr_t hartid, uintptr_t dtb)
{
hart_init();
hart_plic_init();
boot_other_hart(dtb);
}
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (-1UL) : "t0");
uintptr_t mstatus = read_csr(mstatus);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
write_csr(mstatus, mstatus);
write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE);
write_csr(mepc, fn);
register uintptr_t a0 asm ("a0") = arg0;
register uintptr_t a1 asm ("a1") = arg1;
asm volatile ("mret" : : "r" (a0), "r" (a1));
__builtin_unreachable();
}

View File

@ -0,0 +1,143 @@
#include "emulation.h"
//#include "fp_emulation.h"
#include "unprivileged_memory.h"
#include "mtrap.h"
#include "config.h"
//#include "pk.h"
union byte_array {
uint8_t bytes[8];
uintptr_t intx;
uint64_t int64;
};
static inline int insn_len(long insn)
{
return (insn & 0x3) < 0x3 ? 2 : 4;
}
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
union byte_array val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
uintptr_t npc = mepc + insn_len(insn);
uintptr_t addr = read_csr(mbadaddr);
int shift = 0, fp = 0, len;
if ((insn & MASK_LW) == MATCH_LW)
len = 4, shift = 8*(sizeof(uintptr_t) - len);
#if __riscv_xlen == 64
else if ((insn & MASK_LD) == MATCH_LD)
len = 8, shift = 8*(sizeof(uintptr_t) - len);
else if ((insn & MASK_LWU) == MATCH_LWU)
len = 4;
#endif
#ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_FLD) == MATCH_FLD)
fp = 1, len = 8;
else if ((insn & MASK_FLW) == MATCH_FLW)
fp = 1, len = 4;
#endif
else if ((insn & MASK_LH) == MATCH_LH)
len = 2, shift = 8*(sizeof(uintptr_t) - len);
else if ((insn & MASK_LHU) == MATCH_LHU)
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
else if ((insn & MASK_C_LD) == MATCH_C_LD)
len = 8, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_LDSP) == MATCH_C_LDSP && ((insn >> SH_RD) & 0x1f))
len = 8, shift = 8*(sizeof(uintptr_t) - len);
# endif
else if ((insn & MASK_C_LW) == MATCH_C_LW)
len = 4, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_LWSP) == MATCH_C_LWSP && ((insn >> SH_RD) & 0x1f))
len = 4, shift = 8*(sizeof(uintptr_t) - len);
# ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_C_FLD) == MATCH_C_FLD)
fp = 1, len = 8, insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_FLDSP) == MATCH_C_FLDSP)
fp = 1, len = 8;
# if __riscv_xlen == 32
else if ((insn & MASK_C_FLW) == MATCH_C_FLW)
fp = 1, len = 4, insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_FLWSP) == MATCH_C_FLWSP)
fp = 1, len = 4;
# endif
# endif
#endif
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
val.int64 = 0;
for (intptr_t i = 0; i < len; i++)
val.bytes[i] = load_uint8_t((void *)(addr + i), mepc);
if (!fp)
SET_RD(insn, regs, (intptr_t)val.intx << shift >> shift);
#ifdef PK_ENABLE_FP_EMULATION
else if (len == 8)
SET_F64_RD(insn, regs, val.int64);
else
SET_F32_RD(insn, regs, val.intx);
#endif
write_csr(mepc, npc);
}
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
union byte_array val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
uintptr_t npc = mepc + insn_len(insn);
int len;
val.intx = GET_RS2(insn, regs);
if ((insn & MASK_SW) == MATCH_SW)
len = 4;
#if __riscv_xlen == 64
else if ((insn & MASK_SD) == MATCH_SD)
len = 8;
#endif
#ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_FSD) == MATCH_FSD)
len = 8, val.int64 = GET_F64_RS2(insn, regs);
else if ((insn & MASK_FSW) == MATCH_FSW)
len = 4, val.intx = GET_F32_RS2(insn, regs);
#endif
else if ((insn & MASK_SH) == MATCH_SH)
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
else if ((insn & MASK_C_SD) == MATCH_C_SD)
len = 8, val.intx = GET_RS2S(insn, regs);
else if ((insn & MASK_C_SDSP) == MATCH_C_SDSP && ((insn >> SH_RD) & 0x1f))
len = 8, val.intx = GET_RS2C(insn, regs);
# endif
else if ((insn & MASK_C_SW) == MATCH_C_SW)
len = 4, val.intx = GET_RS2S(insn, regs);
else if ((insn & MASK_C_SWSP) == MATCH_C_SWSP && ((insn >> SH_RD) & 0x1f))
len = 4, val.intx = GET_RS2C(insn, regs);
# ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_C_FSD) == MATCH_C_FSD)
len = 8, val.int64 = GET_F64_RS2S(insn, regs);
else if ((insn & MASK_C_FSDSP) == MATCH_C_FSDSP)
len = 8, val.int64 = GET_F64_RS2C(insn, regs);
# if __riscv_xlen == 32
else if ((insn & MASK_C_FSW) == MATCH_C_FSW)
len = 4, val.intx = GET_F32_RS2S(insn, regs);
else if ((insn & MASK_C_FSWSP) == MATCH_C_FSWSP)
len = 4, val.intx = GET_F32_RS2C(insn, regs);
# endif
# endif
#endif
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
uintptr_t addr = read_csr(mbadaddr);
for (int i = 0; i < len; i++)
store_uint8_t((void *)(addr + i), val.bytes[i], mepc);
write_csr(mepc, npc);
}

235
riscv-pk/machine/mtrap.c Normal file
View File

@ -0,0 +1,235 @@
#include "mtrap.h"
#include "mcall.h"
#include "htif.h"
#include "atomic.h"
#include "bits.h"
#include "vm.h"
#include "uart.h"
#include "uart16550.h"
#include "finisher.h"
#include "fdt.h"
#include "unprivileged_memory.h"
#include "disabled_hart_mask.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
void __attribute__((noreturn)) bad_trap(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
die("machine mode: unhandlable trap %d @ %p", read_csr(mcause), mepc);
}
static uintptr_t mcall_console_putchar(uint8_t ch)
{
if (uart) {
uart_putchar(ch);
} else if (uart16550) {
uart16550_putchar(ch);
} else if (htif) {
htif_console_putchar(ch);
}
return 0;
}
void poweroff(uint16_t code)
{
printm("Power off\n");
finisher_exit(code);
if (htif) {
htif_poweroff();
} else {
while (1) { asm volatile ("#noop\n"); }
}
}
void putstring(const char* s)
{
while (*s)
mcall_console_putchar(*s++);
}
void vprintm(const char* s, va_list vl)
{
char buf[256];
vsnprintf(buf, sizeof buf, s, vl);
putstring(buf);
}
void printm(const char* s, ...)
{
va_list vl;
va_start(vl, s);
vprintm(s, vl);
va_end(vl);
}
static void send_ipi(uintptr_t recipient, int event)
{
if (((disabled_hart_mask >> recipient) & 1)) return;
atomic_or(&OTHER_HLS(recipient)->mipi_pending, event);
mb();
*OTHER_HLS(recipient)->ipi = 1;
}
static uintptr_t mcall_console_getchar()
{
if (uart) {
return uart_getchar();
} else if (uart16550) {
return uart16550_getchar();
} else if (htif) {
return htif_console_getchar();
} else {
return '\0';
}
}
static uintptr_t mcall_clear_ipi()
{
return clear_csr(mip, MIP_SSIP) & MIP_SSIP;
}
static uintptr_t mcall_shutdown()
{
poweroff(0);
}
static uintptr_t mcall_set_timer(uint64_t when)
{
*HLS()->timecmp = when;
clear_csr(mip, MIP_STIP);
set_csr(mie, MIP_MTIP);
return 0;
}
static void send_ipi_many(uintptr_t* pmask, int event)
{
_Static_assert(MAX_HARTS <= 8 * sizeof(*pmask), "# harts > uintptr_t bits");
uintptr_t mask = hart_mask;
if (pmask)
mask &= load_uintptr_t(pmask, read_csr(mepc));
// send IPIs to everyone
for (uintptr_t i = 0, m = mask; m; i++, m >>= 1)
if (m & 1)
send_ipi(i, event);
if (event == IPI_SOFT)
return;
// wait until all events have been handled.
// prevent deadlock by consuming incoming IPIs.
uint32_t incoming_ipi = 0;
for (uintptr_t i = 0, m = mask; m; i++, m >>= 1)
if (m & 1)
while (*OTHER_HLS(i)->ipi)
incoming_ipi |= atomic_swap(HLS()->ipi, 0);
// if we got an IPI, restore it; it will be taken after returning
if (incoming_ipi) {
*HLS()->ipi = incoming_ipi;
mb();
}
}
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr);
void mcall_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
write_csr(mepc, mepc + 4);
uintptr_t n = regs[17], arg0 = regs[10], arg1 = regs[11], retval, ipi_type;
switch (n)
{
case SBI_CONSOLE_PUTCHAR:
retval = mcall_console_putchar(arg0);
break;
case SBI_CONSOLE_GETCHAR:
retval = mcall_console_getchar();
break;
case SBI_SEND_IPI:
ipi_type = IPI_SOFT;
goto send_ipi;
case SBI_REMOTE_SFENCE_VMA:
case SBI_REMOTE_SFENCE_VMA_ASID:
ipi_type = IPI_SFENCE_VMA;
goto send_ipi;
case SBI_REMOTE_FENCE_I:
ipi_type = IPI_FENCE_I;
send_ipi:
send_ipi_many((uintptr_t*)arg0, ipi_type);
retval = 0;
break;
case SBI_CLEAR_IPI:
retval = mcall_clear_ipi();
break;
case SBI_SHUTDOWN:
retval = mcall_shutdown();
break;
case SBI_SET_TIMER:
#if __riscv_xlen == 32
retval = mcall_set_timer(arg0 + ((uint64_t)arg1 << 32));
#else
retval = mcall_set_timer(arg0);
#endif
break;
default:
redirect_trap(read_csr(mepc), read_csr(mstatus), read_csr(mbadaddr));
retval = -ENOSYS;
break;
}
regs[10] = retval;
}
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr)
{
write_csr(sbadaddr, badaddr);
write_csr(sepc, epc);
write_csr(scause, read_csr(mcause));
write_csr(mepc, read_csr(stvec));
uintptr_t new_mstatus = mstatus & ~(MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
uintptr_t mpp_s = MSTATUS_MPP & (MSTATUS_MPP >> 1);
new_mstatus |= (mstatus * (MSTATUS_SPIE / MSTATUS_SIE)) & MSTATUS_SPIE;
new_mstatus |= (mstatus / (mpp_s / MSTATUS_SPP)) & MSTATUS_SPP;
new_mstatus |= mpp_s;
write_csr(mstatus, new_mstatus);
extern void __redirect_trap();
return __redirect_trap();
}
void pmp_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
redirect_trap(mepc, read_csr(mstatus), read_csr(mbadaddr));
}
static void machine_page_fault(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
// MPRV=1 iff this trap occurred while emulating an instruction on behalf
// of a lower privilege level. In that case, a2=epc and a3=mstatus.
if (read_csr(mstatus) & MSTATUS_MPRV) {
return redirect_trap(regs[12], regs[13], read_csr(mbadaddr));
}
bad_trap(regs, dummy, mepc);
}
void trap_from_machine_mode(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
uintptr_t mcause = read_csr(mcause);
switch (mcause)
{
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
case CAUSE_FETCH_ACCESS:
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
return machine_page_fault(regs, dummy, mepc);
default:
bad_trap(regs, dummy, mepc);
}
}

96
riscv-pk/machine/mtrap.h Normal file
View File

@ -0,0 +1,96 @@
#ifndef _RISCV_MTRAP_H
#define _RISCV_MTRAP_H
#include "encoding.h"
#ifdef __riscv_atomic
# define MAX_HARTS 8 // arbitrary
#else
# define MAX_HARTS 1
#endif
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#define read_const_csr(reg) ({ unsigned long __tmp; \
asm ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
static inline int supports_extension(char ext)
{
return read_const_csr(misa) & (1 << (ext - 'A'));
}
static inline int xlen()
{
return read_const_csr(misa) < 0 ? 64 : 32;
}
extern uintptr_t mem_size;
extern volatile uint64_t* mtime;
extern volatile uint32_t* plic_priorities;
extern size_t plic_ndevs;
typedef struct {
volatile uint32_t* ipi;
volatile int mipi_pending;
volatile uint64_t* timecmp;
volatile uint32_t* plic_m_thresh;
volatile uintptr_t* plic_m_ie;
volatile uint32_t* plic_s_thresh;
volatile uintptr_t* plic_s_ie;
} hls_t;
#define MACHINE_STACK_TOP() ({ \
register uintptr_t sp asm ("sp"); \
(void*)((sp + RISCV_PGSIZE) & -RISCV_PGSIZE); })
// hart-local storage, at top of stack
#define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE))
#define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid))))
hls_t* hls_init(uintptr_t hart_id);
void parse_config_string();
void poweroff(uint16_t code) __attribute((noreturn));
void printm(const char* s, ...);
void vprintm(const char *s, va_list args);
void putstring(const char* s);
#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); })
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
__attribute__((noreturn));
void boot_loader(uintptr_t dtb);
void boot_other_hart(uintptr_t dtb);
static inline void wfi()
{
asm volatile ("wfi" ::: "memory");
}
#endif // !__ASSEMBLER__
#define IPI_SOFT 0x1
#define IPI_FENCE_I 0x2
#define IPI_SFENCE_VMA 0x4
#define MACHINE_STACK_SIZE RISCV_PGSIZE
#define MENTRY_HLS_OFFSET (INTEGER_CONTEXT_SIZE + SOFT_FLOAT_CONTEXT_SIZE)
#define MENTRY_FRAME_SIZE (MENTRY_HLS_OFFSET + HLS_SIZE)
#define MENTRY_IPI_OFFSET (MENTRY_HLS_OFFSET)
#define MENTRY_IPI_PENDING_OFFSET (MENTRY_HLS_OFFSET + REGBYTES)
#ifdef __riscv_flen
# define SOFT_FLOAT_CONTEXT_SIZE 0
#else
# define SOFT_FLOAT_CONTEXT_SIZE (8 * 32)
#endif
#define HLS_SIZE 64
#define INTEGER_CONTEXT_SIZE (32 * REGBYTES)
#endif

View File

@ -0,0 +1,64 @@
#include "emulation.h"
#ifndef __riscv_muldiv
#if __riscv_xlen == 64
typedef __int128 double_int;
#else
typedef int64_t double_int;
#endif
// These routines rely on the compiler to turn these operations into libcalls
// when not natively supported. So work on making those go fast.
DECLARE_EMULATION_FUNC(emulate_mul_div)
{
uintptr_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs), val;
if ((insn & MASK_MUL) == MATCH_MUL)
val = rs1 * rs2;
else if ((insn & MASK_DIV) == MATCH_DIV)
val = (intptr_t)rs1 / (intptr_t)rs2;
else if ((insn & MASK_DIVU) == MATCH_DIVU)
val = rs1 / rs2;
else if ((insn & MASK_REM) == MATCH_REM)
val = (intptr_t)rs1 % (intptr_t)rs2;
else if ((insn & MASK_REMU) == MATCH_REMU)
val = rs1 % rs2;
else if ((insn & MASK_MULH) == MATCH_MULH)
val = ((double_int)(intptr_t)rs1 * (double_int)(intptr_t)rs2) >> (8 * sizeof(rs1));
else if ((insn & MASK_MULHU) == MATCH_MULHU)
val = ((double_int)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
else if ((insn & MASK_MULHSU) == MATCH_MULHSU)
val = ((double_int)(intptr_t)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, val);
}
#if __riscv_xlen == 64
DECLARE_EMULATION_FUNC(emulate_mul_div32)
{
uint32_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs);
int32_t val;
if ((insn & MASK_MULW) == MATCH_MULW)
val = rs1 * rs2;
else if ((insn & MASK_DIVW) == MATCH_DIVW)
val = (int32_t)rs1 / (int32_t)rs2;
else if ((insn & MASK_DIVUW) == MATCH_DIVUW)
val = rs1 / rs2;
else if ((insn & MASK_REMW) == MATCH_REMW)
val = (int32_t)rs1 % (int32_t)rs2;
else if ((insn & MASK_REMUW) == MATCH_REMUW)
val = rs1 % rs2;
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, val);
}
#endif
#endif

76
riscv-pk/machine/uart.c Normal file
View File

@ -0,0 +1,76 @@
#include <string.h>
#include "uart.h"
#include "fdt.h"
volatile uint32_t* uart;
void uart_putchar(uint8_t ch)
{
#ifdef __riscv_atomic
int32_t r;
do {
__asm__ __volatile__ (
"amoor.w %0, %2, %1\n"
: "=r" (r), "+A" (uart[UART_REG_TXFIFO])
: "r" (ch));
} while (r < 0);
#else
volatile uint32_t *tx = uart + UART_REG_TXFIFO;
while ((int32_t)(*tx) < 0);
*tx = ch;
#endif
}
int uart_getchar()
{
int32_t ch = uart[UART_REG_RXFIFO];
if (ch < 0) return -1;
return ch;
}
struct uart_scan
{
int compat;
uint64_t reg;
};
static void uart_open(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void uart_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void uart_done(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!scan->compat || !scan->reg || uart) return;
// Enable Rx/Tx channels
uart = (void*)(uintptr_t)scan->reg;
uart[UART_REG_TXCTRL] = UART_TXEN;
uart[UART_REG_RXCTRL] = UART_RXEN;
}
void query_uart(uintptr_t fdt)
{
struct fdt_cb cb;
struct uart_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = uart_open;
cb.prop = uart_prop;
cb.done = uart_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

21
riscv-pk/machine/uart.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _RISCV_UART_H
#define _RISCV_UART_H
#include <stdint.h>
extern volatile uint32_t* uart;
#define UART_REG_TXFIFO 0
#define UART_REG_RXFIFO 1
#define UART_REG_TXCTRL 2
#define UART_REG_RXCTRL 3
#define UART_REG_DIV 4
#define UART_TXEN 0x1
#define UART_RXEN 0x1
void uart_putchar(uint8_t ch);
int uart_getchar();
void query_uart(uintptr_t dtb);
#endif

View File

@ -0,0 +1,74 @@
#include <string.h>
#include "uart16550.h"
#include "fdt.h"
volatile uint8_t* uart16550;
#define UART_REG_QUEUE 0
#define UART_REG_LINESTAT 5
#define UART_REG_STATUS_RX 0x01
#define UART_REG_STATUS_TX 0x20
void uart16550_putchar(uint8_t ch)
{
while ((uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_TX) == 0);
uart16550[UART_REG_QUEUE] = ch;
}
int uart16550_getchar()
{
if (uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_RX)
return uart16550[UART_REG_QUEUE];
return -1;
}
struct uart16550_scan
{
int compat;
uint64_t reg;
};
static void uart16550_open(const struct fdt_scan_node *node, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void uart16550_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ns16550a")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void uart16550_done(const struct fdt_scan_node *node, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
if (!scan->compat || !scan->reg || uart16550) return;
uart16550 = (void*)(uintptr_t)scan->reg;
// http://wiki.osdev.org/Serial_Ports
uart16550[1] = 0x00; // Disable all interrupts
uart16550[3] = 0x80; // Enable DLAB (set baud rate divisor)
uart16550[0] = 0x03; // Set divisor to 3 (lo byte) 38400 baud
uart16550[1] = 0x00; // (hi byte)
uart16550[3] = 0x03; // 8 bits, no parity, one stop bit
uart16550[2] = 0xC7; // Enable FIFO, clear them, with 14-byte threshold
}
void query_uart16550(uintptr_t fdt)
{
struct fdt_cb cb;
struct uart16550_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = uart16550_open;
cb.prop = uart16550_prop;
cb.done = uart16550_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -0,0 +1,12 @@
#ifndef _RISCV_16550_H
#define _RISCV_16550_H
#include <stdint.h>
extern volatile uint8_t* uart16550;
void uart16550_putchar(uint8_t ch);
int uart16550_getchar();
void query_uart16550(uintptr_t dtb);
#endif

View File

@ -0,0 +1,103 @@
#ifndef _RISCV_MISALIGNED_H
#define _RISCV_MISALIGNED_H
#include "encoding.h"
#include "bits.h"
#include <stdint.h>
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
static inline type load_##type(const type* addr, uintptr_t mepc) \
{ \
register uintptr_t __mepc asm ("a2") = mepc; \
register uintptr_t __mstatus asm ("a3"); \
type val; \
asm ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus), "=&r" (val) \
: "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
return val; \
}
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
static inline void store_##type(type* addr, type val, uintptr_t mepc) \
{ \
register uintptr_t __mepc asm ("a2") = mepc; \
register uintptr_t __mstatus asm ("a3"); \
asm volatile ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus) \
: "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), \
"r" (__mepc)); \
}
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint8_t, lbu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint16_t, lhu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int8_t, lb)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int16_t, lh)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int32_t, lw)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint8_t, sb)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint16_t, sh)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint32_t, sw)
#if __riscv_xlen == 64
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lwu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint64_t, ld)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint64_t, sd)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, ld)
#else
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lw)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, lw)
static inline uint64_t load_uint64_t(const uint64_t* addr, uintptr_t mepc)
{
return load_uint32_t((uint32_t*)addr, mepc)
+ ((uint64_t)load_uint32_t((uint32_t*)addr + 1, mepc) << 32);
}
static inline void store_uint64_t(uint64_t* addr, uint64_t val, uintptr_t mepc)
{
store_uint32_t((uint32_t*)addr, val, mepc);
store_uint32_t((uint32_t*)addr + 1, val >> 32, mepc);
}
#endif
static uintptr_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr_t* mstatus)
{
register uintptr_t __mepc asm ("a2") = mepc;
register uintptr_t __mstatus asm ("a3");
uintptr_t val;
#ifndef __riscv_compressed
asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
STR(LWU) " %[insn], (%[addr])\n"
"csrw mstatus, %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
#else
uintptr_t rvc_mask = 3, tmp;
asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
STR(LWU) " %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw mstatus, %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
[rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
#endif
*mstatus = __mstatus;
return val;
}
#endif

35
riscv-pk/machine/vm.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _VM_H
#define _VM_H
#include "encoding.h"
#include <stdint.h>
#define MEGAPAGE_SIZE ((uintptr_t)(RISCV_PGSIZE << RISCV_PGLEVEL_BITS))
#if __riscv_xlen == 64
# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP64_MODE, SATP_MODE_SV39)
# define VA_BITS 39
# define GIGAPAGE_SIZE (MEGAPAGE_SIZE << RISCV_PGLEVEL_BITS)
#else
# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP32_MODE, SATP_MODE_SV32)
# define VA_BITS 32
#endif
typedef uintptr_t pte_t;
extern pte_t* root_page_table;
static inline void flush_tlb()
{
asm volatile ("sfence.vma");
}
static inline pte_t pte_create(uintptr_t ppn, int type)
{
return (ppn << PTE_PPN_SHIFT) | PTE_V | type;
}
static inline pte_t ptd_create(uintptr_t ppn)
{
return pte_create(ppn, PTE_V);
}
#endif

1526
riscv-pk/scripts/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1662
riscv-pk/scripts/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

238
riscv-pk/scripts/install.sh Executable file
View File

@ -0,0 +1,238 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@ -0,0 +1,40 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-05-16
# Public domain
# $Id: mkinstalldirs,v 1.1 2003/09/09 22:24:03 mhampton Exp $
errstatus=0
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here

117
riscv-pk/scripts/vcs-version.sh Executable file
View File

@ -0,0 +1,117 @@
#!/bin/bash
#=========================================================================
# vcs-version.sh [options] [src-dir]
#=========================================================================
#
# -h Display this message
# -v Verbose mode
#
# This script will create a version string by querying a version control
# system. The string is appropriate for use in installations and
# distributions. Currently this script assumes we are using git as our
# version control system but it would be possible to check and see if we
# are using an alternative version control system and create a version
# string appropriately.
#
# The script uses git describe plus a few other git commands to create a
# version strings in the following format:
#
# X.Y[-Z-gN][-dirty]
#
# where X is the major release, Y is the minor release, Z is the number
# of commits since the X.Y release, N is an eight digit abbreviated SHA
# hash of the most recent commit and the dirty suffix is appended when
# the working directory used to create the installation or distribution
# is not a pristine checkout. Here are some example version strings:
#
# 0.0 : initial import
# 0.0-3-g99ef6933 : 3rd commit since initial import (N=99ef6933)
# 1.0 : release 1.0
# 1.1-12-g3487ab12 : 12th commit since release 1.1 (N=3487ab12)
# 1.1-12-g3487ab12-dirty : 12th commit since release 1.1 (N=3487ab12)
#
# The last example is from a dirty working directory. To find the last
# release, the script looks for the last tag (does not need to be an
# annotated tag, but probably should be) which matches the format rel-*.
# If there is no such tag in the history, then the script uses 0.0 as
# the release number and counts the total number of commits since the
# original import for the commit count.
#
# If the current directory is not within the working directory, then the
# path to the source directory should be supplied on the command line.
#
# Author : Christopher Batten
# Date : August 5, 2009
set -e
#-------------------------------------------------------------------------
# Command line parsing
#-------------------------------------------------------------------------
if ( test "$1" = "-h" ); then
echo ""
sed -n '3p' $0 | sed -e 's/#//'
sed -n '5,/^$/p' $0 | sed -e 's/#//'
exit 1
fi
# Source directory command line option
src_dir="."
if ( test -n "$1" ); then
src_dir="$1"
fi
#-------------------------------------------------------------------------
# Verify source directory
#-------------------------------------------------------------------------
# If the source directory is not a git working directory output a
# question mark. A distribution will not be in a working directory, but
# the build system should be structured such that this script is not
# executed (and instead the version information should probably come
# from configure). If the user does not specify a source directory use
# the current directory.
if !( git rev-parse --is-inside-work-tree &> /dev/null ); then
echo "?"
exit 1;
fi
top_dir=`git rev-parse --show-cdup`
cd ./${top_dir}
#-------------------------------------------------------------------------
# Create the version string
#-------------------------------------------------------------------------
# See if we can do a describe based on a tag and if not use a default
# release number of 0.0 so that we always get canonical version number
if ( git describe --tags --match "rel-*" &> /dev/null ); then
ver_str=`git describe --tags --match "rel-*" | sed 's/rel-//'`
else
ver_num="0.0"
ver_commits=`git rev-list --all | wc -l | tr -d " "`
ver_sha=`git describe --tags --match "rel-*" --always`
ver_str="${ver_num}-${ver_commits}-g${ver_sha}"
fi
# Add a dirty suffix if working directory is dirty
if !( git diff --quiet ); then
ver_str="${ver_str}-dirty"
else
untracked=`git ls-files --directory --exclude-standard --others -t`
if ( test -n "${untracked}" ); then
ver_str="${ver_str}-dirty"
fi
fi
# Output the final version string
echo "${ver_str}"
# Final exit status
exit 0;

98
riscv-pk/util/snprintf.c Normal file
View File

@ -0,0 +1,98 @@
// See LICENSE for license details.
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
int vsnprintf(char* out, size_t n, const char* s, va_list vl)
{
bool format = false;
bool longarg = false;
size_t pos = 0;
for( ; *s; s++)
{
if(format)
{
switch(*s)
{
case 'l':
longarg = true;
break;
case 'p':
longarg = true;
if (++pos < n) out[pos-1] = '0';
if (++pos < n) out[pos-1] = 'x';
case 'x':
{
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
for(int i = 2*(longarg ? sizeof(long) : sizeof(int))-1; i >= 0; i--) {
int d = (num >> (4*i)) & 0xF;
if (++pos < n) out[pos-1] = (d < 10 ? '0'+d : 'a'+d-10);
}
longarg = false;
format = false;
break;
}
case 'd':
{
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
if (num < 0) {
num = -num;
if (++pos < n) out[pos-1] = '-';
}
long digits = 1;
for (long nn = num; nn /= 10; digits++)
;
for (int i = digits-1; i >= 0; i--) {
if (pos + i + 1 < n) out[pos + i] = '0' + (num % 10);
num /= 10;
}
pos += digits;
longarg = false;
format = false;
break;
}
case 's':
{
const char* s2 = va_arg(vl, const char*);
while (*s2) {
if (++pos < n)
out[pos-1] = *s2;
s2++;
}
longarg = false;
format = false;
break;
}
case 'c':
{
if (++pos < n) out[pos-1] = (char)va_arg(vl,int);
longarg = false;
format = false;
break;
}
default:
break;
}
}
else if(*s == '%')
format = true;
else
if (++pos < n) out[pos-1] = *s;
}
if (pos < n)
out[pos] = 0;
else if (n)
out[n-1] = 0;
return pos;
}
int snprintf(char* out, size_t n, const char* s, ...)
{
va_list vl;
va_start(vl, s);
int res = vsnprintf(out, n, s, vl);
va_end(vl);
return res;
}

90
riscv-pk/util/string.c Normal file
View File

@ -0,0 +1,90 @@
#include <string.h>
#include <stdint.h>
#include <ctype.h>
void* memcpy(void* dest, const void* src, size_t len)
{
const char* s = src;
char *d = dest;
if ((((uintptr_t)dest | (uintptr_t)src) & (sizeof(uintptr_t)-1)) == 0) {
while ((void*)d < (dest + len - (sizeof(uintptr_t)-1))) {
*(uintptr_t*)d = *(const uintptr_t*)s;
d += sizeof(uintptr_t);
s += sizeof(uintptr_t);
}
}
while (d < (char*)(dest + len))
*d++ = *s++;
return dest;
}
void* memset(void* dest, int byte, size_t len)
{
if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) {
uintptr_t word = byte & 0xFF;
word |= word << 8;
word |= word << 16;
word |= word << 16 << 16;
uintptr_t *d = dest;
while (d < (uintptr_t*)(dest + len))
*d++ = word;
} else {
char *d = dest;
while (d < (char*)(dest + len))
*d++ = byte;
}
return dest;
}
size_t strlen(const char *s)
{
const char *p = s;
while (*p)
p++;
return p - s;
}
int strcmp(const char* s1, const char* s2)
{
unsigned char c1, c2;
do {
c1 = *s1++;
c2 = *s2++;
} while (c1 != 0 && c1 == c2);
return c1 - c2;
}
char* strcpy(char* dest, const char* src)
{
char* d = dest;
while ((*d++ = *src++))
;
return dest;
}
long atol(const char* str)
{
long res = 0;
int sign = 0;
while (*str == ' ')
str++;
if (*str == '-' || *str == '+') {
sign = *str == '-';
str++;
}
while (*str) {
res *= 10;
res += *str++ - '0';
}
return sign ? -res : res;
}

0
riscv-pk/util/util.ac Normal file
View File

9
riscv-pk/util/util.mk.in Normal file
View File

@ -0,0 +1,9 @@
util_subproject_deps = \
util_hdrs = \
util_c_srcs = \
snprintf.c \
string.c \
util_asm_srcs = \