From 535f28f2335a251fc3f5486cf02136fa40fb4a2b Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Wed, 13 Jan 2021 15:59:23 +0100 Subject: [PATCH 1/2] [SAIL] Use git-external to integrate sail-{cheri-riscv,riscv} repos --- .gitexternals | 13 ++ .gitignore | 4 +- git-external | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 .gitexternals create mode 100755 git-external diff --git a/.gitexternals b/.gitexternals new file mode 100644 index 00000000..04cf0eb5 --- /dev/null +++ b/.gitexternals @@ -0,0 +1,13 @@ +[external "sail-riscv"] + path = simulators/sail/riscv + url = git@github.com:danceos/sail-riscv.git + branch = master + only = update + vcs = git + +[external "sail-cheri-riscv"] + path = simulators/sail/cheri-riscv + url = git@github.com:danceos/sail-cheri-riscv.git + branch = master + only = update + vcs = git diff --git a/.gitignore b/.gitignore index 931513da..87892ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,7 @@ debuggers/openocd/src/startup.tcl debuggers/openocd/src/startup_tcl.c debuggers/openocd/src/target/xscale_debug.h debuggers/openocd/stamp-h1 +.idea -.idea \ No newline at end of file +simulators/sail/riscv +simulators/sail/cheri-riscv diff --git a/git-external b/git-external new file mode 100755 index 00000000..0c4fce17 --- /dev/null +++ b/git-external @@ -0,0 +1,470 @@ +#!/usr/bin/env python3 +"""Add other Git directories as externals (subfolders).""" +import os +import re +import sys +from subprocess import check_output, check_call, call, CalledProcessError +from subprocess import DEVNULL +from collections import defaultdict, namedtuple +import urllib.request +import types +import importlib +import importlib.machinery +import fnmatch +import contextlib +import argparse + +defaulturl = "https://raw.githubusercontent.com/stettberger/git-external/master/bin/git-external" + +self_path = os.path.relpath(os.path.abspath(sys.argv[0]), ".") +if "/" not in self_path: + self_path = "./" + self_path + + +def get_git_config(file=None, path='.') -> dict: + """Return the git configuration as retrieved in the current directory as a + dictionary. + + If file is given, git configuration is read only from this file. + """ + file_cmd = [] + if file: + file_cmd = ["-f", file] + config = defaultdict(dict) + lines = check_output(["git", "config", "-l"] + file_cmd, cwd=path) + lines = lines.decode("utf-8").split("\n") + for line in lines: + m = re.match(r"external\.([^.]+)\.([^.]+)=(.*)", line) + if m: + config[m.group(1)][m.group(2)] = m.group(3) + m = re.match(r"external\.([^.]+)=(.*)", line) + if m: + config["external"][m.group(1)]= m.group(2) + return config + + +class command_description: + """Decorator that adds a hidden attribute _commands to the class which + function was decorated. _commands is a list consisting of tuples of + (, , ) + """ + def __init__(self, fn): + self.fn = fn + + def __set_name__(self, owner, name): + if "_commands" not in owner.__dict__: + owner._commands = [] + owner._commands.append((self.fn.__name__.replace('_', '-'), + self.fn.__doc__, self.fn)) + setattr(owner, name, self.fn) + + +class InitScript: + def __init__(self): + self.config = get_git_config() + + @contextlib.contextmanager + def _open_url(self, url): + """Open url either as http(s) link or as file path and return the file + object. + """ + if url.startswith("http"): + with urllib.request.urlopen(url) as x: + yield x + else: + with open(os.path.expanduser(url), "rb") as x: + yield x + + def cmd_self_update(self, args): + """Update the script itself. + + If "updateurl" is given in the git configuration, it is used for update + otherwise defaulturl is used. The format can either be a web URL or a + file path. + """ + url = self.config["external"].get("updateurl", defaulturl) + print(f"Fetching {url}") + with self._open_url(url) as x: + update = x.read() + with open(self_path, "wb+") as fd: + fd.write(update) + print(f"Updated {self_path}") + + @command_description + def self_update(self, subparser): + """update the init script""" + subparser.set_defaults(func=self.cmd_self_update) + + +class GitExternal: + def __init__(self, path='.'): + try: + self.rootdir = check_output(["git", "rev-parse", + "--show-toplevel"], cwd=path) + self.rootdir = self.rootdir.decode('utf-8').strip() + except CalledProcessError as e: + print("Not a git directory", e) + sys.exit(1) + + self.externals_file = os.path.join(self.rootdir, ".gitexternals") + self.ignore_file = os.path.join(self.rootdir, ".gitignore") + self.configurations = defaultdict(dict) + self.path = path + + def is_git_svn(self, path=None): + """Check if path is a git svn repository.""" + if path is None: + path = self.rootdir + + # call to 'git svn info' causes git to create an .git/svn (empty) + # repository, so everyone thinks it is actually a git svn repo (except + # 'git svn info' itself), so check that before + if not os.path.exists(os.path.join(path, '.git', 'svn')): + return False + foo = call(["git", "svn", "info"], stdout=DEVNULL, stderr=DEVNULL, + cwd=path) + return foo == 0 + + def get_git_svn_externals(self): + if not self.is_git_svn(path=self.path): + return defaultdict(dict) + exts = check_output(["git", "svn", "show-externals"], + cwd=self.path).decode() + externals = defaultdict(dict) + prefix = "" + for line in exts.split('\n'): + m = re.match(r"^# (.*)", line) + if m: + prefix = m.group(1) + elif line.startswith(prefix): + m = re.match(r"(.*) (.*)", line[len(prefix):]) + if m: + externals[prefix + m.group(2)] = { + 'path': prefix[1:] + m.group(2), + 'url': m.group(1), + 'vcs': 'git-svn' + } + return externals + + def merge_externals(self, new_externals): + """Merge the given new externals into the already existing externals in + self.configurations. + + If a path in new_externals dominates an already existing external, the + existing one will be overwritten. + """ + # make a mapping [(repo_url, key), ...] + new_paths = [(new_externals[x]['path'], x) for x in new_externals] + + for path, repo in new_paths: + matches = [x for x in self.configurations + if self.configurations[x]['path'].startswith(path)] + for match in matches: + del self.configurations[match] + print(f"External '{repo}' is masking '{match}'.", + file=sys.stderr) + self.configurations[repo] = new_externals[repo] + + def load_configuration(self): + """Load the configuration from ./.gitexternals and git configuration. + + Matching values from git configuration override values specified in + ./.gitexternals. + """ + self.configurations = self.get_git_svn_externals() + + if os.path.exists(self.externals_file): + self.merge_externals(get_git_config(file=self.externals_file)) + + # Overrides from global config + override = get_git_config(path=self.path) + + # We inspect all override configurations and match them up + # with the externals from this repository by match-* + # attribute. The corresponding attribute is globbed against + # match-attribute. + for name, config in override.items(): + for repo in self.configurations: + matches = False + for key in list(config.keys()): + if not key.startswith('match-'): + continue + pattern = config[key].strip() + key = key[len('match-'):] + + attribute = self.configurations[repo][key].strip() + if pattern and attribute and fnmatch.fnmatch(attribute, pattern): + matches = True + if matches: + # print(name, "matches", repo) + self.configurations[repo].update( + {k: v for (k, v) in config.items() + if not k.startswith('match-')}) + + def add_external(self, url, path, branch='master', vcs="git"): + """Adding an external by writing it to .gitexternals. + + Arguments: + url -- URL of the external (source location) + path -- Path of the external (target directory) + + Keyword arguments: + branch -- Which branch should be cloned/pulled. + vcs -- Which vcs to use (git, svn, or git-svn). + """ + config = ["git", "config", "-f", self.externals_file, "--replace-all"] + path = os.path.relpath(os.path.abspath(path), self.rootdir) + check_call(config + [f"external.{path}.path", path]) + check_call(config + [f"external.{path}.url", url]) + check_call(config + [f"external.{path}.branch", branch]) + check_call(config + [f"external.{path}.vcs", vcs]) + + # Add path to ignore file + found = False + if os.path.exists(self.ignore_file): + # check if directory is already ignored + with open(self.ignore_file, "r") as fd: + for line in fd: + if line.strip() in (path, "./" + path, "/" + path): + found = True + break + # append to .gitignore + if not found: + with open(self.ignore_file, "a+") as fd: + fd.write("/" + path+"\n") + + check_call(["git", "add", self.externals_file]) + check_call(["git", "add", self.ignore_file]) + + print("Added external %s\n Don't forget to call init" % (path)) + + def switch_or_create_branch(self, path, branch): + """Switch to (created) branch in GITDIR=${path}""" + if not branch: + return + cur_branch = check_output(["git", "symbolic-ref", "--short", "HEAD"], + cwd=path) + cur_branch = cur_branch.decode().strip() + if cur_branch != branch: + # list of branches + # expected output: + # refs/heads/ + branches = check_output(["git", "show-ref", "--heads"], cwd=path) + branches = [line.split("/")[-1] + for line in branches.decode().strip().split("\n")] + if branch in branches: + print(f" Switch to branch: {branch} (from {cur_branch})") + else: + print(f" Switch and create branch: {branch} (from {cur_branch}") + check_call(["git", "checkout", "-b", branch, + "origin/" + branch], cwd=path) + + def is_repository(self, path: str) -> bool: + """Check if path is a git or SVN repository.""" + return any([os.path.exists(os.path.join(path, x)) + for x in ['.git', '.svn']]) + + def init_or_update(self, recursive=True, only=None, external=None): + """Init or update all repositories in self.configurations. + + Keyword arguments: + recursive -- checkout/clone externals in externals + only -- values could be "clone" and/or "update". If "clone" is + given, init the repository. If "update" is given, update + the repository. Default is "clone" and "update". + external -- specify that only one external should be cloned or updated + """ + if external and external not in self.configurations: + raise RuntimeError("External '%s' not found" % external) + + for repo, config in self.configurations.items(): + path = os.path.join(self.rootdir, config["path"]) + vcs = config.get("vcs", "git").lower() + + if external and external not in (repo, config['path']): + continue + + # Determine which commands to perform + if only: + repo_only = only + elif 'only' in config: + repo_only = config['only'] + else: + repo_only = ('clone', 'update') + + if 'update' in repo_only and self.is_repository(path): + # Update that external + if vcs == "git-svn": + print(f"Updating GIT-SVN external: {repo}") + call(["git", "svn", "rebase"], cwd=path) + elif vcs == "svn": + print("Updating Git SVN external: %s" % repo) + call(["svn", "up"], cwd=path) + else: + print(f"Updating Git external: {repo}") + self.switch_or_create_branch(path, config.get("branch")) + call(["git", "pull", "--ff-only"], cwd=path) + elif 'clone' in repo_only and not self.is_repository(path): + # Clone that repo + if config.get("symlink"): + link = os.path.expanduser(config["symlink"]) + print(f"Cloning symlinked external: {repo}") + assert os.path.exists(link), "Path does not exist" + if os.path.exists(path) and os.path.islink(path): + os.unlink(path) + os.symlink(link, path) + elif vcs == "git-svn": + print(f"Cloning Git SVN external: {repo}") + check_call(["git", "svn", "clone", config["url"], + path, "-r", "HEAD"]) + elif vcs == "svn": + print("Cloning SVN external: %s" % repo) + check_call(["svn", "checkout", config["url"], + path, ]) + else: + print(f"Cloning Git external: {repo}") + check_call(["git", "clone", config["url"], path]) + self.switch_or_create_branch(path, config.get("branch")) + # recursively call for externals + if (args.recursive and vcs in ['git', 'git-svn'] and + set(repo_only) & set(['clone', 'update'])): + print(f"Updating externals of {repo}") + ext = GitExternal(path=path) + ext.cmd_update(namedtuple('Args', + ['recursive', 'automatic', 'external', 'only']) + (True, False, None, None)) + + if config.get("run-init", "").lower() == "true": + init = os.path.join(path, "init") + print(init) + if os.path.exists(init): + call(init, cwd=path) + + def install_hook(self): + """Install the script into git hooks, so it is executed every + merge/pull. + """ + hook = check_output(["git", "rev-parse", "--git-path", "hooks"]) + hook = os.path.join(hook.decode().strip(), "post-merge") + if not os.path.exists(hook): + with open(hook, "w+") as fd: + fd.write("#!/bin/sh\n\n") + fd.write(f"{self_path}\n") + os.chmod(hook, int("755", 8)) + + def cmd_update(self, args): + """Update/clone all externals.""" + self.load_configuration() + self.init_or_update(external=args.external, + recursive=args.recursive, + only=args.only) + if args.automatic: + self.install_hook() + + @command_description + def update(self, subparser): + """init or update the externals""" + subparser.set_defaults(func=self.cmd_update, only=None) + subparser.add_argument("-r", "--not-recursive", action="store_false", + dest="recursive", + help="Do not clone externals in externals.") + subparser.add_argument("-a", "--not-automatic", action="store_false", + dest="automatic", + help="Do not update externals on every pull.") + + subparser.add_argument("external", nargs='?', default=None, + help="Name of external to update") + + @command_description + def clone(self, subparser): + """init or update the externals""" + subparser.set_defaults(func=self.cmd_update, only=('clone',)) + subparser.add_argument("-r", "--not-recursive", action="store_false", + dest="recursive", + help="Do not clone externals in externals.") + subparser.add_argument("-a", "--not-automatic", action="store_false", + dest="automatic", + help="Do not update externals on every pull.") + + subparser.add_argument("external", nargs='?', default=None, + help="Name of external to update") + + + def cmd_add(self, args): + """Add an external. + + Arguments: + args -- arguments retrieved with argparse + """ + self.add_external(args.URL, args.PATH, + vcs=args.vcs, branch=args.branch) + + @command_description + def add(self, subparser): + """add a Git or Git SVN external""" + subparser.set_defaults(func=self.cmd_add) + subparser.add_argument("URL", help="Url of the external") + subparser.add_argument("PATH", help="Path where to clone the external") + subparser.add_argument("-b", "--branch", default="master", + help="Branch that should be used") + vcs_group = subparser.add_mutually_exclusive_group() + vcs_group.add_argument("-s", "--svn", action='store_const', + dest='vcs', const='svn', default='git', + help="Use 'svn' for handling the external") + vcs_group.add_argument("-g", "--git-svn", action='store_const', + dest='vcs', const='git-svn', default='git', + help="Use 'git-svn' for handling the external") + + def cmd_show(self, args): + """Show all externals.""" + self.load_configuration() + for repo, config in self.configurations.items(): + print(f'[external "{repo}"]') + for key, value in config.items(): + print(f' {key} = {value}') + + @command_description + def show(self, subparser): + """show the externals configuration""" + subparser.set_defaults(func=self.cmd_show) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(prog=sys.argv[0], + description=sys.modules[__name__].__doc__) + subparsers = parser.add_subparsers(help='sub-command help') + + modules = [GitExternal()] + if os.access(self_path, os.W_OK): + modules.append(InitScript()) + + # default action: recursive update + parser.set_defaults(func=modules[0].cmd_update, + recursive=True, automatic=True, + external=None, only=None) + + # Find more modules. We search for all files that are named like + # our self_path and end with a .py extension. We load these files + # with imp and include all classes that have a .commands attribute + # to our module list. + for fn in os.listdir(os.path.dirname(self_path)): + fn_x = os.path.abspath(fn) + x = os.path.abspath(self_path) + if fn_x.startswith(x) and fn.endswith(".py"): + loader = importlib.machinery.SourceFileLoader(fn, fn) + F = types.ModuleType(loader.name) + loader.exec_module(F) + for obj in dir(F): + obj = getattr(F, obj) + if hasattr(obj, '_commands'): + modules.append(obj()) + + for mod in modules: + for cmd, help_msg, init in mod._commands: + cmd_parser = subparsers.add_parser(cmd, help=help_msg) + init(mod, cmd_parser) + + args = parser.parse_args() + + sys.exit(args.func(args)) From 3f03f916c0b0a38b83848c4fe3deb09da3a8430b Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Tue, 26 Jan 2021 16:40:23 +0100 Subject: [PATCH 2/2] [SAIL] Integration of RISC-V and CHERI-RISCV With this (large) patch, we integrate the riscv and cheri-riscv model as potential tracing and injection targets. This change also introduces the infratstructure to integrate other models with a relatively low overhead. Mixed into this patch are a few changes that are unrelated. I'm aware of this, but I have no desire to pull everything appart. The effort was large enough. - llvmdisassembler: bump version to 11.0.0 With 11.0.0, the llvmdisassemble broke FAIL*, since the LLVM's ELF.h used enums to define constants, while the system elf.h used preprocessor #define to define the same constants. Depending on the inclusion order, this broke horribly. Co-authored-by: Christian Dietrich Co-authored-by: Malte Bargholz Co-authored-by: Marcel Budoj --- CMakeLists.txt | 71 ++++- cmake/FindLLVM.cmake | 34 -- cmake/sail.cmake | 82 +++++ configurations/sail.sh | 72 +++++ simulators/sail/README | 7 + simulators/sail/fail_defs.sail | 12 + .../sail/fail_empty_source_file_for_build.cc | 0 simulators/sail/sail-cc.in | 4 + src/core/config/VariantConfig.hpp.in | 4 + src/core/sal/Architecture.hpp | 4 + src/core/sal/CMakeLists.txt | 87 ++--- src/core/sal/ConcreteCPU.hpp | 2 + src/core/sal/Register.hpp | 5 +- src/core/sal/SALConfig.cc | 31 +- src/core/sal/SALConfig.hpp | 12 + src/core/sal/SALInst.hpp | 8 + src/core/sal/faultspace/CMakeLists.txt | 5 + src/core/sal/faultspace/FaultSpace.hpp | 5 + src/core/sal/sail/CMakeLists.txt | 22 ++ src/core/sal/sail/SailArchitecture.cc | 45 +++ src/core/sal/sail/SailArchitecture.hpp | 103 ++++++ src/core/sal/sail/SailCPU.cc | 23 ++ src/core/sal/sail/SailCPU.hpp | 65 ++++ src/core/sal/sail/SailFailInterface.cc | 127 ++++++++ src/core/sal/sail/SailFailInterface.h | 100 ++++++ src/core/sal/sail/SailMemoryExtern.hpp | 45 +++ src/core/sal/sail/SailMemoryManager.cc | 157 +++++++++ src/core/sal/sail/SailMemoryManager.hpp | 84 +++++ src/core/sal/sail/SailSimulator.cc | 121 +++++++ src/core/sal/sail/SailSimulator.hpp | 64 ++++ src/core/sal/sail/cheri-riscv/SailArchCPU.hpp | 14 + .../sal/sail/cheri-riscv/SailArchConfig.hpp | 27 ++ .../sail/cheri-riscv/SailArchFaultSpace.cc | 38 +++ .../sail/cheri-riscv/SailArchFaultSpace.hpp | 22 ++ .../sal/sail/cheri-riscv/SailArchRegisters.cc | 31 ++ .../sail/cheri-riscv/SailArchRegisters.hpp | 117 +++++++ .../sail/cheri-riscv/SailArchRegisters.inc | 147 +++++++++ .../cheri-riscv/SailArchRegistersExtern.h | 297 +++++++++++++++++ .../cheri-riscv/SailArchRegistersExtern.hpp | 298 ++++++++++++++++++ .../sal/sail/cheri-riscv/SailArchSimulator.cc | 104 ++++++ .../sail/cheri-riscv/SailArchSimulator.hpp | 19 ++ .../sail/cheri-riscv/SailTagMemoryManager.cc | 135 ++++++++ .../sail/cheri-riscv/SailTagMemoryManager.hpp | 78 +++++ src/core/sal/sail/riscv/SailArchCPU.hpp | 5 + src/core/sal/sail/riscv/SailArchConfig.hpp | 25 ++ src/core/sal/sail/riscv/SailArchFaultSpace.cc | 15 + .../sal/sail/riscv/SailArchFaultSpace.hpp | 13 + src/core/sal/sail/riscv/SailArchRegisters.cc | 19 ++ src/core/sal/sail/riscv/SailArchRegisters.hpp | 10 + src/core/sal/sail/riscv/SailArchRegisters.inc | 121 +++++++ .../sail/riscv/SailArchRegistersExtern.hpp | 167 ++++++++++ src/core/sal/sail/riscv/SailArchSimulator.cc | 87 +++++ src/core/sal/sail/riscv/SailArchSimulator.hpp | 9 + src/core/util/llvmdisassembler/CMakeLists.txt | 37 ++- .../llvmdisassembler/LLVMDisassembler.cpp | 82 ++++- .../llvmdisassembler/LLVMDisassembler.hpp | 32 +- .../llvmdisassembler/LLVMtoFailSailRiscv.cpp | 147 +++++++++ .../llvmdisassembler/LLVMtoFailSailRiscv.hpp | 16 + .../llvmdisassembler/testing/llvmDisTest.cc | 2 + src/plugins/serialoutput/CMakeLists.txt | 1 + tools/import-trace/CMakeLists.txt | 25 +- tools/import-trace/MemoryImporter.cc | 18 +- 62 files changed, 3421 insertions(+), 138 deletions(-) delete mode 100644 cmake/FindLLVM.cmake create mode 100644 cmake/sail.cmake create mode 100755 configurations/sail.sh create mode 100644 simulators/sail/README create mode 100644 simulators/sail/fail_defs.sail create mode 100644 simulators/sail/fail_empty_source_file_for_build.cc create mode 100755 simulators/sail/sail-cc.in create mode 100644 src/core/sal/sail/CMakeLists.txt create mode 100644 src/core/sal/sail/SailArchitecture.cc create mode 100644 src/core/sal/sail/SailArchitecture.hpp create mode 100644 src/core/sal/sail/SailCPU.cc create mode 100644 src/core/sal/sail/SailCPU.hpp create mode 100644 src/core/sal/sail/SailFailInterface.cc create mode 100644 src/core/sal/sail/SailFailInterface.h create mode 100644 src/core/sal/sail/SailMemoryExtern.hpp create mode 100644 src/core/sal/sail/SailMemoryManager.cc create mode 100644 src/core/sal/sail/SailMemoryManager.hpp create mode 100644 src/core/sal/sail/SailSimulator.cc create mode 100644 src/core/sal/sail/SailSimulator.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchCPU.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchConfig.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchFaultSpace.cc create mode 100644 src/core/sal/sail/cheri-riscv/SailArchFaultSpace.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchRegisters.cc create mode 100644 src/core/sal/sail/cheri-riscv/SailArchRegisters.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchRegisters.inc create mode 100644 src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.h create mode 100644 src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailArchSimulator.cc create mode 100644 src/core/sal/sail/cheri-riscv/SailArchSimulator.hpp create mode 100644 src/core/sal/sail/cheri-riscv/SailTagMemoryManager.cc create mode 100644 src/core/sal/sail/cheri-riscv/SailTagMemoryManager.hpp create mode 100644 src/core/sal/sail/riscv/SailArchCPU.hpp create mode 100644 src/core/sal/sail/riscv/SailArchConfig.hpp create mode 100644 src/core/sal/sail/riscv/SailArchFaultSpace.cc create mode 100644 src/core/sal/sail/riscv/SailArchFaultSpace.hpp create mode 100644 src/core/sal/sail/riscv/SailArchRegisters.cc create mode 100644 src/core/sal/sail/riscv/SailArchRegisters.hpp create mode 100644 src/core/sal/sail/riscv/SailArchRegisters.inc create mode 100644 src/core/sal/sail/riscv/SailArchRegistersExtern.hpp create mode 100644 src/core/sal/sail/riscv/SailArchSimulator.cc create mode 100644 src/core/sal/sail/riscv/SailArchSimulator.hpp create mode 100644 src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.cpp create mode 100644 src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 51e8598f..e56e6807 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -# cmake 2.6 might suffice, but we don't test it (even Debian stable has 2.8.2) -cmake_minimum_required(VERSION 2.8.2) +# cmake 2.6 might suffice, but we don't test it (even Debian stable has 3.12) +cmake_minimum_required(VERSION 3.12) if("${CMAKE_VERSION}" VERSION_GREATER 2.8.3) # system cmake modules take precedence over those in CMAKE_MODULE_PATH # (makes cmake 2.8.4 and newer) @@ -15,6 +15,8 @@ else() set(PROJECT_VERSION "1.0.1" CACHE INTERNAL "FAIL* version number" FORCE) endif() +cmake_policy(SET CMP0074 NEW) + ENABLE_TESTING() #### Put all resulting library files in /lib #### @@ -43,13 +45,18 @@ include(doxygen) #### Backend selection #### OPTION( BUILD_BOCHS "Build Bochs Variant?" ON) +OPTION( BUILD_SAIL "Build Sail Variant" OFF) OPTION( BUILD_GEM5 "Build gem5 Variant?" OFF) OPTION( BUILD_QEMU "Build QEMU Variant?" OFF) OPTION( BUILD_T32 "Build Lauterbach Trace32 Variant?" OFF) OPTION( BUILD_PANDA "Build Pandaboard ES + Flyswatter2 Variant?" OFF) -OPTION( BUILD_X86 "Build for x86 guests?" ON) -OPTION( BUILD_ARM "Build for ARM guests?" OFF) +OPTION( BUILD_X86 "Build for x86 guests?" ON) +OPTION( BUILD_ARM "Build for ARM guests?" OFF) +OPTION( BUILD_RISCV_CHERI "Build for CHERI enabled RISC-V guests?" OFF) +OPTION( BUILD_RISCV "Build for RISC-V guests?" OFF) + +OPTION( BUILD_64BIT "Build RISCV or CHERI RISC-V with 64-bit support" OFF) # FIXME: only add simulators/ to include_directories, and include, e.g., # bochs/bochs.h in FAIL*. -> avoids naming conflicts (e.g., /usr/include/elf.h @@ -69,8 +76,61 @@ elseif(BUILD_T32) add_subdirectory(scripts/t32cmm) elseif(BUILD_PANDA) include_directories(debuggers/openocd/src debuggers/openocd/jimtcl src/core) +elseif(BUILD_SAIL) + message(STATUS "[${PROJECT_NAME}] Building Sail ...") + SET(VARIANT sail) + + if(BUILD_64BIT) + message(STATUS "[${PROJECT_NAME}] Building 64-bit Sail Simulator ...") + set(ARCH_SUFFIX "RV64") + else() + message(STATUS "[${PROJECT_NAME}] Building 32-bit Sail Simulator ...") + set(ARCH_SUFFIX "RV32") + endif() + + if (BUILD_RISCV) + message(STATUS "[${PROJECT_NAME}] Building Sail RISC-V Variant ...") + set(SAIL_ARCH riscv) + set(SAIL_SIMULATOR build/riscv_sim_${ARCH_SUFFIX}.a) + set(SAIL_SOFTFLOAT_DIR c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC) + set(SAIL_SOFTFLOAT_BUILD_ARGS SPECIALIZE_TYPE=RISCV) + set(SAIL_BUILD_ARGS ${SAIL_SIMULATOR} ARCH=${ARCH_SUFFIX}) + elseif(BUILD_RISCV_CHERI) + message(STATUS "[${PROJECT_NAME}] Building Sail CHERI RISC-V Variant") + set(SAIL_ARCH cheri-riscv) + set(SAIL_SIMULATOR build/cheri_riscv_sim_${ARCH_SUFFIX}.a) + set(SAIL_SOFTFLOAT_DIR sail-riscv/c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC) + set(SAIL_SOFTFLOAT_BUILD_ARGS SPECIALIZE_TYPE=RISCV) + set(SAIL_BUILD_ARGS ${SAIL_SIMULATOR} ARCH=${ARCH_SUFFIX}) + else() + message( FATAL_ERROR "No supported architecture selected" ) + endif() + # Architecture specific include directory + message("Add include: ${PROJECT_SOURCE_DIR}/src/core/sal/sail/${SAIL_ARCH}") + include_directories("${PROJECT_SOURCE_DIR}/src/core/sal/sail/${SAIL_ARCH}") endif(BUILD_BOCHS) +if(BUILD_LLVM_DISASSEMBLER) + if (BUILD_RISCV_CHERI) + set(FIND_PACKAGE_VERSION 11.0.0) + set(LLVM_ROOT /opt/llvm-cheri-05.2020 CACHE STRING "Where is LLVM located") + set(LLVM_FIND_PACKAGE_ARGS HINTS ${LLVM_ROOT} NO_DEFAULT_PATH) + else() + set(FIND_PACKAGE_VERSION 11.0.0) + set(LLVM_FIND_PACKAGE_ARGS HINTS) + endif() + + find_package(LLVM ${FIND_PACKAGE_VERSION} + REQUIRED + CONFIG + ${FIND_PACKAGE_ARGS} + ) + + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +endif(BUILD_LLVM_DISASSEMBLER) + ## Tell the linker where to find the FAIL* libraries link_directories("${LIBRARY_OUTPUT_PATH}") @@ -84,10 +144,11 @@ add_subdirectory(tools) add_subdirectory(src) -#### Backend-related build system stuff +#### Backend-related build system stuff [cmake/{name}.cmake] include(bochs) include(gem5) include(qemu) include(t32) include(panda) +include(sail) diff --git a/cmake/FindLLVM.cmake b/cmake/FindLLVM.cmake deleted file mode 100644 index 5c36850b..00000000 --- a/cmake/FindLLVM.cmake +++ /dev/null @@ -1,34 +0,0 @@ -find_program(LLVMCONFIG NAMES llvm-config-8 llvm-config-7 llvm-config-6.0 llvm-config-5.0 llvm-config-4.0 llvm-config-3.9 llvm-config) - -if( NOT LLVMCONFIG ) - message(FATAL_ERROR "llvm-config not found, try installing llvm-dev llvm") -else() - message(STATUS "[FAIL*] LLVM Disassembler: Found llvm-config @ ${LLVMCONFIG}") -endif() - -# examine LLVM include directory -execute_process( COMMAND ${LLVMCONFIG} --includedir - OUTPUT_VARIABLE LLVM_INCLUDE_DIRS - OUTPUT_STRIP_TRAILING_WHITESPACE ) -include_directories( ${LLVM_INCLUDE_DIRS} ) - -# Library path -execute_process( COMMAND ${LLVMCONFIG} --libdir - OUTPUT_VARIABLE LLVM_LIBRARY_DIRS - OUTPUT_STRIP_TRAILING_WHITESPACE ) -link_directories( ${LLVM_LIBRARY_DIRS} ) - -# necessary CPP flags. -execute_process( COMMAND ${LLVMCONFIG} --cxxflags - OUTPUT_VARIABLE LLVM_CXX_FLAGS - OUTPUT_STRIP_TRAILING_WHITESPACE ) - -# and additional libs (this is -ldl and -lpthread in llvm 3.1) -execute_process( COMMAND ${LLVMCONFIG} --ldflags - OUTPUT_VARIABLE LLVM_LDFLAGS - OUTPUT_STRIP_TRAILING_WHITESPACE ) - -## FIXME? Here we add *all* libraries to the link step (although we need only a handful..) -execute_process( COMMAND ${LLVMCONFIG} --libs all - OUTPUT_VARIABLE LLVM_LIBS - OUTPUT_STRIP_TRAILING_WHITESPACE ) diff --git a/cmake/sail.cmake b/cmake/sail.cmake new file mode 100644 index 00000000..2e378b06 --- /dev/null +++ b/cmake/sail.cmake @@ -0,0 +1,82 @@ +if(BUILD_SAIL) + find_package(ZLIB REQUIRED) # -lz + if(ZLIB_FOUND) + set(sail_library_dependencies ${sail_library_dependencies} ${ZLIB_LIBRARIES}) + endif(ZLIB_FOUND) + + #FIXME: find package GMP dynamically + + #find_package(GMP REQUIRED) + #if(GMP_FOUND) + # set(sail_library_dependencies ${sail_library_dependencies} ${GMP_LIBRARIES}) + #endif(GMP_FOUND) + + set(sail_library_dependencies ${sail_library_dependencies} -lgmp) + + set(SAIL_SIMULATOR_DIR ${PROJECT_SOURCE_DIR}/simulators/sail) + set(sail_src_dir ${SAIL_SIMULATOR_DIR}/${SAIL_ARCH}) + add_executable(fail-client ${SAIL_SIMULATOR_DIR}/fail_empty_source_file_for_build.cc) + + # make sure aspects don't fail to match in entry.cc and the experiment headers are found + include_directories(${PROJECT_SOURCE_DIR}/src/core ${CMAKE_BINARY_DIR}/src/core) + + set(sail_build_CC "${CMAKE_C_COMPILER}") + set(sail_build_CFLAGS "-I${PROJECT_SOURCE_DIR}/src/core -I${CMAKE_BINARY_DIR}/src/core") + configure_file(${PROJECT_SOURCE_DIR}/simulators/sail/sail-cc.in + ${CMAKE_CURRENT_BINARY_DIR}/sail-cc) + + include(ExternalProject) + ExternalProject_Add( + libsail-emu_external + SOURCE_DIR ${sail_src_dir} + ## Put configure command here, to prevent cmake calling make configure + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "[${PROJECT_NAME}] No configure for libsail-emu" + BUILD_COMMAND + ${CMAKE_COMMAND} -E env CC=${CMAKE_CURRENT_BINARY_DIR}/sail-cc $(MAKE) -C ${sail_src_dir} ${SAIL_BUILD_ARGS} + BUILD_IN_SOURCE 1 + BUILD_ALWAYS true + ## Put install command here, to prevent cmake calling make install + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "[${PROJECT_NAME}] No install for libsail-emu" + + ) + + add_library(libsail-emu STATIC IMPORTED GLOBAL) + add_dependencies(libsail-emu libsail-emu_external) + set_property(TARGET libsail-emu PROPERTY IMPORTED_LOCATION ${sail_src_dir}/${SAIL_SIMULATOR}) + + set(SAIL_SOFTFLOAT_LIB ${SAIL_SOFTFLOAT_DIR}/softfloat.a) + ExternalProject_Add( + libsail-softfloat_external + SOURCE_DIR ${sail_src_dir} + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "[${PROJECT_NAME}] no configure for libsail-softfloat" + BUILD_COMMAND + ${CMAKE_COMMAND} -E env CC=${CMAKE_CURRENT_BINARY_DIR}/sail-cc $(MAKE) -C ${SAIL_SOFTFLOAT_DIR} ${SAIL_SOFTFLOAT_BUILD_ARGS} + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "[${PROJECT_NAME}] no install for libsail-softfloat" + BUILD_IN_SOURCE 1 + ) + add_library(libsail-softfloat STATIC IMPORTED GLOBAL) + set_property(TARGET libsail-softfloat PROPERTY IMPORTED_LOCATION ${sail_src_dir}/${SAIL_SOFTFLOAT_LIB}) + add_dependencies(libsail-softfloat libsail-softfloat_external) + #set(sail_library_dependencies ${sail_library_dependencies} + #libsail-softfloat) + + # add all libraries which need to be linked with libsail-emu to the target INTERFACE_LINK_LIBRARIES + # this way they get linked too when libsail-emu gets linked to a target. + set_property(TARGET libsail-emu PROPERTY INTERFACE_LINK_LIBRARIES ${sail_library_dependencies}) + + add_dependencies(fail-client libsail-emu libsail-softfloat) + target_link_libraries(fail-client fail libsail-emu libsail-softfloat fail-sal fail-sail fail-fsp fail-sal) + install(TARGETS fail-client RUNTIME DESTINATION bin) + + # Get stamp directory to touch files for forcing rebuilds. + ExternalProject_Get_Property(libsail-emu_external stamp_dir) + + add_custom_target(libsailclean + COMMAND +make -C ${sail_src_dir} clean + COMMAND +make -C ${sail_src_dir}/${SAIL_SOFTFLOAT_DIR} clean + # touch stamp file to force rebuild, without calling configure again. + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${stamp_dir}/libsail-emu_external-configure || true + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${stamp_dir}/libsail-softfloat_external-configure || true + COMMENT "[${PROJECT_NAME}] Cleaning all up (clean in sail)" + ) +endif(BUILD_SAIL) diff --git a/configurations/sail.sh b/configurations/sail.sh new file mode 100755 index 00000000..7a421429 --- /dev/null +++ b/configurations/sail.sh @@ -0,0 +1,72 @@ +#!/bin/bash +FAILPATH=$(dirname $0)/.. +ARCH=$1; shift +DEBUG=$1; shift + +USE_64=OFF +RISCV=OFF +RISCV_CHERI=OFF + +case $ARCH in + riscv32) + RISCV=ON + ;; + riscv64) + USE_64=ON + RISCV=ON + ;; + cheri32) + RISCV_CHERI=ON + ;; + cheri64) + USE_64=ON + RISCV_CHERI=ON + ;; + *) + echo "Unknown ARCH argument" + exit 1 + ;; +esac + +case $DEBUG in + ON) + TYPE=Debug + ;; + + OFF|"") + TYPE=Release + ;; + + *) + echo "Unknown DEBUG Arg" + exit 1 +esac + + +cmake \ + -DCMAKE_AGPP_FLAGS:STRING="--c_compiler clang++" \ + -DBUILD_64BIT:BOOL="${USE_64}"\ + -DVERBOSE_MAKE:BOOL="${DEBUG}" \ + -DCMAKE_BUILD_TYPE="${TYPE}" \ + -DBUILD_SAIL:BOOL=ON \ + -DBUILD_RISCV_CHERI:BOOL=${RISCV_CHERI} \ + -DBUILD_RISCV:BOOL=${RISCV} \ + -DBUILD_BOCHS:BOOL=OFF \ + -DBUILD_GEM5:BOOL=OFF \ + -DBUILD_X86:BOOL=OFF \ + -DBUILD_ARM:BOOL=OFF \ + -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON \ + -DCONFIG_EVENT_IOPORT:BOOL=ON \ + -DCONFIG_EVENT_MEMREAD:BOOL=ON \ + -DCONFIG_EVENT_MEMWRITE:BOOL=ON \ + -DCONFIG_EVENT_TRAP:BOOL=ON \ + -DCONFIG_SR_RESTORE:BOOL=ON \ + -DCONFIG_SR_SAVE:BOOL=ON \ + -DEXPERIMENTS_ACTIVATED:STRING="generic-tracing;generic-experiment" \ + -DPLUGINS_ACTIVATED:STRING="tracing;serialoutput" \ + -DBUILD_DUMP_TRACE:BOOL=ON \ + -DBUILD_IMPORT_TRACE:BOOL=ON \ + -DBUILD_PRUNE_TRACE:BOOL=ON \ + -DBUILD_LLVM_DISASSEMBLER=ON \ + -DCLIENT_RETRY_COUNT=1 \ + -H${FAILPATH} diff --git a/simulators/sail/README b/simulators/sail/README new file mode 100644 index 00000000..4ce95c4b --- /dev/null +++ b/simulators/sail/README @@ -0,0 +1,7 @@ +# steps to take to implement a new architecture + + +- include fail_defs.sail into sail spec +- define xlenbits to architecture instruction length +- call functions defined in fail_defs.sail from model sail code + diff --git a/simulators/sail/fail_defs.sail b/simulators/sail/fail_defs.sail new file mode 100644 index 00000000..b8ac401f --- /dev/null +++ b/simulators/sail/fail_defs.sail @@ -0,0 +1,12 @@ +val fail_executeRequests = {c: "fail_executeRequests"} : unit -> unit +val fail_onTrap = {c: "fail_onTrap"} : bits(8) -> unit +val fail_onInterrupt = {c: "fail_onInterrupt"} : (bits(8), bool) -> unit +val fail_isSuppressedInterrupt = {c: "fail_isSuppressedInterrupt"} : bits(8) -> bool +val fail_willExecuteInstruction = {c: "fail_willExecuteInstruction" } : (xlenbits) -> unit +val fail_didExecuteInstruction = {c: "fail_didExecuteInstruction"} : (xlenbits, xlenbits) -> unit +val fail_setInstructionFetch = {c: "fail_setInstructionFetch"} : bool -> unit + +let fail_memtype_ram : bits(8) = 0b00000001 +let fail_memtype_tags : bits(8) = 0b00000011 +val fail_onMemoryRead = {c: "fail_onMemoryRead"} : (xlenbits, int, int, bits(8), xlenbits) -> unit +val fail_onMemoryWrite = {c: "fail_onMemoryWrite"} : (xlenbits, int, int, bits(8), xlenbits) -> unit diff --git a/simulators/sail/fail_empty_source_file_for_build.cc b/simulators/sail/fail_empty_source_file_for_build.cc new file mode 100644 index 00000000..e69de29b diff --git a/simulators/sail/sail-cc.in b/simulators/sail/sail-cc.in new file mode 100755 index 00000000..7dcaef59 --- /dev/null +++ b/simulators/sail/sail-cc.in @@ -0,0 +1,4 @@ +#!/bin/sh + +echo @sail_build_CC@ @sail_build_CFLAGS@ $* +exec @sail_build_CC@ @sail_build_CFLAGS@ $* \ No newline at end of file diff --git a/src/core/config/VariantConfig.hpp.in b/src/core/config/VariantConfig.hpp.in index 73c7efc0..debb78d4 100644 --- a/src/core/config/VariantConfig.hpp.in +++ b/src/core/config/VariantConfig.hpp.in @@ -7,9 +7,13 @@ #cmakedefine BUILD_T32 #cmakedefine BUILD_PANDA #cmakedefine T32_MOCK_API +#cmakedefine BUILD_SAIL +#cmakedefine BUILD_RISCV +#cmakedefine BUILD_RISCV_CHERI #cmakedefine BUILD_X86 #cmakedefine BUILD_ARM +#cmakedefine BUILD_64BIT #cmakedefine BUILD_LLVM_DISASSEMBLER #cmakedefine BUILD_CAPSTONE_DISASSEMBLER diff --git a/src/core/sal/Architecture.hpp b/src/core/sal/Architecture.hpp index 6492c606..fb2b43cc 100644 --- a/src/core/sal/Architecture.hpp +++ b/src/core/sal/Architecture.hpp @@ -14,4 +14,8 @@ #include "arm/ArmArchitecture.hpp" #endif +#ifdef BUILD_SAIL +#include "sail/SailArchitecture.hpp" +#endif + #endif diff --git a/src/core/sal/CMakeLists.txt b/src/core/sal/CMakeLists.txt index b086e9d6..471d6be1 100644 --- a/src/core/sal/CMakeLists.txt +++ b/src/core/sal/CMakeLists.txt @@ -1,26 +1,24 @@ +add_subdirectory(faultspace) + +# Some files are common over all architectures +set(SRCS + CPU.cc + CPUState.cc + Listener.cc + ListenerManager.cc + SALConfig.cc + Register.cc + SimulatorController.cc + ) if(BUILD_BOCHS) - set(SRCS - CPU.cc - CPUState.cc - Listener.cc - ListenerManager.cc - SALConfig.cc - Register.cc - SimulatorController.cc + set(SRCS ${SRCS} bochs/BochsController.cc bochs/BochsListener.cc bochs/BochsCPU.cc ) elseif(BUILD_GEM5) - set(SRCS - CPU.cc - CPUState.cc - Listener.cc - ListenerManager.cc - SALConfig.cc - Register.cc - SimulatorController.cc + set(SRCS ${SRCS} gem5/Gem5Controller.cc ) if(BUILD_ARM) @@ -29,26 +27,12 @@ elseif(BUILD_GEM5) ) endif(BUILD_ARM) elseif(BUILD_QEMU) - set(SRCS - CPU.cc - CPUState.cc - Listener.cc - ListenerManager.cc - SALConfig.cc - Register.cc - SimulatorController.cc + set(SRCS ${SRCS} qemu/QEMUController.cc qemu/wrappers.cc ) elseif(BUILD_T32) - set(SRCS - CPU.cc - CPUState.cc - Listener.cc - ListenerManager.cc - SALConfig.cc - Register.cc - SimulatorController.cc + set(SRCS ${SRCS} t32/T32Controller.cc ) if(BUILD_ARM) @@ -60,14 +44,7 @@ elseif(BUILD_T32) endif(BUILD_ARM) elseif(BUILD_PANDA) include_directories(${PROJECT_SOURCE_DIR}/debuggers/openocd) - set(SRCS - CPU.cc - CPUState.cc - Listener.cc - ListenerManager.cc - SALConfig.cc - Register.cc - SimulatorController.cc + set(SRCS ${SRCS} panda/PandaController.cc panda/PandaArmCPU.cc panda/PandaListener.cc @@ -77,6 +54,23 @@ elseif(BUILD_PANDA) panda/PandaArmCPU.cc ) endif(BUILD_ARM) +elseif(BUILD_SAIL) + add_subdirectory(sail) + #set(SRCS ${SRCS} + # sail/memory.cc + # sail/tag_memory.cc + # sail/wrapper.cc + # sail/simulator.cc + #) + #if(BUILD_RISCV) + #set(SRCS ${SRCS} + # sail/riscv/arch.cpp) + #elseif(BUILD_RISCV_CHERI) +# set(SRCS ${SRCS} +# sail/cheri-riscv/arch.cpp) +# else() +# message(ERROR " No SAIL_ARCH set. Aborting!") +# endif(BUILD_RISCV) endif(BUILD_BOCHS) if(BUILD_X86) @@ -120,12 +114,21 @@ if(CONFIG_FAST_BREAKPOINTS) ) endif(CONFIG_FAST_BREAKPOINTS) -add_subdirectory(faultspace) - add_library(fail-sal ${SRCS}) + +# FIXME: Find dynamic +if(BUILD_SAIL) + target_link_libraries(fail-sal fail-sail) + if (BUILD_64BIT) + target_link_libraries(fail-sal -lgmpxx -lgmp) + endif() +endif() + target_link_libraries(fail-sal fail-efw fail-fsp fail-util) + + foreach(exp ${EXPERIMENTS_ACTIVATED}) target_link_libraries(fail-sal fail-${exp}) endforeach() diff --git a/src/core/sal/ConcreteCPU.hpp b/src/core/sal/ConcreteCPU.hpp index 759c5b5d..efea0acf 100644 --- a/src/core/sal/ConcreteCPU.hpp +++ b/src/core/sal/ConcreteCPU.hpp @@ -25,6 +25,8 @@ #elif defined BUILD_PANDA #include "panda/PandaConfig.hpp" #include "panda/PandaArmCPU.hpp" +#elif defined BUILD_SAIL +#include "sail/SailCPU.hpp" #else #error SAL Config Target not defined #endif diff --git a/src/core/sal/Register.hpp b/src/core/sal/Register.hpp index b8804ddc..a775a961 100644 --- a/src/core/sal/Register.hpp +++ b/src/core/sal/Register.hpp @@ -27,8 +27,8 @@ enum RegisterType { RT_ST, //!< status register RT_CONTROL, //!< control registers RT_SEGMENT, //!< segmentation registers - - RT_TRACE //!< registers to be recorded in an extended trace + RT_TRACE, //!< registers to be recorded in an extended trace + RT_IMPL_SPECIFIC //!< simulator specific registers. }; /** @@ -54,6 +54,7 @@ class Register { */ Register(id_t id, regwidth_t w) : m_Width(w), m_Id(id) { } + virtual ~Register() {} /** * Returns the (fixed) width of this register. * @return the width in bits diff --git a/src/core/sal/SALConfig.cc b/src/core/sal/SALConfig.cc index 6a250103..d1ce1794 100644 --- a/src/core/sal/SALConfig.cc +++ b/src/core/sal/SALConfig.cc @@ -1,5 +1,10 @@ #include "SALConfig.hpp" +#if defined(BUILD_RISCV_CHERI) && defined(BUILD_64BIT) +#include "gmpxx.h" +#endif + + namespace fail { const char* memtype_descriptions[MEMTYPE_LAST] = { @@ -14,7 +19,7 @@ const char* memtype_descriptions[MEMTYPE_LAST] = { // (For now, the initialization values are all the same): #if defined BUILD_BOCHS || defined BUILD_GEM5 || \ defined BUILD_T32 || defined BUILD_QEMU || \ - defined BUILD_PANDA + defined BUILD_PANDA || defined BUILD_SAIL const address_t ADDR_INV = static_cast (0); const address_t ANY_ADDR = static_cast (-1); const memory_type_t ANY_MEMORY = static_cast (-1); @@ -26,4 +31,28 @@ const timer_id_t INVALID_TIMER = static_cast (0); #error SAL Config Target not defined #endif +#if defined(BUILD_RISCV_CHERI) && defined(BUILD_64BIT) + +std::ostream& operator<<(std::ostream& os, unsigned __int128 v) { + mpz_class result; + result = static_cast(v >> 64 & UINT64_MAX); + result <<= 64; + result += static_cast(v & UINT64_MAX); + return (os << result); +} + +std::istream& operator>>(std::istream& is, unsigned __int128& v) { + mpz_class input; + unsigned __int128 hi, lo; + is >> input; + lo = input.get_ui(); + input >>= 64; + hi = input.get_ui(); + v = hi << 64 | lo; + return is; +} + +#endif + + } // end-of-namespace: fail diff --git a/src/core/sal/SALConfig.hpp b/src/core/sal/SALConfig.hpp index 561b57f9..f97af03c 100644 --- a/src/core/sal/SALConfig.hpp +++ b/src/core/sal/SALConfig.hpp @@ -18,6 +18,8 @@ #include "t32/T32Config.hpp" #elif defined BUILD_PANDA #include "panda/PandaConfig.hpp" +#elif defined BUILD_SAIL + #include "SailArchConfig.hpp" #else #error SAL Config Target not defined #endif @@ -35,7 +37,17 @@ typedef uint64_t simtime_t; //! backend-specific notion of time difference typedef int64_t simtime_diff_t; +// define additional ostream operators for 128 bit integers +#if defined(BUILD_RISCV_CHERI) && defined(BUILD_64BIT) +std::ostream& operator<<(std::ostream& os, unsigned __int128 v); +std::istream& operator>>(std::istream& is, unsigned __int128& v); +#endif + + typedef enum { + // Only append values at this point. These are MAGIC constants, + // that are encoded in different emulators. Do not change their + // value. MEMTYPE_UNKNOWN = 0x0, //!< Somehow, we do not know MEMTYPE_RAM = 0x1, //!< Access to volatile memory MEMTYPE_FLASH = 0x2, //!< Access to flash memory diff --git a/src/core/sal/SALInst.hpp b/src/core/sal/SALInst.hpp index 9c2ca52c..528a1265 100644 --- a/src/core/sal/SALInst.hpp +++ b/src/core/sal/SALInst.hpp @@ -44,6 +44,14 @@ namespace fail { typedef PandaController ConcreteSimulatorController; //!< concrete simulator (type) } +#elif defined BUILD_SAIL + +#include "sail/SailSimulator.hpp" + +namespace fail { +typedef SailSimulator ConcreteSimulatorController; //!< concrete simulator (type) +} + #else #error SAL Instance not defined diff --git a/src/core/sal/faultspace/CMakeLists.txt b/src/core/sal/faultspace/CMakeLists.txt index 13e2fa12..ce1b788a 100644 --- a/src/core/sal/faultspace/CMakeLists.txt +++ b/src/core/sal/faultspace/CMakeLists.txt @@ -3,4 +3,9 @@ add_library(fail-fsp MemoryArea.cc RegisterArea.cc ../x86/X86FaultSpace.cc + ../arm/ArmFaultSpace.cc ) + +if (BUILD_SAIL) + target_link_libraries(fail-fsp fail-sail) +endif(BUILD_SAIL) diff --git a/src/core/sal/faultspace/FaultSpace.hpp b/src/core/sal/faultspace/FaultSpace.hpp index 898c5e73..96e9497d 100644 --- a/src/core/sal/faultspace/FaultSpace.hpp +++ b/src/core/sal/faultspace/FaultSpace.hpp @@ -14,6 +14,11 @@ typedef X86FaultSpace FaultSpace; namespace fail { typedef ArmFaultSpace FaultSpace; } +#elif defined(BUILD_SAIL) +#include "SailArchFaultSpace.hpp" +namespace fail { +typedef SailFaultSpace FaultSpace; +} #else #error Architecture does not yet support the Virtual Fault Space abstraction #endif diff --git a/src/core/sal/sail/CMakeLists.txt b/src/core/sal/sail/CMakeLists.txt new file mode 100644 index 00000000..753f0371 --- /dev/null +++ b/src/core/sal/sail/CMakeLists.txt @@ -0,0 +1,22 @@ +set(SRCS) + +if(BUILD_RISCV_CHERI) + set(SRCS ${SRCS} + ${SAIL_ARCH}/SailTagMemoryManager.cc) +endif(BUILD_RISCV_CHERI) + +add_library(fail-sail + # Architecture independent + SailArchitecture.cc + SailCPU.cc + SailSimulator.cc + SailMemoryManager.cc + SailFailInterface.cc + # Architecture dependend: + ${SAIL_ARCH}/SailArchRegisters.cc + ${SAIL_ARCH}/SailArchFaultSpace.cc + ${SAIL_ARCH}/SailArchSimulator.cc + ${SRCS} +) + +target_link_libraries(fail-sail fail-fsp) diff --git a/src/core/sal/sail/SailArchitecture.cc b/src/core/sal/sail/SailArchitecture.cc new file mode 100644 index 00000000..4a901790 --- /dev/null +++ b/src/core/sal/sail/SailArchitecture.cc @@ -0,0 +1,45 @@ +#include "../Register.hpp" +#include "SailArchitecture.hpp" +#include "SailArchRegisters.hpp" +#include "SailArchRegistersExtern.hpp" + +using namespace fail; + +SailArchitecture::SailArchitecture() { + Register *reg; +#define SAIL_REG_PTR(id, width, classes, variable) \ + reg = new SailRegisterPtr(RID_ ## id, width, &(variable)); \ + reg->setName(#id); \ + m_addRegister(reg, classes); + +#define SAIL_REG_FN(id, width, classes, fn_name) \ + reg = new SailRegisterFn(RID_ ## id, width); \ + reg->setName(#id); \ + m_addRegister(reg, classes); + +#define SAIL_REG_CLASS(id, width, classes, CLS,variable) \ + reg = new CLS(RID_ ## id, width, &(variable)); \ + reg->setName(#id); \ + m_addRegister(reg, classes); + +#define SAIL_REG_TMPL(id, width, classes, TMPL,variable) \ + reg = new TMPL(RID_ ## id, width, &(variable)); \ + reg->setName(#id); \ + m_addRegister(reg, classes); + +#include "SailArchRegisters.inc" + +#undef SAIL_REG_PTR +#undef SAIL_REG_FN +#undef SAIL_REG_CLASS +#undef SAIL_REG_TMPL + +} + +SailArchitecture::~SailArchitecture() { + for (auto reg : m_Registers) { + if (reg) delete reg; + } + m_Registers.clear(); +} + diff --git a/src/core/sal/sail/SailArchitecture.hpp b/src/core/sal/sail/SailArchitecture.hpp new file mode 100644 index 00000000..348ddccc --- /dev/null +++ b/src/core/sal/sail/SailArchitecture.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include "../CPU.hpp" +#include "../SALConfig.hpp" +#include + + +namespace fail { + +/** + * \class SailArchitecture + * + * For a SAIL architecture, we generate a custom CPU architecture that + * depends on specific registers for that architecture. + */ +class SailArchitecture : public CPUArchitecture { +public: + SailArchitecture(); + ~SailArchitecture(); + + simtime_t getInstructionCounter() const; +}; + +typedef SailArchitecture Architecture; + +// Register IDs +enum RegisterID { +#define SAIL_REG_PTR(id,...) RID_##id, +#define SAIL_REG_FN(id,...) RID_##id, +#define SAIL_REG_TMPL(id,...) RID_##id, +#define SAIL_REG_CLASS(id,...) RID_##id, + +#include "SailArchRegisters.inc" + +#undef SAIL_REG_PTR +#undef SAIL_REG_FN +#undef SAIL_REG_TMPL +#undef SAIL_REG_CLASS +}; + +/** + * \class SailRegister + * + * Sail Registers are at most regdata_t wide and have a read and a write function + */ +class SailRegister: public Register { +private: + friend std::ostream& operator<<(std::ostream& os, const SailRegister& r); + friend std::istream& operator>>(std::istream& is, const SailRegister& r); +public: + SailRegister(id_t id, regwidth_t w) : Register(id, w) { + assert(w <= sizeof(regdata_t) * 8); + } + virtual regdata_t read() const = 0; + virtual void write(regdata_t val) const = 0; +}; + +inline std::ostream& operator<<(std::ostream& os, const SailRegister& r) { + regdata_t value = r.read(); + os << value; + return os; +} +inline std::istream& operator>>(std::istream& is, const SailRegister& r) { + regdata_t dummy; + is >> dummy; + r.write(dummy); + return is; +} + +template +class SailRegisterPtr: public SailRegister { + T* m_ref; + +public: + SailRegisterPtr(id_t id, regwidth_t w, T* ref) + : SailRegister(id, w), m_ref(ref) {} + + virtual regdata_t read() const { + assert(m_ref); + return (regdata_t) *m_ref; + } + + virtual void write(regdata_t val) const { + assert(m_ref); + *m_ref = (T) val; + } +}; + +template +class SailRegisterFn: public SailRegister { +public: + SailRegisterFn(id_t id, regwidth_t w): SailRegister(id, w) {} + virtual regdata_t read() const { + return RFn(); + } + virtual void write(regdata_t val) const { + return WFn(val); + } +}; + + +} // end-of-namespace: fail + diff --git a/src/core/sal/sail/SailCPU.cc b/src/core/sal/sail/SailCPU.cc new file mode 100644 index 00000000..9f93c6f8 --- /dev/null +++ b/src/core/sal/sail/SailCPU.cc @@ -0,0 +1,23 @@ +#include "SailCPU.hpp" + +using namespace fail; + +SailBaseCPU::SailBaseCPU(unsigned int id) + : id(id) { + pc_reg = getRegister(RID_PC); + sp_reg = getRegister(RID_SP); +} + +void SailBaseCPU::serialize(std::ostream& os) { + for (Register *reg : *static_cast(this)) { + os << getRegisterContent(reg) << " "; + } +} + +void SailBaseCPU::unserialize(std::istream& is) { + for (Register *reg : *static_cast(this)) { + regdata_t data; + is >> data; + setRegisterContent(reg, data); + } +} diff --git a/src/core/sal/sail/SailCPU.hpp b/src/core/sal/sail/SailCPU.hpp new file mode 100644 index 00000000..8e8e340f --- /dev/null +++ b/src/core/sal/sail/SailCPU.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "SailArchitecture.hpp" +#include "../CPUState.hpp" + +namespace fail { + +class SailBaseCPU: public SailArchitecture, public CPUState { +protected: +private: + unsigned int id; + +protected: + Register *pc_reg; + Register *sp_reg; + +public: + SailBaseCPU(): SailBaseCPU(0) { } + SailBaseCPU(unsigned int id); + virtual ~SailBaseCPU() {} + + //////////////////////////////////////////////////////////////// + // CPUState interface + regdata_t getRegisterContent(const Register* r) const { + return static_cast(r)->read(); + } + + void setRegisterContent(const Register* r, regdata_t value) { + static_cast(r)->write(value); + } + + address_t getInstructionPointer() const { + return getRegisterContent(pc_reg); + } + + address_t getStackPointer() const { + return getRegisterContent(sp_reg); + } + + simtime_t getInstructionCounter() const { + return SailArchitecture::getInstructionCounter(); + } + + constexpr simtime_t getFrequency() const { return 100000; } + + unsigned int getId() const { return id; } + + // CPU serialization and deserialization + void serialize(std::ostream& os); + void unserialize(std::istream& is); + + // lifecycle + void reset() { + setRegisterContent(pc_reg, SAIL_RESET_VECTOR); + } +}; + +} // end-of-namespace: fail + +// Declares SailCPU +#include "SailArchCPU.hpp" + +namespace fail { +typedef SailCPU ConcreteCPU; +} diff --git a/src/core/sal/sail/SailFailInterface.cc b/src/core/sal/sail/SailFailInterface.cc new file mode 100644 index 00000000..39b8688e --- /dev/null +++ b/src/core/sal/sail/SailFailInterface.cc @@ -0,0 +1,127 @@ +#include "SailFailInterface.h" +#include "sal/SALInst.hpp" +#include "sal/SALConfig.hpp" +#include "SailSimulator.hpp" +#include +#include + +static bool inIFetch = false; + +using namespace fail; + +extern "C" { +void fail_startup(int *argc, char*** argv) { + // This will manipulate the argc and argv, such that the FAIL* + // arguments are filtered out + fail::simulator.startup(*argc, *argv); +} + +int fail_onGuestSystem(char data, unsigned port) { + #if defined(CONFIG_EVENT_GUESTSYS) + fail::simulator.onGuestSystem(data, port); + #endif + return 0; +} + +int fail_onMemoryRead(uint64_t addr, mpz_t data, mpz_t size, uint64_t mem_type, uint64_t instrPtr) { +#if defined(CONFIG_EVENT_MEMREAD) + if(!inIFetch) { + static bool warned_once = false; + if(!mpz_fits_ulong_p(data) && !warned_once) { + std::cerr << "[sail wrapper] warning once: can't fit accessed data into 8-byte, extended trace information will be truncated!" << std::endl; + warned_once = true; + } + + // alternatively one could create a vector of arbitrary length here, but trace_event_extended only supports + // upto 8 byte extended trace information anyway. + // fixme: uint64_t udata = mpz_get_ui(data); + size_t bitsize = mpz_get_ui(size); + assert(bitsize >= mpz_sizeinbase(data, 2)); + + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + + fail::simulator.onMemoryAccess(&triggerCPU, addr, bitsize, false, instrPtr, + static_cast(mem_type)); + } +#endif + return 0; +} + +int fail_onMemoryWrite(uint64_t addr, mpz_t data, mpz_t size, uint64_t mem_type, uint64_t instrPtr) { +#if defined(CONFIG_EVENT_MEMWRITE) + static bool warned_once = false; + if(!mpz_fits_ulong_p(data) && !warned_once) { + std::cerr << "[sail wrapper] warning once: can't fit accessed data into 8-byte, extended trace information will be truncated!" << std::endl; + warned_once = true; + } + + // alternatively one could create a vector of arbitrary length here, but Trace_Event_Extended only supports + // upto 8 byte extended trace information anyway. + // FIXME: uint64_t udata = mpz_get_ui(data); + size_t bitsize = mpz_get_ui(size); + assert(bitsize >= mpz_sizeinbase(data, 2)); + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + + fail::simulator.onMemoryAccess(&triggerCPU, addr, bitsize, true, instrPtr, static_cast(mem_type)); +#endif + return 0; +} + +int fail_willExecuteInstruction(uint64_t instrPtr) { +#if defined(CONFIG_EVENT_BREAKPOINTS) || defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + // always address space 0 + fail::simulator.onBreakpoint(&triggerCPU, instrPtr, 0); +#endif + return 0; +} + +int fail_executeRequests() { +#if defined(CONFIG_SR_SAVE) || defined(CONFIG_SR_RESTORE) + fail::simulator.checkTimers(); + fail::simulator.executeRequests(); +#endif + return 0; +} + +int fail_didExecuteInstruction(uint64_t instrPtr, uint64_t instr) { +#if defined(CONFIG_EVENT_JUMP) + if (fail::simulator::isJump(instrPtr, instr)) { + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + fail::simulator.onJump(&triggerCPU, false, instr); + } +#endif + return 0; +} + +int fail_onTrap(unsigned trapNum) { +#if defined(CONFIG_EVENT_TRAP) + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + fail::simulator.onTrap(&triggerCPU, trapNum); +#endif + return 0; +} + +int fail_onInterrupt(unsigned interruptNum, bool nmi) { +#if defined(CONFIG_EVENT_INTERRUPT) + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + fail::simulator.onInterrupt(&triggerCPU, interruptNum, nmi); +#endif + return 0; +} + +bool fail_isSuppressedInterrupt(unsigned interruptNum) { +#if defined(CONFIG_SUPPRESS_INTERRUPTS) + fail::ConcreteCPU& triggerCPU = fail::simulator.getCPU(0); + return triggerCPU.isSuppressedInterrupt(interruptNum); +#endif + return false; +} + + +int fail_setInstructionFetch(bool instructionFetch) { + inIFetch = instructionFetch; + return 0; +} + +} // extern "C" diff --git a/src/core/sal/sail/SailFailInterface.h b/src/core/sal/sail/SailFailInterface.h new file mode 100644 index 00000000..b5a2638d --- /dev/null +++ b/src/core/sal/sail/SailFailInterface.h @@ -0,0 +1,100 @@ +#ifndef SAILWRAPPER_H +#define SAILWRAPPER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Wrapper function for SailController::startup(). + * @param argc main()'s argument counter + * @param argv main()'s argument value vector + */ + +void fail_startup(int* argc, char*** argv); +/** + * Wrapper function for SailController::onGuestSystem(). Has to be executed + * after a guest system communication call. + * @param data the "message" from the guest system + * @param port the port used for communications + */ +int fail_onGuestSystem(char data, unsigned port); +/** + * Wrapper function for SailController::onMemoryAccess() triggered by a memory + * read. Has to be executed before a memory read operation. + * The memory read event is surpressed, if the simulator is currently fetching + * an instruction from memory. + * @param addr the accessed memory address + * @param data the accessed data + * @param mem_type the type of memory which was accessed, must be convertible to memory_type_t. + * @param instrPtr the address of the instruction causing the memory + * access + */ +int fail_onMemoryRead(uint64_t addr, mpz_t data, mpz_t size, uint64_t mem_type, uint64_t instrPtr); +/** + * Wrapper function for SailController::onMemoryAccess(). Has to be executed + * after a memory write operation. + * @param addr the accessed memory address + * @param data the accessed data + * @param mem_type the type of memory which was accessed, must be convertible to memory_type_t. + * @param instrPtr the address of the instruction causing the memory + * access + */ +int fail_onMemoryWrite(uint64_t addr, mpz_t data, mpz_t size, uint64_t mem_type, uint64_t instrPtr); + +/** + * Wrapper function for SailController::onBreakpoint(). + * Has to be execute before the instruction is fetched, and before any hooks are executed + * through fail_executeHooks() since this may add additional save/restore hooks. + * @param instrPtr the instruction pointer which will be executed + */ +int fail_willExecuteInstruction(uint64_t instrPtr); + +/** + * Wrapper function to check & execute any pending FAIL requests, such as save and restore. + * Must be called _after_ onWillExecuteInstruction but _before_ any processing of the instruction begins. + */ +int fail_executeRequests(); + +/** + * Wrapper function for SailController::onJump. + * Has to be executed after an instruction has been fully processed, but before the next instruction is prepared + * XXX: this is untested! + * @param instrPtr The instruction pointer which was executed. + * @param instr The instruction which was executed. + */ +int fail_didExecuteInstruction(uint64_t instrPtr, uint64_t instr); +/** + * Wrapper function for SailController::onTrap(). Has to be executed before + * the trap handling is executed. + * @param trapNum the trap-type id + */ +int fail_onTrap(unsigned trapNum); +/** + * Wrapper function for SailController::onInterrupt(). Has to be executed before + * the interrupt handling is executed. + * @param interruptNum the interrupt-type id + * @param nmi nmi-value from guest-system + */ +int fail_onInterrupt(unsigned interruptNum, bool nmi); +/** + * Wrapper function for ConcreteCPU::isSuppressedInterrupt(). Has the be executed + * before the interrupt handling is executed. + * @param interruptNum the interrupt-type id + * @return \c true if the interrupt is suppressed, \c false otherwise + */ +bool fail_isSuppressedInterrupt(unsigned interruptNum); +/** + * Wrapper function for SailController::setInstructionFetch(). Set to true before + * an instruction fetch from memory and to false after the instrucion was fetched. + */ +int fail_setInstructionFetch(bool instructionFetch); + +#ifdef __cplusplus +} // end extern "C" +#endif + +#endif /* SAILWRAPPER_H */ diff --git a/src/core/sal/sail/SailMemoryExtern.hpp b/src/core/sal/sail/SailMemoryExtern.hpp new file mode 100644 index 00000000..d666e4cd --- /dev/null +++ b/src/core/sal/sail/SailMemoryExtern.hpp @@ -0,0 +1,45 @@ +//! The sail internal memory structure +struct block { + uint64_t block_id; + uint8_t *mem; + struct block *next; +}; +//! sail-internal tag memory structure +struct tag_block { + uint64_t block_id; + bool *mem; + struct tag_block *next; +}; + +//! weak-reference to start of sail memory +extern "C" __attribute__((weak)) struct block *sail_memory; +//! weak-symbol to beginning of tag memory linked-list. +extern "C" __attribute__((weak)) struct tag_block *sail_tags; +//! weak-reference to block mask. +extern "C" __attribute__((weak)) uint64_t MASK; + +/** + * Retrieves the data at \a address from the sail memory representation. + * @param address The address where the data is located. + * @return The data at \a address. + */ +extern "C" __attribute__((weak)) uint64_t read_mem(uint64_t address); +/** + * Writes the data to \a address in the memory. + * @param address The address to write. + * @param byte The new data to write. + */ +extern "C" __attribute__((weak)) void write_mem(uint64_t address, uint64_t byte); + +/** + * Sail-internal function to read a tag bit at the specified \a address. + * \param address The address of which the tag bit should be returned. + * \return The tag bit at the specified address. + */ +extern "C" __attribute__((weak)) bool read_tag_bool(const uint64_t address); +/** + * Sail-internal function to write a tag bit for the given \a address. + * \param address The address at which the tag bit will be modified. + * \param tag Which tag to write at the address. + */ +extern "C" __attribute__((weak)) int write_tag_bool(const uint64_t address, const bool tag); diff --git a/src/core/sal/sail/SailMemoryManager.cc b/src/core/sal/sail/SailMemoryManager.cc new file mode 100644 index 00000000..0bc85dcf --- /dev/null +++ b/src/core/sal/sail/SailMemoryManager.cc @@ -0,0 +1,157 @@ +#include +#include +#include "SailMemoryManager.hpp" +#include "SailMemoryExtern.hpp" + +using namespace fail; + + +size_t SailMemoryManager::getPoolSize() const { + return ULONG_MAX; //Return unsinged long max since pool size is dynamic +} + +host_address_t SailMemoryManager::getStartAddr() const { + return 0; +} + +byte_t SailMemoryManager::getByte(guest_address_t addr) { + if(read_mem) + return static_cast(read_mem(addr)); + else + throw std::runtime_error("can't read memory, simulator not linked!"); +} + +void SailMemoryManager::getBytes(guest_address_t addr, size_t cnt, + void *dest) { + char *d = static_cast(dest); + for (size_t i = 0; i < cnt; ++i) d[i] = getByte(addr + i); +} + +void SailMemoryManager::setByte(guest_address_t addr, byte_t data) { + if(write_mem) { + write_mem(addr, data); + } + else + throw std::runtime_error("can't write memory, simulator not linked"); +} + +void SailMemoryManager::setBytes(guest_address_t addr, size_t cnt, void const *src) { + char const *s = static_cast(src); + for (size_t i = 0; i < cnt; ++i) setByte(addr + i, s[i]); +} + +bool SailMemoryManager::isMapped(guest_address_t addr) { + if(!sail_memory) throw std::runtime_error("can't access memory, simulator not linked"); + + if(sail_memory) { + uint64_t address = static_cast(addr); + uint64_t mask = address & ~MASK; + struct block *current = sail_memory; + + while (current != NULL) { + if (current->block_id == mask) { + return true; + } else { + current = current->next; + } + } + } else throw std::runtime_error("can't access memory, simulator not linked"); + + return false; +} + +void SailMemoryManager::serialize(std::ostream& os) { + // at least this must be != NULL, otherwise + // we can safely assume that the simulator has not been linked + // in theory both, sail_memory and sail_tags could be NULL if the simulator hasn't actually accessed any memory + // but since we are executing a program, at the very least that + // has been loaded to memory + if(!sail_memory) throw std::runtime_error("can't access memory, simulator not linked"); + if(!os) throw std::runtime_error("can't open ostream."); + + const size_t blk_len = (MASK + 1); + const size_t blk_size = blk_len*sizeof(uint8_t); + + unsigned long cnt = 0; + block* start = sail_memory; + while(sail_memory != NULL) { + std::cout << "serializing memory block (id=" << sail_memory->block_id << ",size=" << blk_size << ")" +#if 0 + + << std::endl + << std::hex + << "\tm[0] = 0x" << (int)sail_memory->mem[0] << std::endl + << "\tm[1] = 0x" << (int)sail_memory->mem[1] << std::endl + << "\tm[2] = 0x" << (int)sail_memory->mem[2] << std::endl + << "\tm[3] = 0x" << (int)sail_memory->mem[3] << std::endl + << std::endl; +#else + << std::endl; +#endif + os.write(reinterpret_cast(&sail_memory->block_id), sizeof(sail_memory->block_id)); + os.write(reinterpret_cast(sail_memory->mem), blk_size); + sail_memory = sail_memory->next; + cnt++; + } + std::cout << "serialized " << cnt << " memory blocks" << std::endl; + sail_memory = start; +} + +void SailMemoryManager::unserialize(std::istream& is) { + if(!is) throw std::runtime_error("can't open istream."); + + reset(); + const size_t blk_len = (MASK + 1); + const size_t blk_size = blk_len*sizeof(uint8_t); + + unsigned cnt = 0; + block* last = nullptr; + while(is) { + block *b = new block; + b->mem = new uint8_t[blk_len]; + b->next = NULL; + + is.read(reinterpret_cast(&b->block_id), sizeof(b->block_id)); + is.read(reinterpret_cast(b->mem), blk_size); + if(is.fail()) { + // XXX: we must check here, since is.eof() will return false, even if the end-of-file has been reached. + // it will only return true if the is has been used to read unsuccessfully + delete b->mem; + delete b; + break; + } + std::cout << "unserializing memory block (id=" << b->block_id << ",size=" << blk_size << ")" +#if 0 + << std::endl + << std::hex + << "\tm[0] = 0x" << (int)b->mem[0] << std::endl + << "\tm[1] = 0x" << (int)b->mem[1] << std::endl + << "\tm[2] = 0x" << (int)b->mem[2] << std::endl + << "\tm[3] = 0x" << (int)b->mem[3] << std::endl + << std::endl; +#else + << std::endl; +#endif + + if(sail_memory == nullptr){ + sail_memory = b; + } else if (last != nullptr) { + last->next = b; + } else { throw std::runtime_error("sail_memory is not empty, can't unserialize!"); } + + last = b; + cnt++; + } + std::cerr << "unserialized " << cnt << " mem blocks with size: " << blk_size << std::endl; +} + +void SailMemoryManager::reset() { + while(sail_memory != NULL) { + block *next = sail_memory->next; + + delete sail_memory->mem; + delete sail_memory; + + sail_memory = next; + } +} diff --git a/src/core/sal/sail/SailMemoryManager.hpp b/src/core/sal/sail/SailMemoryManager.hpp new file mode 100644 index 00000000..7ef5bb24 --- /dev/null +++ b/src/core/sal/sail/SailMemoryManager.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "../Memory.hpp" +#include + + +//TODO: does the memory injection work, if there are only blocks of memory far apart +namespace fail { +/** + * \class SailMemoryManager + * Represents a concrete implemenation of the abstract + * MemoryManager to provide access to Sails memory pool. + */ +class SailMemoryManager : public MemoryManager { + public: + /** + * Constructs a new MemoryManager object and initializes + * it's attributes appropriately. + */ + SailMemoryManager() : MemoryManager() { } + /** + * Retrieves the size of the currently allocated memory blocks. + * @return the size of the currently allocated memory blocks in bytes + */ + size_t getPoolSize() const; + /** + * Retrieves the starting address of the host memory. This is the + * first valid address in memory. + * @return the starting address + */ + host_address_t getStartAddr() const; + /** + * Retrieves the byte at address \a addr in the memory. + * @param addr The guest address where the byte is located. + * @return the byte at \a addr + */ + byte_t getByte(guest_address_t addr); + /** + * Retrieves \a cnt bytes at address \a addr from the memory. + * @param addr The guest address where the bytes are located. + * @param cnt The number of bytes to be retrieved. + * @param dest Pointer to destination buffer to copy the data to. + */ + void getBytes(guest_address_t addr, size_t cnt, void *dest); + /** + * Writes the byte \a data to memory. + * @param addr The guest address to write. + * @param data The new byte to write + */ + void setByte(guest_address_t addr, byte_t data); + /** + * Copies data to memory. + * @param addr The guest address to write. + * @param cnt The number of bytes to be retrieved. + * @param src Pointer to data to be copied. + */ + void setBytes(guest_address_t addr, size_t cnt, void const *src); + /** + * Checks whether memory is mapped and available. + * @param addr The guest address to check. + */ + bool isMapped(guest_address_t addr); + /** + * Serialize the memory state to output streams. + * @param mem_os The output stream for memory blocks. + * @param tag_os The output stream for memory tag blocks. + */ + void serialize(std::ostream& os); + + /** + * Unserialize the memory state from an input streams. + * @param mem_is The input stream for memory blocks. + * @param tag_is The input stream for memory tag blocks. + */ + void unserialize(std::istream& is); + + /** + * Reset the memory state + */ + void reset(); +}; + +} // namespace fail + diff --git a/src/core/sal/sail/SailSimulator.cc b/src/core/sal/sail/SailSimulator.cc new file mode 100644 index 00000000..0c9f615d --- /dev/null +++ b/src/core/sal/sail/SailSimulator.cc @@ -0,0 +1,121 @@ +#include "SailSimulator.hpp" +#include "../Listener.hpp" +#include +#include "SailCPU.hpp" + +using namespace fail; + +SailBaseSimulator::SailBaseSimulator() + : SimulatorController() { + setMemoryManager(&m_mem_manager); + addCPU(new ConcreteCPU(0)); +} + +SailBaseSimulator::~SailBaseSimulator() { + auto it = m_CPUs.begin(); + while (it != m_CPUs.end()) { + delete *it; + it = m_CPUs.erase(it); + } +} + +void SailBaseSimulator::do_save(const std::string& base) { + // create base directory if it does not exist + // XXX: c++17 use + assert(base.size() > 0 && "FATAL ERROR: tried to save state without valid path"); + std::string mkdirState("mkdir -p "); + mkdirState.append(base); + int status = system(mkdirState.c_str()); + if (status == -1) { + throw std::runtime_error("[FAIL] Error: do_save() directory creation failed"); + } + + // serialize registers + std::string reg_base = base + "/registers"; + for(const auto c: m_CPUs) { + std::ofstream f { reg_base + std::to_string(c->getId())}; + if (!f.is_open()) throw std::runtime_error("[FAIL] couldnt open register file for writing"); + c->serialize(f); + } + // serialize memory + std::ofstream fm { base + "/memory", std::ios::binary }; + if (!fm.is_open()) throw std::runtime_error("[FAIL] couldnt open memory file for writing"); + m_mem_manager.serialize(fm); + +} +void SailBaseSimulator::do_restore(const std::string& base) { + // unserialize registers + std::string reg_base = base + "/registers"; + for( const auto c: m_CPUs ) { + std::ifstream f { reg_base + std::to_string(c->getId()) }; + if (!f.is_open()) throw std::runtime_error("[FAIL] couldnt open register file for reading"); + c->unserialize(f); + } + + // unserialize memory + std::ifstream fm { base + "/memory", std::ios::binary }; + if (!fm.is_open()) throw std::runtime_error("[FAIL] couldnt open memory file for reading"); + m_mem_manager.unserialize(fm); +} + + +bool SailBaseSimulator::save(const std::string& path) { +#if defined(CONFIG_SR_SAVE) + queueRequest(req_type::save, path); + return true; +#else + return false; +#endif +} + +void SailBaseSimulator::restore(const std::string& path) { +#if defined(CONFIG_SR_RESTORE) + clearListeners(); + queueRequest(req_type::restore, path); +#endif +} + +void SailBaseSimulator::reboot() { + m_mem_manager.reset(); + for(const auto c: m_CPUs) + c->reset(); +} + +void SailBaseSimulator::executeRequests() { + while(!requests.empty()) { + auto e = requests.front(); + requests.pop_front(); + if(e.t == req_type::save) + do_save(e.path); + else if(e.t == req_type::restore) + do_restore(e.path); + m_Flows.toggle(e.parent); + } +} + +void SailBaseSimulator::checkTimers() { + const auto ticks = getTimerTicks(); + + ListenerManager::iterator it = m_LstList.begin(); + while(it != m_LstList.end()) { + BaseListener* pev = *it; + if(auto t = dynamic_cast(pev)) { + if(t->getTimeout() <= ticks) { + std::cout << "xxx" << t->getTimeout() << " timer has gone off" << std::endl; + it = m_LstList.makeActive(it); + continue; + } + } + it++; + } + m_LstList.triggerActiveListeners(); +} + +simtime_t SailBaseSimulator::getTimerTicks() { + return getCPU(0).getInstructionCounter(); +} + +simtime_t SailBaseSimulator::getTimerTicksPerSecond() { + return getCPU(0).getFrequency(); +} + diff --git a/src/core/sal/sail/SailSimulator.hpp b/src/core/sal/sail/SailSimulator.hpp new file mode 100644 index 00000000..098bd51d --- /dev/null +++ b/src/core/sal/sail/SailSimulator.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "../SALConfig.hpp" +#include "../SimulatorController.hpp" +#include "SailMemoryManager.hpp" +#include + +namespace fail { + +/** + * \class SailController + * Sail-specific implementation of a SimulatorController. + */ +class SailBaseSimulator: public SimulatorController { +private: + enum class req_type: short { + save, restore + }; + struct request { + const req_type t; + const std::string path; + ExperimentFlow* parent; + request(const req_type t, const std::string p, ExperimentFlow* f): t(t),path(p),parent(f) {} + }; + + std::deque requests = {}; + + void queueRequest(req_type t, const std::string& p) { + requests.emplace_back(t, p, m_Flows.getCurrent()); + m_Flows.resume(); + } + + SailMemoryManager m_mem_manager; + +protected: + virtual void do_save(const std::string& base) ; + virtual void do_restore(const std::string& base); + +public: + SailBaseSimulator(); + ~SailBaseSimulator(); + bool save(const std::string& path); + void restore(const std::string& path); + + void reboot(); + + // called by Sail wrapper code to execute any + // pending save/restore requests + void executeRequests(); + + void checkTimers(); + + // XXX: find a way to make this configurable + // to be either a cpu specific value or a + // device. + // for now just use inst count of cpu 0 + simtime_t getTimerTicks(); + simtime_t getTimerTicksPerSecond(); +}; + +} // namespace fail + +// Declares SailSimulator +#include "SailArchSimulator.hpp" diff --git a/src/core/sal/sail/cheri-riscv/SailArchCPU.hpp b/src/core/sal/sail/cheri-riscv/SailArchCPU.hpp new file mode 100644 index 00000000..048c932b --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchCPU.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "../SailCPU.hpp" + +namespace fail { +class SailCPU : public SailBaseCPU { +public: + SailCPU(unsigned int id) : SailBaseCPU(id) { + pc_reg = getRegister(RID_RAW_PC); + } + virtual ~SailCPU() {} +}; +} + diff --git a/src/core/sal/sail/cheri-riscv/SailArchConfig.hpp b/src/core/sal/sail/cheri-riscv/SailArchConfig.hpp new file mode 100644 index 00000000..80c1d38e --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchConfig.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace fail { +typedef uint64_t guest_address_t; //!< the guest memory address type +typedef uint64_t host_address_t; //!< the host memory address type +typedef unsigned int timer_t; //!< type of timer IDs + +/** + * For CHERI enabled RISC-V, all GP register may hold + * up to length(capability) bits, which is 2*XLEN for + * CHERI concentrate representation. + * NOTE: This uses the GCC builtin 128 bit unsigned integer type. + * And thus is not compatible with LLVM. + */ +#if defined(BUILD_64BIT) +typedef unsigned __int128 register_data_t; +#define SAIL_XLEN 64 +#else +typedef uint64_t register_data_t; +#define SAIL_XLEN 32 +#endif + +#define SAIL_RESET_VECTOR 0x8000000 + +} diff --git a/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.cc b/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.cc new file mode 100644 index 00000000..21c22034 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.cc @@ -0,0 +1,38 @@ +#include +#include "SailArchFaultSpace.hpp" +#include "SailArchRegisters.hpp" +#include "sal/sail/SailArchitecture.hpp" +#include "sal/faultspace/MemoryArea.hpp" +#include "sal/faultspace/RegisterArea.hpp" + +using namespace fail; + +std::vector> +SailCheriRegisterArea::translate(const RegisterView &view) { + auto ret = RegisterArea::translate(view); + Register* base = m_arch.getRegister(view.id); + if (auto reg = dynamic_cast(base)) { + SailRegisterCheriTags* regtags = dynamic_cast( + m_arch.getRegister(RID_REGTAGS)); + unsigned offset = regtags->getTagIndex(reg); + RegisterView view_tag(RID_REGTAGS, 1, offset); + + for (auto pair : RegisterArea::translate(view_tag)) { + ret.push_back(pair); + } + } + return ret; +} + +SailFaultSpace::SailFaultSpace() { + // Order Matters! + // 4GiB of RAM + add_area(std::make_unique("ram", 0, 0xffffffff)); + set_point(1L<<32); + // The Tag memory + add_area(std::make_unique("tags", 0, 0xffffffff)); + set_point(2L<<32); + // The Registers + add_area(std::make_unique()); +} + diff --git a/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.hpp b/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.hpp new file mode 100644 index 00000000..31b77e8b --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchFaultSpace.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "sal/faultspace/BaseFaultSpace.hpp" +#include "sal/faultspace/RegisterArea.hpp" + + +namespace fail { + +class SailCheriRegisterArea: public RegisterArea { +public: + // We override the translate function to also touch the tag bit for capability registers + virtual std::vector> translate(const RegisterView &) override; +}; + +class SailFaultSpace: public BaseFaultSpace { +public: + SailFaultSpace(); +}; + +} // end-of-namespace: fail + diff --git a/src/core/sal/sail/cheri-riscv/SailArchRegisters.cc b/src/core/sal/sail/cheri-riscv/SailArchRegisters.cc new file mode 100644 index 00000000..24742153 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchRegisters.cc @@ -0,0 +1,31 @@ +#include +#include "../../SALConfig.hpp" +#include "../SailArchitecture.hpp" +#include "SailArchRegisters.hpp" +#include "SailArchRegistersExtern.hpp" + +using namespace fail; + +regdata_t fail::minstret_written() { + return static_cast(zminstret_written); +} + +void fail::minstret_written(regdata_t value) { + zminstret_written = static_cast(value); +} + +regdata_t fail::parity_mismatch() { + if (&zparity_mismatch) + return static_cast(zparity_mismatch); + return 0; +} + +void fail::parity_mismatch(regdata_t value) { + if (&zparity_mismatch) + zparity_mismatch = static_cast(value); +} + + +simtime_t SailArchitecture::getInstructionCounter() const { + return static_cast(zminstret); +} diff --git a/src/core/sal/sail/cheri-riscv/SailArchRegisters.hpp b/src/core/sal/sail/cheri-riscv/SailArchRegisters.hpp new file mode 100644 index 00000000..6ac4bc56 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchRegisters.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include "../../SALConfig.hpp" +#include "SailArchRegistersExtern.hpp" + +namespace fail { + +#if defined(BUILD_64BIT) // CHERI64 +#include "gmp.h" + +extern "C" { + typedef struct { + mp_bitcnt_t len; + mpz_t * bits; +} lbits; +} + +extern "C" __attribute__((weak)) struct zCapability zmemBitsToCapability(bool, lbits); +extern "C" __attribute__((weak)) void zcapToMemBits(lbits*, struct zCapability); +extern "C" __attribute__((weak)) void create_lbits(lbits*); + +#else // CHERI32 +extern "C" __attribute__((weak)) struct zCapability zmemBitsToCapability(bool, uint64_t); +extern "C" __attribute__((weak)) uint64_t zcapToMemBits(struct zCapability); +#endif + + +class SailCapabilityRegister: public SailRegister { +public: + struct zCapability* m_ref; + + SailCapabilityRegister(id_t id, regwidth_t w, struct zCapability* ref) + : SailRegister(id, 2*w), m_ref(ref) {} + + virtual regdata_t read() const { + assert(m_ref); +#if defined(BUILD_64BIT) + lbits c; + create_lbits(&c); + zcapToMemBits(&c, *m_ref); + unsigned __int128 hi,lo; + lo = mpz_get_ui(*c.bits); + mpz_cdiv_q_2exp(*c.bits,*c.bits,64); + hi = mpz_get_ui(*c.bits); + return hi << 64 | lo; +#else + return static_cast(zcapToMemBits(*m_ref)); +#endif + } + + virtual void write(regdata_t val) const { + assert(m_ref); +#if defined(BUILD_64BIT) + lbits c; + create_lbits(&c); + uint64_t hi,lo; \ + hi = (val >> 64) & UINT64_MAX; + lo = val & UINT64_MAX; + mpz_set_ui(*c.bits, hi); + mpz_mul_2exp(*c.bits, *c.bits, 64); \ + mpz_add_ui(*c.bits, *c.bits, lo); + c.len = 128; + *m_ref = zmemBitsToCapability(m_ref->ztag, c); +#else + *m_ref = zmemBitsToCapability(m_ref->ztag, static_cast(val)); +#endif + } +}; + + +class SailRegisterCheriTags: public SailRegister { + std::vector m_regs; + +public: + SailRegisterCheriTags(id_t id, regwidth_t w, SailArchitecture* arch) + : SailRegister(id, w) { + for (Register *r : *arch) { + if (r == nullptr) continue; + if (auto *reg = dynamic_cast(r)) { + m_regs.push_back(reg); + } + } + assert(m_regs.size() < w && "can't fit all register tags into one regdata_t"); + } + + virtual regdata_t read() const { + regdata_t val = 0; + for(size_t i = 0; i < m_regs.size(); ++i) { + val |= (m_regs[i]->m_ref->ztag << i); + } + return val; + } + + virtual void write(regdata_t val) const { + for(size_t i = 0; i < m_regs.size(); ++i) { + m_regs[i]->m_ref->ztag = !!(val & (1 << i)); + } + } + + unsigned getTagIndex(SailCapabilityRegister *reg) const { + for(size_t i = 0; i < m_regs.size(); ++i) { + if (m_regs[i]->getId() == reg->getId()) { + return i; + } + } + throw std::runtime_error("Unknown capability register"); + } +}; + + +extern regdata_t minstret_written(); +extern void minstret_written(regdata_t value); + +extern regdata_t parity_mismatch(); +extern void parity_mismatch(regdata_t value); + +}; diff --git a/src/core/sal/sail/cheri-riscv/SailArchRegisters.inc b/src/core/sal/sail/cheri-riscv/SailArchRegisters.inc new file mode 100644 index 00000000..d2030e56 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchRegisters.inc @@ -0,0 +1,147 @@ +#define SINGLE_ARG(...) __VA_ARGS__ + +// 32 General-Purpose Registers +#define GP(id, ptr) SAIL_REG_CLASS(id, SAIL_XLEN, SINGLE_ARG({RT_GP, RT_TRACE}), SailCapabilityRegister, ptr) +SAIL_REG_CLASS(PC, SAIL_XLEN, RT_IP, SailCapabilityRegister, zPCC) +GP(SP, zx1) +GP(RA, zx2) +GP(GP, zx3) +GP(TP, zx4) +GP(T0, zx5) +GP(T1, zx6) +GP(T2, zx7) +GP(S0, zx8) +GP(S1, zx9) +GP(A0, zx10) +GP(A1, zx11) +GP(A2, zx12) +GP(A3, zx13) +GP(A4, zx14) +GP(A5, zx15) +GP(A6, zx16) +GP(A7, zx17) +GP(S2, zx18) +GP(S3, zx19) +GP(S4, zx20) +GP(S5, zx21) +GP(S6, zx22) +GP(S7, zx23) +GP(S8, zx24) +GP(S9, zx25) +GP(S10, zx26) +GP(S11, zx27) +GP(T3, zx28) +GP(T4, zx29) +GP(T5, zx30) +GP(T6, zx31) +#undef GP + +// CPU Specific Registers +#define CSR(id, ptr) SAIL_REG_PTR(id, SAIL_XLEN, RT_CONTROL, ptr) +#define CSR_CAP(id, ptr) SAIL_REG_CLASS(id, SAIL_XLEN, RT_CONTROL, SailCapabilityRegister, ptr) +CSR(MINSTRET, zminstret) +CSR(MISA, zmisa.zMisa_chunk_0) +CSR(MSTATUS, zmstatus.zMstatus_chunk_0) +CSR(MIP, zmip.zMinterrupts_chunk_0) +CSR(MIE, zmie.zMinterrupts_chunk_0) +CSR(MIDELEG, zmideleg.zMinterrupts_chunk_0) +CSR(MEDELEG, zmedeleg.zMedeleg_chunk_0) +CSR(MTVEC, zmtvec.zMtvec_chunk_0) +CSR(MEPC, zmepc) +CSR(MTVAL, zmtval) +CSR(MSCRATCH, zmscratch) +CSR(MCYCLE, zmcycle) +CSR(MTIME, zmtime) +CSR(MVENDORID, zmvendorid) +CSR(MIMPID, zmimpid) +CSR(MARCHID, zmarchid) +CSR(MHARTID, zmhartid) +CSR(SSCRATCH, zsscratch) +CSR(SEPC, zsepc) +CSR(STVAL, zstval) +CSR(TSELECT, ztselect) +CSR(PMPADDR0, zpmpaddr0) +CSR(PMPADDR1, zpmpaddr1) +CSR(PMPADDR2, zpmpaddr2) +CSR(PMPADDR3, zpmpaddr3) +CSR(PMPADDR4, zpmpaddr4) +CSR(PMPADDR5, zpmpaddr5) +CSR(PMPADDR6, zpmpaddr6) +CSR(PMPADDR7, zpmpaddr7) +CSR(PMPADDR8, zpmpaddr8) +CSR(PMPADDR9, zpmpaddr9) +CSR(PMPADDR10, zpmpaddr10) +CSR(PMPADDR11, zpmpaddr11) +CSR(PMPADDR12, zpmpaddr12) +CSR(PMPADDR13, zpmpaddr13) +CSR(PMPADDR14, zpmpaddr14) +CSR(PMPADDR15, zpmpaddr15) +CSR(USCRATCH, zuscratch) +CSR(UEPC, zuepc) +CSR(UTVAL, zutval) +CSR(MTIMECMP, zmtimecmp) +CSR(SATP, zsatp) +CSR(MCOUNTEREN, zmcounteren.zCounteren_chunk_0) +CSR(SCOUNTEREN, zscounteren.zCounteren_chunk_0) +CSR(MCAUSE, zmcause.zMcause_chunk_0) +CSR(SEDELEG, zsedeleg.zSedeleg_chunk_0) +CSR(SIDELEG, zsideleg.zSinterrupts_chunk_0) +CSR(STVEC, zstvec.zMtvec_chunk_0) +CSR(SCAUSE, zscause.zMcause_chunk_0) +CSR(PMP0CFG, zpmp0cfg.zPmpcfg_ent_chunk_0) +CSR(PMP1CFG, zpmp1cfg.zPmpcfg_ent_chunk_0) +CSR(PMP2CFG, zpmp2cfg.zPmpcfg_ent_chunk_0) +CSR(PMP3CFG, zpmp3cfg.zPmpcfg_ent_chunk_0) +CSR(PMP4CFG, zpmp4cfg.zPmpcfg_ent_chunk_0) +CSR(PMP5CFG, zpmp5cfg.zPmpcfg_ent_chunk_0) +CSR(PMP6CFG, zpmp6cfg.zPmpcfg_ent_chunk_0) +CSR(PMP7CFG, zpmp7cfg.zPmpcfg_ent_chunk_0) +CSR(PMP8CFG, zpmp8cfg.zPmpcfg_ent_chunk_0) +CSR(PMP9CFG, zpmp9cfg.zPmpcfg_ent_chunk_0) +CSR(PMP10CFG, zpmp10cfg.zPmpcfg_ent_chunk_0) +CSR(PMP11CFG, zpmp11cfg.zPmpcfg_ent_chunk_0) +CSR(PMP12CFG, zpmp12cfg.zPmpcfg_ent_chunk_0) +CSR(PMP13CFG, zpmp13cfg.zPmpcfg_ent_chunk_0) +CSR(PMP14CFG, zpmp14cfg.zPmpcfg_ent_chunk_0) +CSR(PMP15CFG, zpmp15cfg.zPmpcfg_ent_chunk_0) +CSR(UTVEC, zutvec.zMtvec_chunk_0) +CSR(UCAUSE, zucause.zMcause_chunk_0) + +// FIXME: Remove redundant non-capability registers from above +CSR_CAP(DDC, zDDC) +CSR_CAP(UTCC, zUTCC) +CSR_CAP(UTDC, zUTDC) +CSR_CAP(USCRATCHC, zUScratchC) +CSR_CAP(UEPCC, zUEPCC) +CSR_CAP(STCC, zSTCC) +CSR_CAP(STDC, zSTDC) +CSR_CAP(SSCRATCHC, zSScratchC) +CSR_CAP(SEPCC, zSEPCC) +CSR_CAP(MTCC, zMTCC) +CSR_CAP(MTDC, zMTDC) +CSR_CAP(MSCRATCHC, zMScratchC) +CSR_CAP(MEPCC, zMEPCC) + +#undef CSR +#undef CSR_CAP + + +// Implementation Specific Registers +#define MODEL_SPECIFIC(id, ptr) SAIL_REG_PTR(id, SAIL_XLEN, RT_IMPL_SPECIFIC, ptr) +#define MODEL_SPECIFIC_CAP(id, ptr) SAIL_REG_CLASS(id, SAIL_XLEN, RT_IMPL_SPECIFIC, SailCapabilityRegister, ptr) + +MODEL_SPECIFIC(HTIF_TOHOST, zhtif_tohost) +MODEL_SPECIFIC(HTIF_EXIT_CODE, zhtif_exit_code) +MODEL_SPECIFIC(RAW_PC, zPC) +MODEL_SPECIFIC(RAW_NEXT_PC, znextPC) +MODEL_SPECIFIC_CAP(NEXT_PC, znextPCC) +MODEL_SPECIFIC(INSTBITS, zinstbits) +MODEL_SPECIFIC(CUR_INST, zcur_inst) + +SAIL_REG_FN(MINSTRET_WRITTEN, SAIL_XLEN, RT_IMPL_SPECIFIC, minstret_written) +SAIL_REG_FN(PARITY_MISMATCH, SAIL_XLEN, RT_IMPL_SPECIFIC, parity_mismatch) + +#undef MODEL_SPECIFIC + +// This refers to the SailArchitecture instance... :-) +SAIL_REG_CLASS(REGTAGS, 2*SAIL_XLEN, RT_NONE, SailRegisterCheriTags, *this) diff --git a/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.h b/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.h new file mode 100644 index 00000000..d613b00e --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.h @@ -0,0 +1,297 @@ +#ifndef cheri_riscv_externs_h +#define cheri_riscv_externs_h + +#include +#include +#include +#include "config/VariantConfig.hpp" + +struct zCapability { + uint64_t zB; + uint64_t zE; + uint64_t zT; + bool zaccess_system_regs; + uint64_t zaddress; + bool zflag_cap_mode; + bool zglobal; + bool zinternal_e; + uint64_t zotype; + bool zpermit_ccall; + bool zpermit_execute; + bool zpermit_load; + bool zpermit_load_cap; + bool zpermit_seal; + bool zpermit_set_CID; + bool zpermit_store; + bool zpermit_store_cap; + bool zpermit_store_local_cap; + bool zpermit_unseal; + uint64_t zreserved; + bool zsealed; + bool ztag; + uint64_t zuperms; +}; + +extern "C" __attribute__((weak)) struct zCapability zx1; + +// register x2 +extern "C" __attribute__((weak)) struct zCapability zx2; + +// register x3 +extern "C" __attribute__((weak)) struct zCapability zx3; + +// register x4 +extern "C" __attribute__((weak)) struct zCapability zx4; + +// register x5 +extern "C" __attribute__((weak)) struct zCapability zx5; + +// register x6 +extern "C" __attribute__((weak)) struct zCapability zx6; + +// register x7 +extern "C" __attribute__((weak)) struct zCapability zx7; + +// register x8 +extern "C" __attribute__((weak)) struct zCapability zx8; + +// register x9 +extern "C" __attribute__((weak)) struct zCapability zx9; + +// register x10 +extern "C" __attribute__((weak)) struct zCapability zx10; + +// register x11 +extern "C" __attribute__((weak)) struct zCapability zx11; + +// register x12 +extern "C" __attribute__((weak)) struct zCapability zx12; + +// register x13 +extern "C" __attribute__((weak)) struct zCapability zx13; + +// register x14 +extern "C" __attribute__((weak)) struct zCapability zx14; + +// register x15 +extern "C" __attribute__((weak)) struct zCapability zx15; + +// register x16 +extern "C" __attribute__((weak)) struct zCapability zx16; + +// register x17 +extern "C" __attribute__((weak)) struct zCapability zx17; + +// register x18 +extern "C" __attribute__((weak)) struct zCapability zx18; + +// register x19 +extern "C" __attribute__((weak)) struct zCapability zx19; + +// register x20 +extern "C" __attribute__((weak)) struct zCapability zx20; + +// register x21 +extern "C" __attribute__((weak)) struct zCapability zx21; + +// register x22 +extern "C" __attribute__((weak)) struct zCapability zx22; + +// register x23 +extern "C" __attribute__((weak)) struct zCapability zx23; + +// register x24 +extern "C" __attribute__((weak)) struct zCapability zx24; + +// register x25 +extern "C" __attribute__((weak)) struct zCapability zx25; + +// register x26 +extern "C" __attribute__((weak)) struct zCapability zx26; + +// register x27 +extern "C" __attribute__((weak)) struct zCapability zx27; + +// register x28 +extern "C" __attribute__((weak)) struct zCapability zx28; + +// register x29 +extern "C" __attribute__((weak)) struct zCapability zx29; + +// register x30 +extern "C" __attribute__((weak)) struct zCapability zx30; + +// register x31 +extern "C" __attribute__((weak)) struct zCapability zx31; + +// register PC +extern "C" __attribute__((weak)) uint64_t zPC; + +// register nextPC +extern "C" __attribute__((weak)) uint64_t znextPC; + +// register PCC +extern "C" __attribute__((weak)) struct zCapability zPCC; + +// register nextPCC +extern "C" __attribute__((weak)) struct zCapability znextPCC; + +// register DDC +extern "C" __attribute__((weak)) struct zCapability zDDC; + +// register UTCC +extern "C" __attribute__((weak)) struct zCapability zUTCC; + +// register UTDC +extern "C" __attribute__((weak)) struct zCapability zUTDC; + +// register UScratchC +extern "C" __attribute__((weak)) struct zCapability zUScratchC; + +// register UEPCC +extern "C" __attribute__((weak)) struct zCapability zUEPCC; + +// register STCC +extern "C" __attribute__((weak)) struct zCapability zSTCC; + +// register STDC +extern "C" __attribute__((weak)) struct zCapability zSTDC; + +// register SScratchC +extern "C" __attribute__((weak)) struct zCapability zSScratchC; + +// register SEPCC +extern "C" __attribute__((weak)) struct zCapability zSEPCC; + +// register MTCC +extern "C" __attribute__((weak)) struct zCapability zMTCC; + +// register MTDC +extern "C" __attribute__((weak)) struct zCapability zMTDC; + +// register MScratchC +extern "C" __attribute__((weak)) struct zCapability zMScratchC; + +// register MEPCC +extern "C" __attribute__((weak)) struct zCapability zMEPCC; + +/** + * Register used in sail-riscv. + */ +enum zPrivilege { + zUser, + zSupervisor, + zMachine +}; +struct zMisa { + uint64_t zMisa_chunk_0; +}; +struct zMstatus { + uint64_t zMstatus_chunk_0; +}; +struct zMinterrupts { + uint64_t zMinterrupts_chunk_0; +}; +struct zMedeleg { + uint64_t zMedeleg_chunk_0; +}; +struct zMtvec { + uint64_t zMtvec_chunk_0; +}; +struct zMcause { + uint64_t zMcause_chunk_0; +}; +struct zCounteren { + uint64_t zCounteren_chunk_0; +}; +struct zSedeleg { + uint64_t zSedeleg_chunk_0; +}; +struct zSinterrupts { + uint64_t zSinterrupts_chunk_0; +}; +struct zPmpcfg_ent { + uint64_t zPmpcfg_ent_chunk_0; +}; + +extern "C" __attribute__((weak)) uint64_t zinstbits; +extern "C" __attribute__((weak)) enum zPrivilege zcur_privilege; +extern "C" __attribute__((weak)) uint64_t zcur_inst; +extern "C" __attribute__((weak)) struct zMisa zmisa; +extern "C" __attribute__((weak)) struct zMstatus zmstatus; +extern "C" __attribute__((weak)) struct zMinterrupts zmip; +extern "C" __attribute__((weak)) struct zMinterrupts zmie; +extern "C" __attribute__((weak)) struct zMinterrupts zmideleg; +extern "C" __attribute__((weak)) struct zMedeleg zmedeleg; +extern "C" __attribute__((weak)) struct zMtvec zmtvec; +extern "C" __attribute__((weak)) struct zMcause zmcause; +extern "C" __attribute__((weak)) uint64_t zmepc; +extern "C" __attribute__((weak)) uint64_t zmtval; +extern "C" __attribute__((weak)) uint64_t zmscratch; +extern "C" __attribute__((weak)) struct zCounteren zmcounteren; +extern "C" __attribute__((weak)) struct zCounteren zscounteren; +extern "C" __attribute__((weak)) uint64_t zmcycle; +extern "C" __attribute__((weak)) uint64_t zmtime; +extern "C" __attribute__((weak)) uint64_t zminstret; +extern "C" __attribute__((weak)) bool zminstret_written; +extern "C" __attribute__((weak)) uint64_t zmvendorid; +extern "C" __attribute__((weak)) uint64_t zmimpid; +extern "C" __attribute__((weak)) uint64_t zmarchid; +extern "C" __attribute__((weak)) uint64_t zmhartid; +extern "C" __attribute__((weak)) struct zSedeleg zsedeleg; +extern "C" __attribute__((weak)) struct zSinterrupts zsideleg; +extern "C" __attribute__((weak)) struct zMtvec zstvec; +extern "C" __attribute__((weak)) uint64_t zsscratch; +extern "C" __attribute__((weak)) uint64_t zsepc; +extern "C" __attribute__((weak)) struct zMcause zscause; +extern "C" __attribute__((weak)) uint64_t zstval; +extern "C" __attribute__((weak)) uint64_t ztselect; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp0cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp1cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp2cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp3cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp4cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp5cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp6cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp7cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp8cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp9cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp10cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp11cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp12cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp13cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp14cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp15cfg; +extern "C" __attribute__((weak)) uint64_t zpmpaddr0; +extern "C" __attribute__((weak)) uint64_t zpmpaddr1; +extern "C" __attribute__((weak)) uint64_t zpmpaddr2; +extern "C" __attribute__((weak)) uint64_t zpmpaddr3; +extern "C" __attribute__((weak)) uint64_t zpmpaddr4; +extern "C" __attribute__((weak)) uint64_t zpmpaddr5; +extern "C" __attribute__((weak)) uint64_t zpmpaddr6; +extern "C" __attribute__((weak)) uint64_t zpmpaddr7; +extern "C" __attribute__((weak)) uint64_t zpmpaddr8; +extern "C" __attribute__((weak)) uint64_t zpmpaddr9; +extern "C" __attribute__((weak)) uint64_t zpmpaddr10; +extern "C" __attribute__((weak)) uint64_t zpmpaddr11; +extern "C" __attribute__((weak)) uint64_t zpmpaddr12; +extern "C" __attribute__((weak)) uint64_t zpmpaddr13; +extern "C" __attribute__((weak)) uint64_t zpmpaddr14; +extern "C" __attribute__((weak)) uint64_t zpmpaddr15; +extern "C" __attribute__((weak)) struct zMtvec zutvec; +extern "C" __attribute__((weak)) uint64_t zuscratch; +extern "C" __attribute__((weak)) uint64_t zuepc; +extern "C" __attribute__((weak)) struct zMcause zucause; +extern "C" __attribute__((weak)) uint64_t zutval; +extern "C" __attribute__((weak)) uint64_t zmtimecmp; +extern "C" __attribute__((weak)) uint64_t zhtif_tohost; +extern "C" __attribute__((weak)) bool zhtif_done; +extern "C" __attribute__((weak)) uint64_t zhtif_exit_code; +extern "C" __attribute__((weak)) struct zoption ztlb32; //TODO: shouldnt be modified after init, otherwise should be saved by riscv +extern "C" __attribute__((weak)) uint64_t zsatp; +extern "C" __attribute__((weak)) bool zparity_mismatch; + +extern "C" __attribute__((weak)) uint64_t globalEntry; +extern "C" __attribute__((weak)) void reinit_sail(uint64_t elf_entry); + +#endif diff --git a/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.hpp b/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.hpp new file mode 100644 index 00000000..b083fe3a --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchRegistersExtern.hpp @@ -0,0 +1,298 @@ +#ifndef cheri_riscv_externs_h +#define cheri_riscv_externs_h + +#include +#include +#include +#include "config/VariantConfig.hpp" + +struct zCapability { + uint64_t zB; + uint64_t zE; + uint64_t zT; + bool zaccess_system_regs; + uint64_t zaddress; + bool zflag_cap_mode; + bool zglobal; + bool zinternal_e; + uint64_t zotype; + bool zpermit_ccall; + bool zpermit_execute; + bool zpermit_load; + bool zpermit_load_cap; + bool zpermit_seal; + bool zpermit_set_CID; + bool zpermit_store; + bool zpermit_store_cap; + bool zpermit_store_local_cap; + bool zpermit_unseal; + uint64_t zreserved; + bool zsealed; + bool ztag; + uint64_t zuperms; +}; + + +extern "C" __attribute__((weak)) struct zCapability zx1; + +// register x2 +extern "C" __attribute__((weak)) struct zCapability zx2; + +// register x3 +extern "C" __attribute__((weak)) struct zCapability zx3; + +// register x4 +extern "C" __attribute__((weak)) struct zCapability zx4; + +// register x5 +extern "C" __attribute__((weak)) struct zCapability zx5; + +// register x6 +extern "C" __attribute__((weak)) struct zCapability zx6; + +// register x7 +extern "C" __attribute__((weak)) struct zCapability zx7; + +// register x8 +extern "C" __attribute__((weak)) struct zCapability zx8; + +// register x9 +extern "C" __attribute__((weak)) struct zCapability zx9; + +// register x10 +extern "C" __attribute__((weak)) struct zCapability zx10; + +// register x11 +extern "C" __attribute__((weak)) struct zCapability zx11; + +// register x12 +extern "C" __attribute__((weak)) struct zCapability zx12; + +// register x13 +extern "C" __attribute__((weak)) struct zCapability zx13; + +// register x14 +extern "C" __attribute__((weak)) struct zCapability zx14; + +// register x15 +extern "C" __attribute__((weak)) struct zCapability zx15; + +// register x16 +extern "C" __attribute__((weak)) struct zCapability zx16; + +// register x17 +extern "C" __attribute__((weak)) struct zCapability zx17; + +// register x18 +extern "C" __attribute__((weak)) struct zCapability zx18; + +// register x19 +extern "C" __attribute__((weak)) struct zCapability zx19; + +// register x20 +extern "C" __attribute__((weak)) struct zCapability zx20; + +// register x21 +extern "C" __attribute__((weak)) struct zCapability zx21; + +// register x22 +extern "C" __attribute__((weak)) struct zCapability zx22; + +// register x23 +extern "C" __attribute__((weak)) struct zCapability zx23; + +// register x24 +extern "C" __attribute__((weak)) struct zCapability zx24; + +// register x25 +extern "C" __attribute__((weak)) struct zCapability zx25; + +// register x26 +extern "C" __attribute__((weak)) struct zCapability zx26; + +// register x27 +extern "C" __attribute__((weak)) struct zCapability zx27; + +// register x28 +extern "C" __attribute__((weak)) struct zCapability zx28; + +// register x29 +extern "C" __attribute__((weak)) struct zCapability zx29; + +// register x30 +extern "C" __attribute__((weak)) struct zCapability zx30; + +// register x31 +extern "C" __attribute__((weak)) struct zCapability zx31; + +// register PC +extern "C" __attribute__((weak)) uint64_t zPC; + +// register nextPC +extern "C" __attribute__((weak)) uint64_t znextPC; + +// register PCC +extern "C" __attribute__((weak)) struct zCapability zPCC; + +// register nextPCC +extern "C" __attribute__((weak)) struct zCapability znextPCC; + +// register DDC +extern "C" __attribute__((weak)) struct zCapability zDDC; + +// register UTCC +extern "C" __attribute__((weak)) struct zCapability zUTCC; + +// register UTDC +extern "C" __attribute__((weak)) struct zCapability zUTDC; + +// register UScratchC +extern "C" __attribute__((weak)) struct zCapability zUScratchC; + +// register UEPCC +extern "C" __attribute__((weak)) struct zCapability zUEPCC; + +// register STCC +extern "C" __attribute__((weak)) struct zCapability zSTCC; + +// register STDC +extern "C" __attribute__((weak)) struct zCapability zSTDC; + +// register SScratchC +extern "C" __attribute__((weak)) struct zCapability zSScratchC; + +// register SEPCC +extern "C" __attribute__((weak)) struct zCapability zSEPCC; + +// register MTCC +extern "C" __attribute__((weak)) struct zCapability zMTCC; + +// register MTDC +extern "C" __attribute__((weak)) struct zCapability zMTDC; + +// register MScratchC +extern "C" __attribute__((weak)) struct zCapability zMScratchC; + +// register MEPCC +extern "C" __attribute__((weak)) struct zCapability zMEPCC; + +/** + * Register used in sail-riscv. + */ +enum zPrivilege { + zUser, + zSupervisor, + zMachine +}; +struct zMisa { + uint64_t zMisa_chunk_0; +}; +struct zMstatus { + uint64_t zMstatus_chunk_0; +}; +struct zMinterrupts { + uint64_t zMinterrupts_chunk_0; +}; +struct zMedeleg { + uint64_t zMedeleg_chunk_0; +}; +struct zMtvec { + uint64_t zMtvec_chunk_0; +}; +struct zMcause { + uint64_t zMcause_chunk_0; +}; +struct zCounteren { + uint64_t zCounteren_chunk_0; +}; +struct zSedeleg { + uint64_t zSedeleg_chunk_0; +}; +struct zSinterrupts { + uint64_t zSinterrupts_chunk_0; +}; +struct zPmpcfg_ent { + uint64_t zPmpcfg_ent_chunk_0; +}; + +extern "C" __attribute__((weak)) uint64_t zinstbits; +extern "C" __attribute__((weak)) enum zPrivilege zcur_privilege; +extern "C" __attribute__((weak)) uint64_t zcur_inst; +extern "C" __attribute__((weak)) struct zMisa zmisa; +extern "C" __attribute__((weak)) struct zMstatus zmstatus; +extern "C" __attribute__((weak)) struct zMinterrupts zmip; +extern "C" __attribute__((weak)) struct zMinterrupts zmie; +extern "C" __attribute__((weak)) struct zMinterrupts zmideleg; +extern "C" __attribute__((weak)) struct zMedeleg zmedeleg; +extern "C" __attribute__((weak)) struct zMtvec zmtvec; +extern "C" __attribute__((weak)) struct zMcause zmcause; +extern "C" __attribute__((weak)) uint64_t zmepc; +extern "C" __attribute__((weak)) uint64_t zmtval; +extern "C" __attribute__((weak)) uint64_t zmscratch; +extern "C" __attribute__((weak)) struct zCounteren zmcounteren; +extern "C" __attribute__((weak)) struct zCounteren zscounteren; +extern "C" __attribute__((weak)) uint64_t zmcycle; +extern "C" __attribute__((weak)) uint64_t zmtime; +extern "C" __attribute__((weak)) uint64_t zminstret; +extern "C" __attribute__((weak)) bool zminstret_written; +extern "C" __attribute__((weak)) uint64_t zmvendorid; +extern "C" __attribute__((weak)) uint64_t zmimpid; +extern "C" __attribute__((weak)) uint64_t zmarchid; +extern "C" __attribute__((weak)) uint64_t zmhartid; +extern "C" __attribute__((weak)) struct zSedeleg zsedeleg; +extern "C" __attribute__((weak)) struct zSinterrupts zsideleg; +extern "C" __attribute__((weak)) struct zMtvec zstvec; +extern "C" __attribute__((weak)) uint64_t zsscratch; +extern "C" __attribute__((weak)) uint64_t zsepc; +extern "C" __attribute__((weak)) struct zMcause zscause; +extern "C" __attribute__((weak)) uint64_t zstval; +extern "C" __attribute__((weak)) uint64_t ztselect; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp0cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp1cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp2cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp3cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp4cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp5cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp6cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp7cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp8cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp9cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp10cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp11cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp12cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp13cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp14cfg; +extern "C" __attribute__((weak)) struct zPmpcfg_ent zpmp15cfg; +extern "C" __attribute__((weak)) uint64_t zpmpaddr0; +extern "C" __attribute__((weak)) uint64_t zpmpaddr1; +extern "C" __attribute__((weak)) uint64_t zpmpaddr2; +extern "C" __attribute__((weak)) uint64_t zpmpaddr3; +extern "C" __attribute__((weak)) uint64_t zpmpaddr4; +extern "C" __attribute__((weak)) uint64_t zpmpaddr5; +extern "C" __attribute__((weak)) uint64_t zpmpaddr6; +extern "C" __attribute__((weak)) uint64_t zpmpaddr7; +extern "C" __attribute__((weak)) uint64_t zpmpaddr8; +extern "C" __attribute__((weak)) uint64_t zpmpaddr9; +extern "C" __attribute__((weak)) uint64_t zpmpaddr10; +extern "C" __attribute__((weak)) uint64_t zpmpaddr11; +extern "C" __attribute__((weak)) uint64_t zpmpaddr12; +extern "C" __attribute__((weak)) uint64_t zpmpaddr13; +extern "C" __attribute__((weak)) uint64_t zpmpaddr14; +extern "C" __attribute__((weak)) uint64_t zpmpaddr15; +extern "C" __attribute__((weak)) struct zMtvec zutvec; +extern "C" __attribute__((weak)) uint64_t zuscratch; +extern "C" __attribute__((weak)) uint64_t zuepc; +extern "C" __attribute__((weak)) struct zMcause zucause; +extern "C" __attribute__((weak)) uint64_t zutval; +extern "C" __attribute__((weak)) uint64_t zmtimecmp; +extern "C" __attribute__((weak)) uint64_t zhtif_tohost; +extern "C" __attribute__((weak)) bool zhtif_done; +extern "C" __attribute__((weak)) uint64_t zhtif_exit_code; +extern "C" __attribute__((weak)) struct zoption ztlb32; //TODO: shouldnt be modified after init, otherwise should be saved by riscv +extern "C" __attribute__((weak)) uint64_t zsatp; +extern "C" __attribute__((weak)) bool zparity_mismatch; + +extern "C" __attribute__((weak)) uint64_t globalEntry; +extern "C" __attribute__((weak)) void reinit_sail(uint64_t elf_entry); + +#endif diff --git a/src/core/sal/sail/cheri-riscv/SailArchSimulator.cc b/src/core/sal/sail/cheri-riscv/SailArchSimulator.cc new file mode 100644 index 00000000..2575d229 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchSimulator.cc @@ -0,0 +1,104 @@ +#include +#include +#include "SailArchSimulator.hpp" + +using namespace fail; + +static const std::vector,std::bitset<32>>> jumpOpCodes = { + { // c.jv + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001010000000000001") + }, + { // c.jr + std::bitset<32>("00000000000000001111000001111111"), + std::bitset<32>("00000000000000001000000000000010") + }, + { // c.jal + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000000010000000000001") + }, + { // c.jalr + std::bitset<32>("00000000000000001111000001111111"), + std::bitset<32>("00000000000000001001000000000010") + }, + { // jal + std::bitset<32>("00000000000000000000000001111111"), + std::bitset<32>("00000000000000000000000001101111") + }, + { // jalr + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000000000001100111") + }, + { // beq + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000000000001100011") + }, + { // bne + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000001000001100011") + }, + { // blt + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000100000001100011") + }, + { // bge + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000101000001100011") + }, + { // bltu + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000110000001100011") + }, + { // bgeu + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000111000001100011") + }, + { // c.beqz + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001100000000000001") + }, + { // c.bnez + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001110000000000001") + }, + { // mret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00110000001000000000000001110011") + }, + { // sret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00010000001000000000000001110011") + }, + { // uret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00000000001000000000000001110011") + } +}; + +bool SailSimulator::isJump(uint64_t instrPtr, uint64_t instr) { + std::bitset<32> binaryInstr(instr); + + for (const auto& p: jumpOpCodes) { + if ((binaryInstr & p.first) == p.second) { + return false; + } + } + return false; +} + +void SailSimulator::do_save(const std::string& base) { + SailBaseSimulator::do_save(base); + + std::ofstream fm { base + "/tags", std::ios::binary }; + if (!fm.is_open()) throw std::runtime_error("[FAIL] couldnt open tags file for writing"); + m_tag_mem_manager.serialize(fm); +} + +void SailSimulator::do_restore(const std::string& base) { + SailBaseSimulator::do_restore(base); + + // unserialize memory + std::ifstream fm { base + "/tags", std::ios::binary }; + if (!fm.is_open()) throw std::runtime_error("[FAIL] couldnt open tags file for reading"); + m_tag_mem_manager.unserialize(fm); +} diff --git a/src/core/sal/sail/cheri-riscv/SailArchSimulator.hpp b/src/core/sal/sail/cheri-riscv/SailArchSimulator.hpp new file mode 100644 index 00000000..8bf3e34c --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailArchSimulator.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "../SailSimulator.hpp" +#include "SailTagMemoryManager.hpp" + +namespace fail { +class SailSimulator : public SailBaseSimulator { + SailTagMemoryManager m_tag_mem_manager; + +public: + SailSimulator() : SailBaseSimulator() { + setMemoryManager(&m_tag_mem_manager, MEMTYPE_TAGS); + } + bool isJump(uint64_t instrPtr, uint64_t instr); + + virtual void do_save(const std::string& base) override; + virtual void do_restore(const std::string& base) override; +}; +} diff --git a/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.cc b/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.cc new file mode 100644 index 00000000..0f930183 --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.cc @@ -0,0 +1,135 @@ +#include +#include +#include "SailTagMemoryManager.hpp" +#include "../SailMemoryExtern.hpp" + + +namespace fail { + +size_t SailTagMemoryManager::getPoolSize() const { + return ULONG_MAX; //Return unsinged long max since pool size is dynamic +} + +host_address_t SailTagMemoryManager::getStartAddr() const { + return 0; +} + +byte_t SailTagMemoryManager::getByte(guest_address_t addr) { + if(read_tag_bool) + return static_cast(read_tag_bool(addr)); + else + throw std::runtime_error("can't read memory, simulator not linked!"); +} + +void SailTagMemoryManager::getBytes(guest_address_t addr, size_t cnt, + void *dest) { + char *d = static_cast(dest); + for (size_t i = 0; i < cnt; ++i) d[i] = getByte(addr + i); +} + +void SailTagMemoryManager::setByte(guest_address_t addr, byte_t data) { + if(write_tag_bool) { + write_tag_bool(addr, static_cast(data)); + } + else + throw std::runtime_error("can't write memory, simulator not linked"); +} + +void SailTagMemoryManager::setBytes(guest_address_t addr, size_t cnt, void const *src) { + char const *s = static_cast(src); + for (size_t i = 0; i < cnt; ++i) setByte(addr + i, s[i]); +} + +bool SailTagMemoryManager::isMapped(guest_address_t addr) { + if(!sail_tags) throw std::runtime_error("can't access memory, simulator not linked"); + + if(sail_tags) { + uint64_t address = static_cast(addr); + uint64_t mask = address & ~MASK; + tag_block *current = sail_tags; + + while (current != NULL) { + if (current->block_id == mask) { + return true; + } else { + current = current->next; + } + } + } else throw std::runtime_error("can't access memory, simulator not linked"); + + return false; +} + +void SailTagMemoryManager::serialize(std::ostream& os) { + // at least this must be != NULL, otherwise + // we can safely assume that the simulator has not been linked + // in theory both, sail_memory and sail_tags could be NULL if the simulator hasn't actually accessed any memory + // but since we are executing a program, at the very least that + // has been loaded to memory + if(!sail_memory) throw std::runtime_error("can't access memory, simulator not linked"); + if(!os) throw std::runtime_error("can't open ostream."); + + const size_t tag_len = (MASK + 1); + const size_t tag_size = tag_len*sizeof(bool); + + unsigned cnt = 0; + tag_block* start = sail_tags; + while(sail_tags != NULL) { + std::cout << "serializing tag block (id=" << sail_tags->block_id << ",size=" << tag_size << std::endl; + os.write(reinterpret_cast(&sail_tags->block_id), sizeof(sail_tags->block_id)); + os.write(reinterpret_cast(sail_tags->mem), tag_size); + sail_tags = sail_tags->next; + cnt++; + } + std::cout << "serialized " << cnt << " tag blocks" << std::endl; + sail_tags = start; +} + +void SailTagMemoryManager::unserialize(std::istream& is) { + if(!is) throw std::runtime_error("can't open istream."); + + reset(); + const size_t tag_len = (MASK + 1); + const size_t tag_size = tag_len*sizeof(bool); + + unsigned long cnt = 0; + tag_block* last; + while(is) { + tag_block* b = new tag_block; + b->mem = new bool[tag_len]; + b->next = NULL; + + is.read(reinterpret_cast(&b->block_id), sizeof(b->block_id)); + is.read(reinterpret_cast(b->mem), tag_size); + if(is.fail()) { + // XXX: we must check here, since is.eof() will return false, even if the end-of-file has been reached. + // it will only return true if the is has been used to read unsuccessfully + delete b->mem; + delete b; + break; + } + + if(cnt == 0) { + sail_tags = b; + } else if(last != NULL) { + last->next = b; + } else { throw std::runtime_error("sail_tags is not empty, can't unserialize!"); } + + last = b; + cnt++; + } + std::cerr << "unserialized " << cnt << " tag blocks with size " << tag_size << std::endl; +} + +void SailTagMemoryManager::reset() { + while(sail_tags != NULL) { + tag_block *next = sail_tags->next; + + delete sail_tags->mem; + delete sail_tags; + + sail_tags = next; + } +} + +} // namespace fail diff --git a/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.hpp b/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.hpp new file mode 100644 index 00000000..79f7bb9b --- /dev/null +++ b/src/core/sal/sail/cheri-riscv/SailTagMemoryManager.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "../../Memory.hpp" +#include + +namespace fail { + class SailTagMemoryManager: public MemoryManager { + private: + static size_t tag_len; + static size_t tag_size; + public: + /** + * Constructs a new MemoryManager object and initializes + * it's attributes appropriately. + */ + SailTagMemoryManager() : MemoryManager() { } + /** + * Retrieves the size of the currently allocated memory blocks. + * @return the size of the currently allocated memory blocks in bytes + */ + size_t getPoolSize() const; + /** + * Retrieves the starting address of the host memory. This is the + * first valid address in memory. + * @return the starting address + */ + host_address_t getStartAddr() const; + /** + * Retrieves the byte at address \a addr in the memory. + * @param addr The guest address where the byte is located. + * @return the byte at \a addr + */ + byte_t getByte(guest_address_t addr); + /** + * Retrieves \a cnt bytes at address \a addr from the memory. + * @param addr The guest address where the bytes are located. + * @param cnt The number of bytes to be retrieved. + * @param dest Pointer to destination buffer to copy the data to. + */ + void getBytes(guest_address_t addr, size_t cnt, void *dest); + /** + * Writes the byte \a data to memory. + * @param addr The guest address to write. + * @param data The new byte to write + */ + void setByte(guest_address_t addr, byte_t data); + /** + * Copies data to memory. + * @param addr The guest address to write. + * @param cnt The number of bytes to be retrieved. + * @param src Pointer to data to be copied. + */ + void setBytes(guest_address_t addr, size_t cnt, void const *src); + /** + * Checks whether memory is mapped and available. + * @param addr The guest address to check. + */ + bool isMapped(guest_address_t addr); + /** + * Serialize the memory state to output streams. + * @param mem_os The output stream for memory blocks. + * @param tag_os The output stream for memory tag blocks. + */ + void serialize(std::ostream& os); + + /** + * Unserialize the memory state from an input streams. + * @param mem_is The input stream for memory blocks. + * @param tag_is The input stream for memory tag blocks. + */ + void unserialize(std::istream& is); + + /** + * Reset the memory state + */ + void reset(); + }; +} diff --git a/src/core/sal/sail/riscv/SailArchCPU.hpp b/src/core/sal/sail/riscv/SailArchCPU.hpp new file mode 100644 index 00000000..7e420849 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchCPU.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace fail{ +typedef SailBaseCPU SailCPU; +} diff --git a/src/core/sal/sail/riscv/SailArchConfig.hpp b/src/core/sal/sail/riscv/SailArchConfig.hpp new file mode 100644 index 00000000..9f9e4fca --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchConfig.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace fail { +typedef uint64_t guest_address_t; //!< the guest memory address type +typedef uint64_t host_address_t; //!< the host memory address type +typedef unsigned int timer_t; //!< type of timer IDs + +/** + * For RISC-V, all GP register may hold up to XLEN bits, e.g. 64 or 32 + * bit for RV32 and RV64 respectively. Larger XLEN are currently not + * supported by the sail model. + */ +#if defined(BUILD_64BIT) +typedef uint64_t register_data_t; +#define SAIL_XLEN 64 +#else +typedef uint32_t register_data_t; +#define SAIL_XLEN 32 +#endif + +#define SAIL_RESET_VECTOR 0x8000000 + +} diff --git a/src/core/sal/sail/riscv/SailArchFaultSpace.cc b/src/core/sal/sail/riscv/SailArchFaultSpace.cc new file mode 100644 index 00000000..027a256b --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchFaultSpace.cc @@ -0,0 +1,15 @@ +#include +#include "SailArchFaultSpace.hpp" +#include "sal/faultspace/MemoryArea.hpp" +#include "sal/faultspace/RegisterArea.hpp" + + +fail::SailFaultSpace::SailFaultSpace() { + // Order Matters! + // 4GiB of RAM + add_area(std::make_unique("ram", 0, 0xffffffff)); + // The Registers + set_point(1L<<32); + add_area(std::make_unique()); +} + diff --git a/src/core/sal/sail/riscv/SailArchFaultSpace.hpp b/src/core/sal/sail/riscv/SailArchFaultSpace.hpp new file mode 100644 index 00000000..5516b39a --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchFaultSpace.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "sal/faultspace/BaseFaultSpace.hpp" + +namespace fail { +class SailFaultSpace: public BaseFaultSpace { +public: + SailFaultSpace(); +}; + +} // end-of-namespace: fail + diff --git a/src/core/sal/sail/riscv/SailArchRegisters.cc b/src/core/sal/sail/riscv/SailArchRegisters.cc new file mode 100644 index 00000000..a83031df --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchRegisters.cc @@ -0,0 +1,19 @@ +#include +#include "../../SALConfig.hpp" +#include "../SailArchitecture.hpp" +#include "SailArchRegisters.hpp" +#include "SailArchRegistersExtern.hpp" + +using namespace fail; + +regdata_t fail::minstret_written() { + return static_cast(zminstret_written); +} + +void fail::minstret_written(regdata_t value) { + zminstret_written = static_cast(value); +} + +simtime_t SailArchitecture::getInstructionCounter() const { + return static_cast(zminstret); +} diff --git a/src/core/sal/sail/riscv/SailArchRegisters.hpp b/src/core/sal/sail/riscv/SailArchRegisters.hpp new file mode 100644 index 00000000..6fbf0c16 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchRegisters.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../../SALConfig.hpp" + +namespace fail { + +extern regdata_t minstret_written(); +extern void minstret_written(regdata_t value); + +}; diff --git a/src/core/sal/sail/riscv/SailArchRegisters.inc b/src/core/sal/sail/riscv/SailArchRegisters.inc new file mode 100644 index 00000000..f358f566 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchRegisters.inc @@ -0,0 +1,121 @@ +// See https://stackoverflow.com/questions/1643226/c-array-initialization-via-macro/1645599#1645599 +// for passing initializer lists in macro argument +#define SAIL_CLASS_GP {RT_GP, RT_TRACE} + +// 32 General-Purpose Registers +#define GP(id, ptr) SAIL_REG_PTR(id, SAIL_XLEN, SAIL_CLASS_GP, ptr) +SAIL_REG_PTR(PC, SAIL_XLEN, RT_IP, zPC) +GP(SP, zx1) +GP(RA, zx2) +GP(GP, zx3) +GP(TP, zx4) +GP(T0, zx5) +GP(T1, zx6) +GP(T2, zx7) +GP(S0, zx8) +GP(S1, zx9) +GP(A0, zx10) +GP(A1, zx11) +GP(A2, zx12) +GP(A3, zx13) +GP(A4, zx14) +GP(A5, zx15) +GP(A6, zx16) +GP(A7, zx17) +GP(S2, zx18) +GP(S3, zx19) +GP(S4, zx20) +GP(S5, zx21) +GP(S6, zx22) +GP(S7, zx23) +GP(S8, zx24) +GP(S9, zx25) +GP(S10, zx26) +GP(S11, zx27) +GP(T3, zx28) +GP(T4, zx29) +GP(T5, zx30) +GP(T6, zx31) +#undef GP + +// CPU Specific Registers +#define CSR(id, ptr) SAIL_REG_PTR(id, SAIL_XLEN, RT_CONTROL, ptr) +CSR(MINSTRET, zminstret) +CSR(MISA, zmisa.zMisa_chunk_0) +CSR(MSTATUS, zmstatus.zMstatus_chunk_0) +CSR(MIP, zmip.zMinterrupts_chunk_0) +CSR(MIE, zmie.zMinterrupts_chunk_0) +CSR(MIDELEG, zmideleg.zMinterrupts_chunk_0) +CSR(MEDELEG, zmedeleg.zMedeleg_chunk_0) +CSR(MTVEC, zmtvec.zMtvec_chunk_0) +CSR(MEPC, zmepc) +CSR(MTVAL, zmtval) +CSR(MSCRATCH, zmscratch) +CSR(MCYCLE, zmcycle) +CSR(MTIME, zmtime) +CSR(MVENDORID, zmvendorid) +CSR(MIMPID, zmimpid) +CSR(MARCHID, zmarchid) +CSR(MHARTID, zmhartid) +CSR(SSCRATCH, zsscratch) +CSR(SEPC, zsepc) +CSR(STVAL, zstval) +CSR(TSELECT, ztselect) +CSR(PMPADDR0, zpmpaddr0) +CSR(PMPADDR1, zpmpaddr1) +CSR(PMPADDR2, zpmpaddr2) +CSR(PMPADDR3, zpmpaddr3) +CSR(PMPADDR4, zpmpaddr4) +CSR(PMPADDR5, zpmpaddr5) +CSR(PMPADDR6, zpmpaddr6) +CSR(PMPADDR7, zpmpaddr7) +CSR(PMPADDR8, zpmpaddr8) +CSR(PMPADDR9, zpmpaddr9) +CSR(PMPADDR10, zpmpaddr10) +CSR(PMPADDR11, zpmpaddr11) +CSR(PMPADDR12, zpmpaddr12) +CSR(PMPADDR13, zpmpaddr13) +CSR(PMPADDR14, zpmpaddr14) +CSR(PMPADDR15, zpmpaddr15) +CSR(USCRATCH, zuscratch) +CSR(UEPC, zuepc) +CSR(UTVAL, zutval) +CSR(MTIMECMP, zmtimecmp) +CSR(SATP, zsatp) +CSR(MCOUNTEREN, zmcounteren.zCounteren_chunk_0) +CSR(SCOUNTEREN, zscounteren.zCounteren_chunk_0) +CSR(MCAUSE, zmcause.zMcause_chunk_0) +CSR(SEDELEG, zsedeleg.zSedeleg_chunk_0) +CSR(SIDELEG, zsideleg.zSinterrupts_chunk_0) +CSR(STVEC, zstvec.zMtvec_chunk_0) +CSR(SCAUSE, zscause.zMcause_chunk_0) +CSR(PMP0CFG, zpmp0cfg.zPmpcfg_ent_chunk_0) +CSR(PMP1CFG, zpmp1cfg.zPmpcfg_ent_chunk_0) +CSR(PMP2CFG, zpmp2cfg.zPmpcfg_ent_chunk_0) +CSR(PMP3CFG, zpmp3cfg.zPmpcfg_ent_chunk_0) +CSR(PMP4CFG, zpmp4cfg.zPmpcfg_ent_chunk_0) +CSR(PMP5CFG, zpmp5cfg.zPmpcfg_ent_chunk_0) +CSR(PMP6CFG, zpmp6cfg.zPmpcfg_ent_chunk_0) +CSR(PMP7CFG, zpmp7cfg.zPmpcfg_ent_chunk_0) +CSR(PMP8CFG, zpmp8cfg.zPmpcfg_ent_chunk_0) +CSR(PMP9CFG, zpmp9cfg.zPmpcfg_ent_chunk_0) +CSR(PMP10CFG, zpmp10cfg.zPmpcfg_ent_chunk_0) +CSR(PMP11CFG, zpmp11cfg.zPmpcfg_ent_chunk_0) +CSR(PMP12CFG, zpmp12cfg.zPmpcfg_ent_chunk_0) +CSR(PMP13CFG, zpmp13cfg.zPmpcfg_ent_chunk_0) +CSR(PMP14CFG, zpmp14cfg.zPmpcfg_ent_chunk_0) +CSR(PMP15CFG, zpmp15cfg.zPmpcfg_ent_chunk_0) +CSR(UTVEC, zutvec.zMtvec_chunk_0) +CSR(UCAUSE, zucause.zMcause_chunk_0) +#undef CSR + +// Implementation Specific Registers +#define MODEL_SPECIFIC(id, ptr) SAIL_REG_PTR(id, SAIL_XLEN, RT_IMPL_SPECIFIC, ptr) +MODEL_SPECIFIC(HTIF_TOHOST, zhtif_tohost) +MODEL_SPECIFIC(HTIF_EXIT_CODE, zhtif_exit_code) +MODEL_SPECIFIC(NEXT_PC, znextPC) +MODEL_SPECIFIC(INSTBITS, zinstbits) +MODEL_SPECIFIC(CUR_INST, zcur_inst) +SAIL_REG_FN(MINSTRET_WRITTEN, SAIL_XLEN, RT_IMPL_SPECIFIC, minstret_written) +#undef MODEL_SPECIFIC + diff --git a/src/core/sal/sail/riscv/SailArchRegistersExtern.hpp b/src/core/sal/sail/riscv/SailArchRegistersExtern.hpp new file mode 100644 index 00000000..1b6c8f75 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchRegistersExtern.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include +#include + +extern "C" { + +/** + * Register used in sail-riscv. + */ +struct zvectorz8deczCz0fbitsz832zCz0decz9z9 { + size_t len; + uint64_t *data; +}; +typedef struct zvectorz8deczCz0fbitsz832zCz0decz9z9 + zvectorz8deczCz0fbitsz832zCz0decz9z9; + +enum zPrivilege { + zUser, + zSupervisor, + zMachine +}; +struct zMisa { + uint64_t zMisa_chunk_0; +}; +struct zMstatus { + uint64_t zMstatus_chunk_0; +}; +struct zMinterrupts { + uint64_t zMinterrupts_chunk_0; +}; +struct zMedeleg { + uint64_t zMedeleg_chunk_0; +}; +struct zMtvec { + uint64_t zMtvec_chunk_0; +}; +struct zMcause { + uint64_t zMcause_chunk_0; +}; +struct zCounteren { + uint64_t zCounteren_chunk_0; +}; +struct zSedeleg { + uint64_t zSedeleg_chunk_0; +}; +struct zSinterrupts { + uint64_t zSinterrupts_chunk_0; +}; +struct zPmpcfg_ent { + uint64_t zPmpcfg_ent_chunk_0; +}; + +__attribute__((weak)) uint64_t zPC; +__attribute__((weak)) uint64_t znextPC; +__attribute__((weak)) uint64_t zinstbits; +__attribute__((weak)) zvectorz8deczCz0fbitsz832zCz0decz9z9 zXs; +__attribute__((weak)) uint64_t zx1; +__attribute__((weak)) uint64_t zx2; +__attribute__((weak)) uint64_t zx3; +__attribute__((weak)) uint64_t zx4; +__attribute__((weak)) uint64_t zx5; +__attribute__((weak)) uint64_t zx6; +__attribute__((weak)) uint64_t zx7; +__attribute__((weak)) uint64_t zx8; +__attribute__((weak)) uint64_t zx9; +__attribute__((weak)) uint64_t zx10; +__attribute__((weak)) uint64_t zx11; +__attribute__((weak)) uint64_t zx12; +__attribute__((weak)) uint64_t zx13; +__attribute__((weak)) uint64_t zx14; +__attribute__((weak)) uint64_t zx15; +__attribute__((weak)) uint64_t zx16; +__attribute__((weak)) uint64_t zx17; +__attribute__((weak)) uint64_t zx18; +__attribute__((weak)) uint64_t zx19; +__attribute__((weak)) uint64_t zx20; +__attribute__((weak)) uint64_t zx21; +__attribute__((weak)) uint64_t zx22; +__attribute__((weak)) uint64_t zx23; +__attribute__((weak)) uint64_t zx24; +__attribute__((weak)) uint64_t zx25; +__attribute__((weak)) uint64_t zx26; +__attribute__((weak)) uint64_t zx27; +__attribute__((weak)) uint64_t zx28; +__attribute__((weak)) uint64_t zx29; +__attribute__((weak)) uint64_t zx30; +__attribute__((weak)) uint64_t zx31; +__attribute__((weak)) enum zPrivilege zcur_privilege; +__attribute__((weak)) uint64_t zcur_inst; +__attribute__((weak)) struct zMisa zmisa; +__attribute__((weak)) struct zMstatus zmstatus; +__attribute__((weak)) struct zMinterrupts zmip; +__attribute__((weak)) struct zMinterrupts zmie; +__attribute__((weak)) struct zMinterrupts zmideleg; +__attribute__((weak)) struct zMedeleg zmedeleg; +__attribute__((weak)) struct zMtvec zmtvec; +__attribute__((weak)) struct zMcause zmcause; +__attribute__((weak)) uint64_t zmepc; +__attribute__((weak)) uint64_t zmtval; +__attribute__((weak)) uint64_t zmscratch; +__attribute__((weak)) struct zCounteren zmcounteren; +__attribute__((weak)) struct zCounteren zscounteren; +__attribute__((weak)) uint64_t zmcycle; +__attribute__((weak)) uint64_t zmtime; +__attribute__((weak)) uint64_t zminstret; +__attribute__((weak)) bool zminstret_written; +__attribute__((weak)) uint64_t zmvendorid; +__attribute__((weak)) uint64_t zmimpid; +__attribute__((weak)) uint64_t zmarchid; +__attribute__((weak)) uint64_t zmhartid; +__attribute__((weak)) struct zSedeleg zsedeleg; +__attribute__((weak)) struct zSinterrupts zsideleg; +__attribute__((weak)) struct zMtvec zstvec; +__attribute__((weak)) uint64_t zsscratch; +__attribute__((weak)) uint64_t zsepc; +__attribute__((weak)) struct zMcause zscause; +__attribute__((weak)) uint64_t zstval; +__attribute__((weak)) uint64_t ztselect; +__attribute__((weak)) struct zPmpcfg_ent zpmp0cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp1cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp2cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp3cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp4cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp5cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp6cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp7cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp8cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp9cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp10cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp11cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp12cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp13cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp14cfg; +__attribute__((weak)) struct zPmpcfg_ent zpmp15cfg; +__attribute__((weak)) uint64_t zpmpaddr0; +__attribute__((weak)) uint64_t zpmpaddr1; +__attribute__((weak)) uint64_t zpmpaddr2; +__attribute__((weak)) uint64_t zpmpaddr3; +__attribute__((weak)) uint64_t zpmpaddr4; +__attribute__((weak)) uint64_t zpmpaddr5; +__attribute__((weak)) uint64_t zpmpaddr6; +__attribute__((weak)) uint64_t zpmpaddr7; +__attribute__((weak)) uint64_t zpmpaddr8; +__attribute__((weak)) uint64_t zpmpaddr9; +__attribute__((weak)) uint64_t zpmpaddr10; +__attribute__((weak)) uint64_t zpmpaddr11; +__attribute__((weak)) uint64_t zpmpaddr12; +__attribute__((weak)) uint64_t zpmpaddr13; +__attribute__((weak)) uint64_t zpmpaddr14; +__attribute__((weak)) uint64_t zpmpaddr15; +__attribute__((weak)) struct zMtvec zutvec; +__attribute__((weak)) uint64_t zuscratch; +__attribute__((weak)) uint64_t zuepc; +__attribute__((weak)) struct zMcause zucause; +__attribute__((weak)) uint64_t zutval; +__attribute__((weak)) uint64_t zmtimecmp; +__attribute__((weak)) uint64_t zhtif_tohost; +__attribute__((weak)) bool zhtif_done; +__attribute__((weak)) uint64_t zhtif_exit_code; +// __attribute__((weak)) struct zoption ztlb32; //TODO: shouldnt be modified after init, otherwise should be saved by riscv +__attribute__((weak)) uint64_t zsatp; + +__attribute__((weak)) uint64_t globalEntry; +__attribute__((weak)) void reinit_sail(uint64_t elf_entry); + +} diff --git a/src/core/sal/sail/riscv/SailArchSimulator.cc b/src/core/sal/sail/riscv/SailArchSimulator.cc new file mode 100644 index 00000000..86c522e7 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchSimulator.cc @@ -0,0 +1,87 @@ +#include +#include "SailArchSimulator.hpp" + +using namespace fail; + +static const std::vector,std::bitset<32>>> jumpOpCodes = { + { // c.jv + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001010000000000001") + }, + { // c.jr + std::bitset<32>("00000000000000001111000001111111"), + std::bitset<32>("00000000000000001000000000000010") + }, + { // c.jal + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000000010000000000001") + }, + { // c.jalr + std::bitset<32>("00000000000000001111000001111111"), + std::bitset<32>("00000000000000001001000000000010") + }, + { // jal + std::bitset<32>("00000000000000000000000001111111"), + std::bitset<32>("00000000000000000000000001101111") + }, + { // jalr + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000000000001100111") + }, + { // beq + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000000000001100011") + }, + { // bne + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000001000001100011") + }, + { // blt + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000100000001100011") + }, + { // bge + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000101000001100011") + }, + { // bltu + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000110000001100011") + }, + { // bgeu + std::bitset<32>("00000000000000000111000001111111"), + std::bitset<32>("00000000000000000111000001100011") + }, + { // c.beqz + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001100000000000001") + }, + { // c.bnez + std::bitset<32>("00000000000000001110000000000011"), + std::bitset<32>("00000000000000001110000000000001") + }, + { // mret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00110000001000000000000001110011") + }, + { // sret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00010000001000000000000001110011") + }, + { // uret + std::bitset<32>("11111111111111111111111111111111"), + std::bitset<32>("00000000001000000000000001110011") + } +}; + +bool SailSimulator::isJump(uint64_t instrPtr, uint64_t instr) { + std::bitset<32> binaryInstr(instr); + + for (const auto& p: jumpOpCodes) { + if ((binaryInstr & p.first) == p.second) { + return false; + } + } + return false; +} + diff --git a/src/core/sal/sail/riscv/SailArchSimulator.hpp b/src/core/sal/sail/riscv/SailArchSimulator.hpp new file mode 100644 index 00000000..e0cf8220 --- /dev/null +++ b/src/core/sal/sail/riscv/SailArchSimulator.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../SailSimulator.hpp" + +namespace fail { +class SailSimulator : public SailBaseSimulator { + bool isJump(uint64_t instrPtr, uint64_t instr); +}; +} diff --git a/src/core/util/llvmdisassembler/CMakeLists.txt b/src/core/util/llvmdisassembler/CMakeLists.txt index 5e9e7bb4..9d513e3e 100644 --- a/src/core/util/llvmdisassembler/CMakeLists.txt +++ b/src/core/util/llvmdisassembler/CMakeLists.txt @@ -1,21 +1,42 @@ set(SRCS LLVMDisassembler.cpp LLVMDisassembler.hpp - LLVMtoFailBochs.cpp - LLVMtoFailBochs.hpp - LLVMtoFailGem5.hpp - LLVMtoFailGem5.cpp LLVMtoFailTranslator.cpp LLVMtoFailTranslator.hpp -) + ) -include(FindLLVM) +set(FIND_PACKAGE_VERSION 11.0.0) +set(FIND_PACKAGE_ARGS) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS}" ) +if(BUILD_BOCHS) + set(SRCS ${SRCS} + LLVMtoFailBochs.cpp + LLVMtoFailBochs.hpp + ) +elseif (BUILD_GEM5) + set(SRCS ${SRCS} + LLVMtoFailGem5.cpp + LLVMtoFailGem5.hpp + ) +elseif (BUILD_SAIL) + set(SRCS ${SRCS} + LLVMtoFailSailRiscv.cpp + LLVMtoFailSailRiscv.hpp + ) +else() + message( FATAL_ERROR "No supported architecture selected" ) +endif(BUILD_BOCHS) + +# Find the libraries that correspond to the LLVM components +# that we wish to use +llvm_map_components_to_libnames(llvm_libs object support core mc AllTargetsDisassemblers AllTargetsDescs) + +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) add_library(fail-llvmdisassembler ${SRCS}) target_link_libraries(fail-llvmdisassembler fail-sal) -target_link_libraries(fail-llvmdisassembler ${LLVM_LIBS} ${LLVM_LDFLAGS} ) +target_link_libraries(fail-llvmdisassembler ${llvm_libs}) ### Tests add_executable(llvmDisTest testing/llvmDisTest.cc) diff --git a/src/core/util/llvmdisassembler/LLVMDisassembler.cpp b/src/core/util/llvmdisassembler/LLVMDisassembler.cpp index a4f117f1..c98c7717 100644 --- a/src/core/util/llvmdisassembler/LLVMDisassembler.cpp +++ b/src/core/util/llvmdisassembler/LLVMDisassembler.cpp @@ -1,6 +1,31 @@ #include "LLVMDisassembler.hpp" + +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" + #include "util/Logger.hpp" +#ifdef BUILD_BOCHS +#include "LLVMtoFailBochs.hpp" +#endif + +#ifdef BUILD_GEM5 +#include "LLVMtoFailGem5.hpp" +#endif + +#if defined(BUILD_RISCV) || defined(BUILD_RISCV_CHERI) +#include "LLVMtoFailSailRiscv.hpp" +#endif + +#include "util/ElfReader.hpp" + + using namespace fail; using namespace llvm; using namespace llvm::object; @@ -10,13 +35,24 @@ static Logger LOG("LLVMDisassembler"); LLVMtoFailTranslator *LLVMDisassembler::getTranslator() { if (!ltofail) { switch ( llvm::Triple::ArchType(m_object->getArch()) ) { +#ifdef BUILD_BOCHS case llvm::Triple::x86: case llvm::Triple::x86_64: ltofail.reset(new LLVMtoFailBochs(this)); break; +#endif +#ifdef BUILD_GEM5 case llvm::Triple::arm: ltofail.reset(new LLVMtoFailGem5(this)); break; +#endif +#if defined(BUILD_RISCV) || defined(BUILD_RISCV_CHERI) + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + ltofail.reset(new LLVMtoFailSailRiscv(this)); + break; +#endif + default: LOG << "ArchType " << llvm::Triple::getArchTypeName(llvm::Triple::ArchType(m_object->getArch())).str() @@ -35,6 +71,8 @@ LLVMDisassembler::LLVMDisassembler(ElfReader *elf) { std::string filename = elf->getFilename(); + m_xlen = elf->m_elfclass == ELFCLASS64 ? 64 : 32; + Expected> BinaryOrErr = createBinary(filename); if (!BinaryOrErr) { std::string Buf; @@ -52,20 +90,31 @@ LLVMDisassembler::LLVMDisassembler(ElfReader *elf) { this->triple = GetTriple(m_object); this->target = GetTarget(triple); + // Package up features to be passed to target/subtarget + llvm::SubtargetFeatures Features = m_object->getFeatures(); + if (this->triple.rfind("riscv", 0) == 0) { + Features.AddFeature("+M"); + } + + llvm::MCTargetOptions options; +#if LLVM_VERSION_MAJOR >= 11 && (defined(BUILD_RISCV) || defined(BUILD_CHERI)) + std::unique_ptr MRI(target->createMCRegInfo(triple ,options)); +#else std::unique_ptr MRI(target->createMCRegInfo(triple)); +#endif if (!MRI) { std::cerr << "DIS error: no register info for target " << triple << "\n"; return; } - std::unique_ptr MAI(target->createMCAsmInfo(*MRI, triple)); + std::unique_ptr MAI(target->createMCAsmInfo(*MRI, triple, options)); if (!MAI) { std::cerr << "DIS error: no assembly info for target " << triple << "\n"; return; } std::unique_ptr STI( - target->createMCSubtargetInfo(triple, MCPU, FeaturesStr)); + target->createMCSubtargetInfo(triple, MCPU, Features.getString())); if (!STI) { std::cerr << "DIS error: no subtarget info for target " << triple << "\n"; return; @@ -132,18 +181,23 @@ void LLVMDisassembler::disassemble() // Sort the symbols by address, just in case they didn't come in that way. array_pod_sort(Symbols.begin(), Symbols.end()); - StringRef name; - if (error(i->getName(name))) break; + llvm::Expected maybeName = i->getName(); + if(auto err = maybeName.takeError()) { + std::cerr << "couldn't get section name for section @ " << std::hex << SectionAddr << " -> skipping!" << std::endl; + break; + } + // safe here, potential error is handled. + auto& name = *maybeName; // If the section has no symbols just insert a dummy one and disassemble // the whole section. if (Symbols.empty()) Symbols.push_back(std::make_pair(0, name)); - StringRef BytesStr; - if (error(i->getContents(BytesStr))) break; - ArrayRef Bytes(reinterpret_cast(BytesStr.data()), - BytesStr.size()); + Expected BytesStr = i->getContents(); + if (BytesStr.takeError()) break; + ArrayRef Bytes(reinterpret_cast(BytesStr->data()), + BytesStr->size()); uint64_t Size; uint64_t Index; @@ -171,7 +225,7 @@ void LLVMDisassembler::disassemble() MCInst Inst; if (disas->getInstruction(Inst, Size, Bytes.slice(Index), Index, - nulls(), nulls()) == MCDisassembler::Success) { + nulls()) == MCDisassembler::Success) { const MCInstrDesc &desc = this->instr_info->get(Inst.getOpcode()); Instr instr; @@ -221,3 +275,13 @@ void LLVMDisassembler::disassemble() LOG << "instructions disassembled: " << std::dec << instrs->size() << std::endl; } + +const std::string +LLVMDisassembler::GetSubtargetFeatures() const { + return m_object->getFeatures().getString(); +} + +std::string +LLVMDisassembler::getRegisterName(unsigned id) { + return getRegisterInfo().getName(id); +} diff --git a/src/core/util/llvmdisassembler/LLVMDisassembler.hpp b/src/core/util/llvmdisassembler/LLVMDisassembler.hpp index 5109c757..4317dc4e 100644 --- a/src/core/util/llvmdisassembler/LLVMDisassembler.hpp +++ b/src/core/util/llvmdisassembler/LLVMDisassembler.hpp @@ -7,34 +7,24 @@ #include #include // unique_ptr -#include "util/ElfReader.hpp" - #include "llvm/Object/ObjectFile.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/Support/Casting.h" #include "LLVMtoFailTranslator.hpp" - namespace fail { +class ElfReader; + class LLVMDisassembler { public: @@ -107,9 +97,9 @@ class LLVMDisassembler { const llvm::MCRegisterInfo& getRegisterInfo() { return *register_info; } - std::string getRegisterName(unsigned id) { return getRegisterInfo().getName(id); } + std::string getRegisterName(unsigned id); - const std::string GetSubtargetFeatures() const { return m_object->getFeatures().getString(); } + const std::string GetSubtargetFeatures() const; void disassemble(); diff --git a/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.cpp b/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.cpp new file mode 100644 index 00000000..b0afc514 --- /dev/null +++ b/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.cpp @@ -0,0 +1,147 @@ +#include "LLVMtoFailSailRiscv.hpp" +#include "LLVMDisassembler.hpp" +#include +#include +#include +#include +#include "sal/sail/SailArchitecture.hpp" + +using namespace fail; + +LLVMtoFailSailRiscv::LLVMtoFailSailRiscv(LLVMDisassembler *disas) { + std::map m; + unsigned xlen = disas->getWordWidth(); + + std::string features = disas->GetSubtargetFeatures(); + + std::cout << "features: " << features << std::endl; + bool is_cheri = features.find("+xcheri") != std::string::npos; + bool is_cheri_purecap = features.find("+cap-mode") != std::string::npos; + + std::cout << std::boolalpha << " is_cheri: " << is_cheri << " is_purecap: " << is_cheri_purecap << std::endl; + + m["pc"] = RegisterView(RID_PC, 2*xlen); + m["ra"] = RegisterView(RID_RA, xlen); + m["x1"] = RegisterView(RID_RA, xlen); + m["sp"] = RegisterView(RID_SP, xlen); + m["x2"] = RegisterView(RID_SP, xlen); + m["gp"] = RegisterView(RID_GP, xlen); + m["x3"] = RegisterView(RID_GP , xlen); + m["tp"] = RegisterView(RID_TP, xlen); + m["x4"] = RegisterView(RID_TP, xlen); + m["t0"] = RegisterView(RID_T0, xlen); + m["x5"] = RegisterView(RID_T0, xlen); + m["t1"] = RegisterView(RID_T1, xlen); + m["x6"] = RegisterView(RID_T1, xlen); + m["t2"] = RegisterView(RID_T2, xlen); + m["x7"] = RegisterView(RID_T2, xlen); + m["s0"] = RegisterView(RID_S0, xlen); + m["x8"] = RegisterView(RID_S0, xlen); + m["s1"] = RegisterView(RID_S1, xlen); + m["x9"] = RegisterView(RID_S1, xlen); + m["a0"] = RegisterView(RID_A0, xlen); + m["x10"] = RegisterView(RID_A0, xlen); + m["a1"] = RegisterView(RID_A1, xlen); + m["x11"] = RegisterView(RID_A1, xlen); + m["a2"] = RegisterView(RID_A2, xlen); + m["x12"] = RegisterView(RID_A2, xlen); + m["a3"] = RegisterView(RID_A3, xlen); + m["x13"] = RegisterView(RID_A3, xlen); + m["a4"] = RegisterView(RID_A4, xlen); + m["x14"] = RegisterView(RID_A4, xlen); + m["a5"] = RegisterView(RID_A5, xlen); + m["x15"] = RegisterView(RID_A5, xlen); + m["a6"] = RegisterView(RID_A6, xlen); + m["x16"] = RegisterView(RID_A6, xlen); + m["a7"] = RegisterView(RID_A7, xlen); + m["x17"] = RegisterView(RID_A7, xlen); + m["s2"] = RegisterView(RID_S2, xlen); + m["x18"] = RegisterView(RID_S2, xlen); + m["s3"] = RegisterView(RID_S3, xlen); + m["x19"] = RegisterView(RID_S3, xlen); + m["s4"] = RegisterView(RID_S4, xlen); + m["x20"] = RegisterView(RID_S4, xlen); + m["s5"] = RegisterView(RID_S5, xlen); + m["x21"] = RegisterView(RID_S5, xlen); + m["s6"] = RegisterView(RID_S6, xlen); + m["x22"] = RegisterView(RID_S6, xlen); + m["s7"] = RegisterView(RID_S7, xlen); + m["x23"] = RegisterView(RID_S7, xlen); + m["s8"] = RegisterView(RID_S8, xlen); + m["x24"] = RegisterView(RID_S8, xlen); + m["s9"] = RegisterView(RID_S9, xlen); + m["x25"] = RegisterView(RID_S9, xlen); + m["s10"] = RegisterView(RID_S10, xlen); + m["x26"] = RegisterView(RID_S10, xlen); + m["s11"] = RegisterView(RID_S11, xlen); + m["x27"] = RegisterView(RID_S11, xlen); + m["t3"] = RegisterView(RID_T3, xlen); + m["x28"] = RegisterView(RID_T3, xlen); + m["t4"] = RegisterView(RID_T4, xlen); + m["x29"] = RegisterView(RID_T4, xlen); + m["t5"] = RegisterView(RID_T5, xlen); + m["x30"] = RegisterView(RID_T5, xlen); + m["t6"] = RegisterView(RID_T6, xlen); + m["x31"] = RegisterView(RID_T6, xlen); + + if(is_cheri) { +#ifdef BUILD_RISCV_CHERI + m["ddc"] = RegisterView(RID_DDC, 2*xlen); + if(is_cheri_purecap) { + m["c1"] = RegisterView(RID_RA, 2*xlen); + m["c2"] = RegisterView(RID_SP, 2*xlen); + m["c3"] = RegisterView(RID_GP, 2*xlen); + m["c4"] = RegisterView(RID_TP, 2*xlen); + m["c5"] = RegisterView(RID_T0, 2*xlen); + m["c6"] = RegisterView(RID_T1, 2*xlen); + m["c7"] = RegisterView(RID_T2, 2*xlen); + m["c8"] = RegisterView(RID_S0, 2*xlen); + m["c9"] = RegisterView(RID_S1, 2*xlen); + m["c10"] = RegisterView(RID_A0, 2*xlen); + m["c11"] = RegisterView(RID_A1, 2*xlen); + m["c12"] = RegisterView(RID_A2, 2*xlen); + m["c13"] = RegisterView(RID_A3, 2*xlen); + m["c14"] = RegisterView(RID_A4, 2*xlen); + m["c15"] = RegisterView(RID_A5, 2*xlen); + m["c16"] = RegisterView(RID_A6, 2*xlen); + m["c17"] = RegisterView(RID_A7, 2*xlen); + m["c18"] = RegisterView(RID_S2, 2*xlen); + m["c19"] = RegisterView(RID_S3, 2*xlen); + m["c20"] = RegisterView(RID_S4, 2*xlen); + m["c21"] = RegisterView(RID_S5, 2*xlen); + m["c22"] = RegisterView(RID_S6, 2*xlen); + m["c23"] = RegisterView(RID_S7, 2*xlen); + m["c24"] = RegisterView(RID_S8, 2*xlen); + m["c25"] = RegisterView(RID_S9, 2*xlen); + m["c26"] = RegisterView(RID_S10, 2*xlen); + m["c27"] = RegisterView(RID_S11, 2*xlen); + m["c28"] = RegisterView(RID_T3, 2*xlen); + m["c29"] = RegisterView(RID_T4, 2*xlen); + m["c30"] = RegisterView(RID_T5, 2*xlen); + m["c31"] = RegisterView(RID_T6, 2*xlen); + } + else { + // FIXME: what is actually needed here? + // TODO: explore how hybrid binary look + throw std::runtime_error("non purecap code is currently not supported."); + } +#endif + } + + const llvm::MCRegisterInfo ®_info = disas->getRegisterInfo(); + std::vector failed_translations; + for (unsigned int i = 0; i < reg_info.getNumRegs(); ++i) { + std::string name = reg_info.getName(i); + std::transform(name.begin(),name.end(),name.begin(),[] (auto c) { return std::tolower(c); }); + if (m.count(name) > 0) { + llvm_to_fail_map[i] = m[name]; + } else { + failed_translations.push_back(name); + } + } + std::cout << "failed to find translations for: "; + std::string out; + for(const auto& n: failed_translations) + out += "," + n; + std::cout << out << std::endl; +} diff --git a/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.hpp b/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.hpp new file mode 100644 index 00000000..06760d16 --- /dev/null +++ b/src/core/util/llvmdisassembler/LLVMtoFailSailRiscv.hpp @@ -0,0 +1,16 @@ +#ifndef LLVMTOFAILSAILRISCV_HPP +#define LLVMTOFAILSAILRISCV_HPP + +#include "LLVMtoFailTranslator.hpp" + +namespace fail { + +class LLVMDisassembler; + +class LLVMtoFailSailRiscv : public LLVMtoFailTranslator { +public: + LLVMtoFailSailRiscv(LLVMDisassembler *disas); +}; +} // end of namespace + +#endif /* LLVMTOFAILSAILRISCV_HPP */ diff --git a/src/core/util/llvmdisassembler/testing/llvmDisTest.cc b/src/core/util/llvmdisassembler/testing/llvmDisTest.cc index cc11fbce..b33c2bd8 100644 --- a/src/core/util/llvmdisassembler/testing/llvmDisTest.cc +++ b/src/core/util/llvmdisassembler/testing/llvmDisTest.cc @@ -1,5 +1,7 @@ #include "llvm/Support/raw_os_ostream.h" #include "../LLVMDisassembler.hpp" +#include "util/ElfReader.hpp" + using namespace llvm; using namespace llvm::object; diff --git a/src/plugins/serialoutput/CMakeLists.txt b/src/plugins/serialoutput/CMakeLists.txt index 066b138c..8c240577 100644 --- a/src/plugins/serialoutput/CMakeLists.txt +++ b/src/plugins/serialoutput/CMakeLists.txt @@ -8,3 +8,4 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) ## Build library add_library(fail-${PLUGIN_NAME} ${MY_PLUGIN_SRCS}) +add_dependencies(fail-${PLUGIN_NAME} fail-protoc) diff --git a/tools/import-trace/CMakeLists.txt b/tools/import-trace/CMakeLists.txt index d2f4b427..077ab6b6 100644 --- a/tools/import-trace/CMakeLists.txt +++ b/tools/import-trace/CMakeLists.txt @@ -11,23 +11,21 @@ if (BUILD_LLVM_DISASSEMBLER) RandomJumpImporter.cc AdvancedMemoryImporter.cc ElfImporter.cc - ) +) - include(FindLLVM) + # Add LLVM Headers + llvm_map_components_to_libnames(llvm_libs object support core mc AllTargetsDisassemblers AllTargetsDescs) + include_directories(${LLVM_INCLUDE_DIRS}) + add_definitions(${LLVM_DEFINITIONS}) # llvm-config does add -fno-exception to the command line. But this # breaks some boost libraries. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fexceptions") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fexceptions") find_package(Boost 1.42 COMPONENTS regex REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) - # libelf and libdwarf required by ElfImporter - find_package(LibElf REQUIRED) - find_package(LibDwarf REQUIRED) - include_directories(${LIBELF_INCLUDE_DIRS}) - include_directories(${LIBDWARF_INCLUDE_DIRS}) endif(BUILD_LLVM_DISASSEMBLER) if (BUILD_CAPSTONE_DISASSEMBLER) @@ -41,13 +39,14 @@ if (BUILD_CAPSTONE_DISASSEMBLER) include(FindCapstone) - # libelf and libdwarf required by ElfImporter - find_package(LibElf REQUIRED) - find_package(LibDwarf REQUIRED) - include_directories(${LIBELF_INCLUDE_DIRS}) - include_directories(${LIBDWARF_INCLUDE_DIRS}) endif(BUILD_CAPSTONE_DISASSEMBLER) +# libelf and libdwarf required by ElfImporter +find_package(LibElf REQUIRED) +find_package(LibDwarf REQUIRED) +include_directories(${LIBELF_INCLUDE_DIRS}) +include_directories(${LIBDWARF_INCLUDE_DIRS}) + find_package(MySQL REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MYSQL_CFLAGS}") diff --git a/tools/import-trace/MemoryImporter.cc b/tools/import-trace/MemoryImporter.cc index 13126165..916e2e2d 100644 --- a/tools/import-trace/MemoryImporter.cc +++ b/tools/import-trace/MemoryImporter.cc @@ -24,14 +24,26 @@ bool MemoryImporter::handle_mem_event(simtime_t curtime, instruction_count_t ins char access_type = ev.accesstype() == ev.READ ? 'R' : 'W'; - guest_address_t from = ev.memaddr(), to = ev.memaddr() + ev.width(); - LOG << std::hex << std::showbase << ev.width() << " bytes -> from=" << from << " to=" << to << std::endl; +#ifdef BUILD_SAIL + // SAIL Produces bit width reads + unsigned byte_count = std::ceil(ev.width() / 8.0); + unsigned bit_count = ev.width(); +#else + unsigned byte_count = ev.width(); + unsigned bit_count = ev.width() * 8; +#endif + + guest_address_t from = ev.memaddr(), to = ev.memaddr() + byte_count; + LOG << std::hex << std::showbase << bit_count << " bits -> from=" << from << " to=" << to << std::endl; auto filter = [this] (address_t a) -> bool { return !(this->m_mm && !this->m_mm->isMatching(a)); }; for (auto &element : area->translate(from, to, filter)) { - if(!add_faultspace_element(curtime, instr, element, 0xFF, + unsigned mask = (1u << std::min(8u, bit_count)) - 1; + if(!add_faultspace_element(curtime, instr, element, mask, access_type, ev)) return false; + + bit_count -= 8; } } return true;