Compare commits
143 Commits
Author | SHA1 | Date |
---|---|---|
Andreas Sandberg | c7f92c43da | |
Curtis Dunham | 567a9b0a08 | |
Curtis Dunham | 60075068ea | |
Curtis Dunham | 2f14baaabc | |
Curtis Dunham | bbdd34d628 | |
Nikos Nikoleris | 3384caf0fe | |
Nikos Nikoleris | 4b164f8382 | |
Andreas Sandberg | 31199bba53 | |
Andreas Sandberg | 9a13acaa36 | |
Andreas Sandberg | 3547af6e44 | |
Andreas Sandberg | 66a1016a35 | |
Andreas Sandberg | d2254e034e | |
Sascha Bischoff | d7aef8be96 | |
Andreas Sandberg | ba00d7449d | |
Andreas Sandberg | cd9ca71b25 | |
Matteo Andreozzi | 626a0cc003 | |
Gabe Black | 9f3615d9c9 | |
Gabe Black | d82e59f74b | |
Gabe Black | ed44b7f6e2 | |
Gabe Black | 03ea796a79 | |
Curtis Dunham | 7d6f2c5050 | |
Andreas Sandberg | 7110d2313e | |
Andreas Sandberg | 065bb8c655 | |
Pierre-Yves Péneau | a4060ab950 | |
Brandon Potter | fcf94310eb | |
Brandon Potter | 1991ff3bb2 | |
Radhika Jagtap | 48333e7e3f | |
Nikos Nikoleris | e2805f825a | |
Andreas Sandberg | 083cd6da78 | |
Andreas Sandberg | 3e200455bd | |
Andreas Sandberg | 35cb11f14e | |
Brandon Potter | 011ddf96fa | |
Brandon Potter | 691a4574b4 | |
Brandon Potter | 2c1286865f | |
Brandon Potter | 6f7bf1b11f | |
Brandon Potter | 8b85f950e5 | |
Brandon Potter | 198c515b97 | |
Brandon Potter | acce7b0dc0 | |
Brandon Potter | e5fe2b82b7 | |
Brandon Potter | 43418e7f81 | |
Pierre-Yves Péneau | 71dd6c2c17 | |
Lena Olson | b2669a7875 | |
Lena Olson | 620bf51ae7 | |
Jason Lowe-Power | 138000796a | |
Andreas Sandberg | b043dcf58a | |
Andreas Sandberg | c07a2d68f3 | |
Sudhanshu Jha | 846a17308c | |
Sudhanshu Jha | 9dd54d10ab | |
Sudhanshu Jha | 82a8230aa7 | |
Sudhanshu Jha | 746e2f3c27 | |
Brandon Potter | 46bfc14312 | |
Nikos Nikoleris | 83cabc6264 | |
Nikos Nikoleris | ce2a0076c9 | |
Rahul Thakur | ceb3bd9733 | |
Rahul Thakur | 0fc9dcf46b | |
Pierre-Yves Péneau | f3e0ac2b06 | |
Lena Olson | efcd8ae024 | |
Andreas Sandberg | 93e20c9a73 | |
Brandon Potter | 2367198921 | |
Brandon Potter | 073cb26607 | |
Brandon Potter | f5656738dc | |
Tony Gutierrez | 8602aea4e5 | |
Brandon Potter | 833fb10ed4 | |
Andreas Sandberg | 8d2c3735d9 | |
Andreas Sandberg | 60b26f1546 | |
Andreas Sandberg | bec4409add | |
Andreas Sandberg | 8b1ba9f99d | |
Brandon Potter | a5802c823f | |
Brandon Potter | a7a0fd2c58 | |
Brandon Potter | 6f549419eb | |
Brandon Potter | 748b87fc36 | |
Brandon Potter | a4c4b4188d | |
Nikos Nikoleris | 41bc2886de | |
Nikos Nikoleris | 83028e730c | |
Nikos Nikoleris | cb97118d91 | |
Nikos Nikoleris | e8723310ef | |
Nikos Nikoleris | da1ddb9aa7 | |
Nikos Nikoleris | a063a14905 | |
Sascha Bischoff | 46b4c40277 | |
Nikos Nikoleris | 767aed4534 | |
Nikos Nikoleris | d37bdc7366 | |
Nikos Nikoleris | 8fe8836eea | |
Nikos Nikoleris | 3c005c0f0e | |
Nikos Nikoleris | 2213fba5c5 | |
Andreas Hansson | f2e2410a50 | |
Andreas Hansson | 184c6d7ebd | |
Andreas Hansson | 912b20d02a | |
Andreas Hansson | 4fc16544af | |
Brandon Potter | d3d983caf9 | |
Brandon Potter | 6c41181b8e | |
Brandon Potter | 49009f170a | |
Brandon Potter | ea8461885f | |
Brandon Potter | b792e9e43c | |
Brandon Potter | 3886c4a8f2 | |
Brandon Potter | 7b6cf951e2 | |
Brandon Potter | 96f8ff5702 | |
Pierre-Yves Péneau | a854373d59 | |
Pierre-Yves Péneau | a06a46f5d1 | |
Wendy Elsasser | ddc6931573 | |
Gabor Dozsa | 4b8b9c0585 | |
Gabor Dozsa | 3bdd58ccb4 | |
Gabor Dozsa | 54c478c0b8 | |
Curtis Dunham | 80c17d0a8d | |
Andreas Sandberg | 092b06b745 | |
Curtis Dunham | 0edf6dc956 | |
Curtis Dunham | 41beacce08 | |
Curtis Dunham | d3bfc03688 | |
Wendy Elsasser | ca0fd665dc | |
Curtis Dunham | 94e6126650 | |
Curtis Dunham | 5638a074b9 | |
Curtis Dunham | 72e74aed0a | |
Alec Roelke | e9311a59ed | |
Christian Menard | 1f1388b6c8 | |
Tushar Krishna | 1be05afa06 | |
Bjoern A. Zeeb | f3643c8a60 | |
Jason Lowe-Power | 153e5879c6 | |
Jason Lowe-Power | 87b9f0b87b | |
Jason Lowe-Power | 76004f08f2 | |
Christian Menard | a309c2f343 | |
Christian Menard | 78e4967b6a | |
Christian Menard | 0c4a69bcbf | |
Christian Menard | b5045005de | |
Christian Menard | 03f740664b | |
Christian Menard | ccd9210e1a | |
Christian Menard | d2b19d2732 | |
Christian Menard | 55f5c4dd8a | |
Christian Menard | b25ea094d4 | |
Christian Menard | 41a6158954 | |
Christian Menard | 164d9bd732 | |
Christian Menard | 5fd959260c | |
Christian Menard | f4b14c73fc | |
Bjoern A. Zeeb | 0852f0cfc6 | |
Bjoern A. Zeeb | b673f2aaa4 | |
Bjoern A. Zeeb | e07f0c5043 | |
Bjoern A. Zeeb | d728f6786b | |
Bjoern A. Zeeb | f0786704db | |
Andreas Sandberg | 653b4657e6 | |
Nikos Nikoleris | 227bdde922 | |
Alec Roelke | e4c57275d3 | |
Paul Rosenfeld | c5df9308c9 | |
Rahul Thakur | e9889c46ed | |
Rahul Thakur | 32d05d5fb6 | |
Andreas Sandberg | 2974dc7a37 |
|
@ -13,3 +13,4 @@ m5out
|
|||
/util/m5/*.o
|
||||
/util/m5/*.a
|
||||
/util/m5/m5
|
||||
/system/arm/dt/*.dtb
|
||||
|
|
|
@ -14,3 +14,4 @@ ext/mcpat/regression/*/*.out
|
|||
util/m5/*.o
|
||||
util/m5/*.a
|
||||
util/m5/m5
|
||||
system/arm/dt/*.dtb
|
||||
|
|
|
@ -0,0 +1,337 @@
|
|||
Authors: Jason Lowe-Power
|
||||
Andreas Sandberg
|
||||
Steve Reinhardt
|
||||
|
||||
If you've made changes to gem5 that might benefit others, we strongly encourage
|
||||
you to contribute those changes to the public gem5 repository. There are
|
||||
several reasons to do this:
|
||||
* Share your work with others, so that they can benefit from new functionality.
|
||||
* Support the scientific principle by enabling others to evaluate your
|
||||
suggestions without having to guess what you did.
|
||||
* Once your changes are part of the main repo, you no longer have to merge
|
||||
them back in every time you update your local repo. This can be a huge time
|
||||
saving!
|
||||
* Once your code is in the main repo, other people have to make their changes
|
||||
work with your code, and not the other way around.
|
||||
* Others may build on your contributions to make them even better, or extend
|
||||
them in ways you did not have time to do.
|
||||
* You will have the satisfaction of contributing back to the community.
|
||||
|
||||
The main method for contributing code to gem5 is via our code review website:
|
||||
https://gem5-review.googlesource.com/. This documents describes the details of
|
||||
how to create code changes, upload your changes, have your changes
|
||||
reviewed, and finally push your changes to gem5. More information can be found
|
||||
from the following sources:
|
||||
* http://gem5.org/Submitting_Contributions
|
||||
* https://gerrit-review.googlesource.com/Documentation/index.html
|
||||
* https://git-scm.com/book
|
||||
|
||||
|
||||
High-level flow for submitting changes
|
||||
======================================
|
||||
|
||||
+-------------+
|
||||
| Make change |
|
||||
+------+------+
|
||||
|
|
||||
|
|
||||
v
|
||||
+------+------+
|
||||
| Post review |
|
||||
+------+------+
|
||||
|
|
||||
v
|
||||
+--------+---------+
|
||||
| Wait for reviews | <--------+
|
||||
+--------+---------+ |
|
||||
| |
|
||||
| |
|
||||
v |
|
||||
+----+----+ No +------+------+
|
||||
|Reviewers+--------->+ Update code |
|
||||
|happy? | +------+------+
|
||||
+----+----+ ^
|
||||
| |
|
||||
| Yes |
|
||||
v |
|
||||
+----+-----+ No |
|
||||
|Maintainer+----------------+
|
||||
|happy? |
|
||||
+----+-----+
|
||||
|
|
||||
| Yes
|
||||
v
|
||||
+------+------+
|
||||
| Submit code |
|
||||
+-------------+
|
||||
|
||||
After creating your change to gem5, you can post a review on our Gerrit
|
||||
code-review site: https://gem5-review.googlesource.com. Before being able to
|
||||
submit your code to the mainline of gem5, the code is reviewed by others in the
|
||||
community. Additionally, the maintainer for that part of the code must sign off
|
||||
on it.
|
||||
|
||||
Cloning the gem5 repo to contribute
|
||||
===================================
|
||||
|
||||
If you plan on contributing, it is strongly encouraged for you to clone the
|
||||
repository directly from our gerrit instance at
|
||||
https://gem5.googlesource.com/.
|
||||
|
||||
To clone the master gem5 repository:
|
||||
> git clone https://gem5.googlesource.com/public/gem5
|
||||
|
||||
Other gem5 repositories
|
||||
-----------------------
|
||||
|
||||
There are a few repositories other than the main gem5 development repository.
|
||||
|
||||
* public/m5threads: The code for a pthreads implementation that works with
|
||||
gem5's syscall emulation mode.
|
||||
|
||||
Other gem5 branches
|
||||
-------------------
|
||||
|
||||
None right now.
|
||||
|
||||
Making changes to gem5
|
||||
======================
|
||||
|
||||
It is strongly encouraged to use git branches when making changes to gem5.
|
||||
Additionally, keeping changes small and concise and only have a single logical
|
||||
change per commit.
|
||||
|
||||
Unlike our previous flow with Mercurial and patch queues, when using git, you
|
||||
will be committing changes to your local branch. By using separate branches in
|
||||
git, you will be able to pull in and merge changes from mainline and simply
|
||||
keep up with upstream changes.
|
||||
|
||||
Requirements for change descriptions
|
||||
------------------------------------
|
||||
To help reviewers and future contributors more easily understand and track
|
||||
changes, we require all change descriptions be strictly formatted.
|
||||
|
||||
A canonical commit message consists of three parts:
|
||||
* A short summary line describing the change. This line starts with one or
|
||||
more keywords separated by commas followed by a colon and a description of
|
||||
the change. This line should be no more than 65 characters long since
|
||||
version control systems usually add a prefix that causes line-wrapping for
|
||||
longer lines.
|
||||
* (Optional, but highly recommended) A detailed description. This describes
|
||||
what you have done and why. If the change isn't obvious, you might want to
|
||||
motivate why it is needed. Lines need to be wrapped to 75 characters or
|
||||
less.
|
||||
* Tags describing patch metadata. You are highly recommended to use
|
||||
tags to acknowledge reviewers for their work. Gerrit will automatically add
|
||||
most tags.
|
||||
|
||||
The keyword should be one or more of the following separated by commas:
|
||||
* Architecture name in lower case (e.g., arm or x86): Anything that is
|
||||
target-architecture specific.
|
||||
* base
|
||||
* ext
|
||||
* stats
|
||||
* sim
|
||||
* syscall_emul
|
||||
* config:
|
||||
* mem: Classic memory system. Ruby uses its own keyword.
|
||||
* ruby: Ruby memory models.
|
||||
* cpu: CPU-model specific (except for kvm)
|
||||
* kvm: KVM-specific. Changes to host architecture specific components should
|
||||
include an architecture keyword (e.g., arm or x86) as well.
|
||||
* gpu-compute
|
||||
* energy
|
||||
* dev
|
||||
* arch: General architecture support (src/arch/)
|
||||
* scons: Build-system related. Trivial changes as a side effect of doing
|
||||
something unrelated (e.g., adding a source file to a SConscript) don't
|
||||
require this.
|
||||
* tests
|
||||
* style: Changes to the style checkers of style fixes.
|
||||
* misc
|
||||
|
||||
Tags are an optional mechanism to store additional metadata about a patch and
|
||||
acknowledge people who reported a bug or reviewed that patch. Tags are
|
||||
generally appended to the end of the commit message in the order they happen.
|
||||
We currently use the following tags:
|
||||
* Signed-off-by: Added by the author and the submitter (if different).
|
||||
This tag is a statement saying that you believe the patch to be correct and
|
||||
have the right to submit the patch according to the license in the affected
|
||||
files. Similarly, if you commit someone else's patch, this tells the rest
|
||||
of the world that you have have the right to forward it to the main
|
||||
repository. If you need to make any changes at all to submit the change,
|
||||
these should be described within hard brackets just before your
|
||||
Signed-off-by tag. By adding this line, the contributor certifies the
|
||||
contribution is made under the terms of the Developer Certificate of Origin
|
||||
(DCO) [https://developercertificate.org/].
|
||||
* Reviewed-by: Used to acknowledge patch reviewers. It's generally considered
|
||||
good form to add these. Added automatically.
|
||||
* Reported-by: Used to acknowledge someone for finding and reporting a bug.
|
||||
* Reviewed-on: Link to the review request corresponding to this patch. Added
|
||||
automatically.
|
||||
* Change-Id: Used by Gerrit to track changes across rebases. Added
|
||||
automatically with a commit hook by git.
|
||||
* Tested-by: Used to acknowledge people who tested a patch. Sometimes added
|
||||
automatically by review systems that integrate with CI systems.
|
||||
|
||||
Other than the "Signed-off-by", "Reported-by", and "Tested-by" tags, you
|
||||
generally don't need to add these manually as they are added automatically by
|
||||
Gerrit.
|
||||
|
||||
It is encouraged for the author of the patch and the submitter to add a
|
||||
Signed-off-by tag to the commit message. By adding this line, the contributor
|
||||
certifies the contribution is made under the terms of the Developer Certificate
|
||||
of Origin (DCO) [https://developercertificate.org/].
|
||||
|
||||
It is imperative that you use your real name and your real email address in
|
||||
both tags and in the author field of the changeset.
|
||||
|
||||
For significant changes, authors are encouraged to add copyright information
|
||||
and their names at the beginning of the file. The main purpose of the author
|
||||
names on the file is to track who is most knowledgeable about the file (e.g.,
|
||||
who has contributed a significant amount of code to the file).
|
||||
|
||||
Note: If you do not follow these guidelines, the gerrit review site will
|
||||
automatically reject your patch.
|
||||
If this happens, update your changeset descriptions to match the required style
|
||||
and resubmit. The following is a useful git command to update the most recent
|
||||
commit (HEAD).
|
||||
|
||||
> git commit --amend
|
||||
|
||||
Posting a review
|
||||
================
|
||||
|
||||
If you have not signed up for an account on the Gerrit review site
|
||||
(https://gem5-review.googlesource.com), you first have to create an account.
|
||||
|
||||
Setting up an account
|
||||
---------------------
|
||||
1. Go to https://gem5.googlesource.com/
|
||||
2. Click "Sign In" in the upper right corner. Note: You will need a Google
|
||||
account to contribute.
|
||||
3. After signing in, click "Generate Password" and follow the instructions.
|
||||
|
||||
Submitting a change
|
||||
-------------------
|
||||
|
||||
In gerrit, to submit a review request, you can simply push your git commits to
|
||||
a special named branch. For more information on git push see
|
||||
https://git-scm.com/docs/git-push.
|
||||
|
||||
There are three ways to push your changes to gerrit.
|
||||
|
||||
Push change to gerrit review
|
||||
----------------------------
|
||||
|
||||
> git push origin HEAD:refs/for/master
|
||||
|
||||
Assuming origin is https://gem5.googlesource.com/public/gem5 and you want to
|
||||
push the changeset at HEAD, this will create a new review request on top of the
|
||||
master branch. More generally,
|
||||
|
||||
> git push <gem5 gerrit instance> <changeset>:refs/for/<branch>
|
||||
|
||||
See https://gerrit-review.googlesource.com/Documentation/user-upload.html for
|
||||
more information.
|
||||
|
||||
Pushing your first change
|
||||
--------------------------
|
||||
The first time you push a change you may get the following error:
|
||||
|
||||
> remote: ERROR: [fb1366b] missing Change-Id in commit message footer
|
||||
> ...
|
||||
|
||||
Within the error message, there is a command line you should run. For every new
|
||||
clone of the git repo, you need to run the following command to automatically
|
||||
insert the change id in the the commit (all on one line).
|
||||
|
||||
> curl -Lo `git rev-parse --git-dir`/hooks/commit-msg
|
||||
https://gerrit-review.googlesource.com/tools/hooks/commit-msg ; chmod +x
|
||||
`git rev-parse --git-dir`/hooks/commit-msg
|
||||
|
||||
If you receive the above error, simply run this command and then amend your
|
||||
changeset.
|
||||
|
||||
> git commit --amend
|
||||
|
||||
Push change to gerrit as a draft
|
||||
--------------------------------
|
||||
|
||||
> git push origin HEAD:refs/drafts/master
|
||||
|
||||
Push change bypassing gerrit
|
||||
-----------------------------
|
||||
|
||||
Only maintainers can bypass gerrit review. This should very rarely be used.
|
||||
|
||||
> git push origin HEAD:refs/heads/master
|
||||
|
||||
Other gerrit push options
|
||||
-------------------------
|
||||
|
||||
There are a number of options you can specify when uploading your changes to
|
||||
gerrit (e.g., reviewers, labels). The gerrit documentation has more
|
||||
information.
|
||||
https://gerrit-review.googlesource.com/Documentation/user-upload.html
|
||||
|
||||
|
||||
Reviewing patches
|
||||
=================
|
||||
|
||||
Reviewing patches is done on our gerrit instance at
|
||||
https://gem5-review.googlesource.com/.
|
||||
|
||||
After logging in with your Google account, you will be able to comment, review,
|
||||
and push your own patches as well as review others' patches. All gem5 users are
|
||||
encouraged to review patches. The only requirement to review patches is to be
|
||||
polite and respectful of others.
|
||||
|
||||
There are multiple labels in Gerrit that can be applied to each review detailed
|
||||
below.
|
||||
* Code-review: This is used by any gem5 user to review patches. When reviewing
|
||||
a patch you can give it a score of -2 to +2 with the following semantics.
|
||||
* -2: This blocks the patch. You believe that this patch should never be
|
||||
committed. This label should be very rarely used.
|
||||
* -1: You would prefer this is not merged as is
|
||||
* 0: No score
|
||||
* +1: This patch seems good, but you aren't 100% confident that it should be
|
||||
pushed.
|
||||
* +2: This is a good patch and should be pushed as is.
|
||||
* Maintainer: Currently only PMC members are maintainers. At least one
|
||||
maintainer must review your patch and give it a +1 before it can be merged.
|
||||
* Verified: This is automatically generated from the continuous integrated
|
||||
(CI) tests. Each patch must receive at least a +1 from the CI tests before
|
||||
the patch can be merged. The patch will receive a +1 if gem5 builds and
|
||||
runs, and it will receive a +2 if the stats match.
|
||||
* Style-Check: This is automatically generated and tests the patch against the
|
||||
gem5 code style (http://www.gem5.org/Coding_Style). The patch must receive a
|
||||
+1 from the style checker to be pushed.
|
||||
|
||||
Note: Whenever the patch creator updates the patch all reviewers must re-review
|
||||
the patch. There is no longer a "Fix it, then Ship It" option.
|
||||
|
||||
Once you have received reviews for your patch, you will likely need to make
|
||||
changes. To do this, you should update the original git changeset. Then, you
|
||||
can simply push the changeset again to the same Gerrit branch to update the
|
||||
review request.
|
||||
|
||||
> git push origin HEAD:refs/for/master
|
||||
|
||||
Note: If you have posted a patch and don't receive any reviews, you may need to
|
||||
prod the reviewers. You can do this by adding a reply to your changeset review
|
||||
on gerrit. It is expected that at least the maintainer will supply a review for
|
||||
your patch.
|
||||
|
||||
Committing changes
|
||||
==================
|
||||
|
||||
Each patch must meet the following criteria to be merged:
|
||||
* At least one review with +2
|
||||
* At least one maintainer with +1
|
||||
* At least +1 from the CI tests (gem5 must build and run)
|
||||
* At least +1 from the style checker
|
||||
|
||||
Once a patch meets the above criteria, the submitter of the patch will be able
|
||||
to merge the patch by pressing the "Submit" button on Gerrit. When the patch is
|
||||
submitted, it is merged into the public gem5 branch.
|
1
COPYING
1
COPYING
|
@ -45,3 +45,4 @@ Copyright (c) 1994-1996 Carnegie-Mellon University.
|
|||
Copyright (c) 1993-1994 Christopher G. Demetriou
|
||||
Copyright (c) 1997-2002 Makoto Matsumoto and Takuji Nishimura
|
||||
Copyright (c) 1998,2001 Manuel Bouyer.
|
||||
Copyright (c) 2016-2017 Google Inc.
|
||||
|
|
96
SConstruct
96
SConstruct
|
@ -268,10 +268,17 @@ against the gem5 style rules on %s.
|
|||
This script will now install the hook in your %s.
|
||||
Press enter to continue, or ctrl-c to abort: """
|
||||
|
||||
mercurial_style_message = style_message % ("hg commit and qrefresh commands",
|
||||
".hg/hgrc file")
|
||||
git_style_message = style_message % ("'git commit'",
|
||||
".git/hooks/ directory")
|
||||
mercurial_style_message = """
|
||||
You're missing the gem5 style hook, which automatically checks your code
|
||||
against the gem5 style rules on hg commit and qrefresh commands.
|
||||
This script will now install the hook in your .hg/hgrc file.
|
||||
Press enter to continue, or ctrl-c to abort: """
|
||||
|
||||
git_style_message = """
|
||||
You're missing the gem5 style or commit message hook. These hooks help
|
||||
to ensure that your code follows gem5's style rules on git commit.
|
||||
This script will now install the hook in your .git/hooks/ directory.
|
||||
Press enter to continue, or ctrl-c to abort: """
|
||||
|
||||
mercurial_style_upgrade_message = """
|
||||
Your Mercurial style hooks are not up-to-date. This script will now
|
||||
|
@ -376,10 +383,43 @@ def install_git_style_hooks():
|
|||
return
|
||||
|
||||
git_hooks = gitdir.Dir("hooks")
|
||||
git_pre_commit_hook = git_hooks.File("pre-commit")
|
||||
git_style_script = File("util/git-pre-commit.py")
|
||||
def hook_exists(hook_name):
|
||||
hook = git_hooks.File(hook_name)
|
||||
return hook.exists()
|
||||
|
||||
if git_pre_commit_hook.exists():
|
||||
def hook_install(hook_name, script):
|
||||
hook = git_hooks.File(hook_name)
|
||||
if hook.exists():
|
||||
print "Warning: Can't install %s, hook already exists." % hook_name
|
||||
return
|
||||
|
||||
if hook.islink():
|
||||
print "Warning: Removing broken symlink for hook %s." % hook_name
|
||||
os.unlink(hook.get_abspath())
|
||||
|
||||
if not git_hooks.exists():
|
||||
mkdir(git_hooks.get_abspath())
|
||||
git_hooks.clear()
|
||||
|
||||
abs_symlink_hooks = git_hooks.islink() and \
|
||||
os.path.isabs(os.readlink(git_hooks.get_abspath()))
|
||||
|
||||
# Use a relative symlink if the hooks live in the source directory,
|
||||
# and the hooks directory is not a symlink to an absolute path.
|
||||
if hook.is_under(main.root) and not abs_symlink_hooks:
|
||||
script_path = os.path.relpath(
|
||||
os.path.realpath(script.get_abspath()),
|
||||
os.path.realpath(hook.Dir(".").get_abspath()))
|
||||
else:
|
||||
script_path = script.get_abspath()
|
||||
|
||||
try:
|
||||
os.symlink(script_path, hook.get_abspath())
|
||||
except:
|
||||
print "Error updating git %s hook" % hook_name
|
||||
raise
|
||||
|
||||
if hook_exists("pre-commit") and hook_exists("commit-msg"):
|
||||
return
|
||||
|
||||
print git_style_message,
|
||||
|
@ -389,22 +429,11 @@ def install_git_style_hooks():
|
|||
print "Input exception, exiting scons.\n"
|
||||
sys.exit(1)
|
||||
|
||||
if not git_hooks.exists():
|
||||
mkdir(git_hooks.get_abspath())
|
||||
git_style_script = File("util/git-pre-commit.py")
|
||||
git_msg_script = File("ext/git-commit-msg")
|
||||
|
||||
# Use a relative symlink if the hooks live in the source directory
|
||||
if git_pre_commit_hook.is_under(main.root):
|
||||
script_path = os.path.relpath(
|
||||
git_style_script.get_abspath(),
|
||||
git_pre_commit_hook.Dir(".").get_abspath())
|
||||
else:
|
||||
script_path = git_style_script.get_abspath()
|
||||
|
||||
try:
|
||||
os.symlink(script_path, git_pre_commit_hook.get_abspath())
|
||||
except:
|
||||
print "Error updating git pre-commit hook"
|
||||
raise
|
||||
hook_install("pre-commit", git_style_script)
|
||||
hook_install("commit-msg", git_msg_script)
|
||||
|
||||
# Try to wire up git to the style hooks
|
||||
if not ignore_style and main.root.Entry(".git").exists():
|
||||
|
@ -655,6 +684,9 @@ if main['GCC'] or main['CLANG']:
|
|||
'-Wno-sign-compare', '-Wno-unused-parameter'])
|
||||
# We always compile using C++11
|
||||
main.Append(CXXFLAGS=['-std=c++11'])
|
||||
if sys.platform.startswith('freebsd'):
|
||||
main.Append(CCFLAGS=['-I/usr/local/include'])
|
||||
main.Append(CXXFLAGS=['-I/usr/local/include'])
|
||||
else:
|
||||
print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
|
||||
print "Don't know what compiler options to use for your compiler."
|
||||
|
@ -690,7 +722,8 @@ if main['GCC']:
|
|||
# to avoid performance penalties on certain AMD chips. Older
|
||||
# assemblers detect this as an error, "Error: expecting string
|
||||
# instruction after `rep'"
|
||||
as_version_raw = readCommand([main['AS'], '-v', '/dev/null'],
|
||||
as_version_raw = readCommand([main['AS'], '-v', '/dev/null',
|
||||
'-o', '/dev/null'],
|
||||
exception=False).split()
|
||||
|
||||
# version strings may contain extra distro-specific
|
||||
|
@ -771,6 +804,10 @@ elif main['CLANG']:
|
|||
main.Append(CXXFLAGS=['-stdlib=libc++'])
|
||||
main.Append(LIBS=['c++'])
|
||||
|
||||
# On FreeBSD we need libthr.
|
||||
if sys.platform.startswith('freebsd'):
|
||||
main.Append(LIBS=['thr'])
|
||||
|
||||
else:
|
||||
print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
|
||||
print "Don't know what compiler options to use for your compiler."
|
||||
|
@ -884,8 +921,12 @@ main.Append(SWIGFLAGS=swig_flags)
|
|||
# Check for 'timeout' from GNU coreutils. If present, regressions will
|
||||
# be run with a time limit. We require version 8.13 since we rely on
|
||||
# support for the '--foreground' option.
|
||||
timeout_lines = readCommand(['timeout', '--version'],
|
||||
exception='').splitlines()
|
||||
if sys.platform.startswith('freebsd'):
|
||||
timeout_lines = readCommand(['gtimeout', '--version'],
|
||||
exception='').splitlines()
|
||||
else:
|
||||
timeout_lines = readCommand(['timeout', '--version'],
|
||||
exception='').splitlines()
|
||||
# Get the first line and tokenize it
|
||||
timeout_version = timeout_lines[0].split() if timeout_lines else []
|
||||
main['TIMEOUT'] = timeout_version and \
|
||||
|
@ -1083,6 +1124,11 @@ backtrace_impls = [ "none" ]
|
|||
if conf.CheckLibWithHeader(None, 'execinfo.h', 'C',
|
||||
'backtrace_symbols_fd((void*)0, 0, 0);'):
|
||||
backtrace_impls.append("glibc")
|
||||
elif conf.CheckLibWithHeader('execinfo', 'execinfo.h', 'C',
|
||||
'backtrace_symbols_fd((void*)0, 0, 0);'):
|
||||
# NetBSD and FreeBSD need libexecinfo.
|
||||
backtrace_impls.append("glibc")
|
||||
main.Append(LIBS=['execinfo'])
|
||||
|
||||
if backtrace_impls[-1] == "none":
|
||||
default_backtrace_impl = "none"
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
# serial links, the main internal crossbar, and an external hmc controller.
|
||||
#
|
||||
# - VAULT CONTROLLERS:
|
||||
# Instances of the HMC_2500_x32 class with their functionality specified in
|
||||
# Instances of the HMC_2500_1x32 class with their functionality specified in
|
||||
# dram_ctrl.cc
|
||||
#
|
||||
# - THE MAIN XBAR:
|
||||
|
|
|
@ -152,7 +152,7 @@ def config_mem(options, system):
|
|||
them.
|
||||
"""
|
||||
|
||||
if ( options.mem_type == "HMC_2500_x32"):
|
||||
if ( options.mem_type == "HMC_2500_1x32"):
|
||||
HMChost = HMC.config_host_hmc(options, system)
|
||||
HMC.config_hmc(options, system, HMChost.hmc_host)
|
||||
subsystem = system.hmc_dev
|
||||
|
@ -163,7 +163,7 @@ def config_mem(options, system):
|
|||
|
||||
if options.tlm_memory:
|
||||
system.external_memory = m5.objects.ExternalSlave(
|
||||
port_type="tlm",
|
||||
port_type="tlm_slave",
|
||||
port_data=options.tlm_memory,
|
||||
port=system.membus.master,
|
||||
addr_ranges=system.mem_ranges)
|
||||
|
@ -223,7 +223,7 @@ def config_mem(options, system):
|
|||
|
||||
# Connect the controllers to the membus
|
||||
for i in xrange(len(subsystem.mem_ctrls)):
|
||||
if (options.mem_type == "HMC_2500_x32"):
|
||||
if (options.mem_type == "HMC_2500_1x32"):
|
||||
subsystem.mem_ctrls[i].port = xbar[i/4].master
|
||||
else:
|
||||
subsystem.mem_ctrls[i].port = xbar.master
|
||||
|
|
|
@ -77,7 +77,7 @@ def addNoISAOptions(parser):
|
|||
parser.add_option("--list-mem-types",
|
||||
action="callback", callback=_listMemTypes,
|
||||
help="List available memory types")
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_x64",
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_8x8",
|
||||
choices=MemConfig.mem_names(),
|
||||
help = "type of memory to use")
|
||||
parser.add_option("--mem-channels", type="int", default=1,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# Copyright (c) 2012, 2015 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# Copyright (c) 2017, Centre National de la Recherche Scientifique (CNRS)
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
|
@ -34,10 +36,12 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Andreas Sandberg
|
||||
# Pierre-Yves Peneau
|
||||
|
||||
import m5.objects
|
||||
import inspect
|
||||
import sys
|
||||
from m5.util import fatal
|
||||
from textwrap import TextWrapper
|
||||
|
||||
# Dictionary of mapping names of real CPU models to classes.
|
||||
|
@ -74,8 +78,7 @@ def get(name):
|
|||
try:
|
||||
return _platform_classes[real_name]
|
||||
except KeyError:
|
||||
print "%s is not a valid Platform model." % (name,)
|
||||
sys.exit(1)
|
||||
fatal("%s is not a valid Platform model." % (name,))
|
||||
|
||||
def print_platform_list():
|
||||
"""Print a list of available Platform classes including their aliases."""
|
||||
|
|
|
@ -131,8 +131,8 @@ class Benchmark(object):
|
|||
|
||||
func(self, isa, os)
|
||||
|
||||
def makeLiveProcessArgs(self, **kwargs):
|
||||
# set up default args for LiveProcess object
|
||||
def makeProcessArgs(self, **kwargs):
|
||||
# set up default args for Process object
|
||||
process_args = {}
|
||||
process_args['cmd'] = [ self.name ] + self.args
|
||||
process_args['executable'] = self.executable
|
||||
|
@ -147,11 +147,11 @@ class Benchmark(object):
|
|||
|
||||
return process_args
|
||||
|
||||
def makeLiveProcess(self, **kwargs):
|
||||
process_args = self.makeLiveProcessArgs(**kwargs)
|
||||
def makeProcess(self, **kwargs):
|
||||
process_args = self.makeProcessArgs(**kwargs)
|
||||
|
||||
# figure out working directory: use m5's outdir unless
|
||||
# overridden by LiveProcess's cwd param
|
||||
# overridden by Process's cwd param
|
||||
cwd = process_args.get('cwd')
|
||||
|
||||
if not cwd:
|
||||
|
@ -163,9 +163,9 @@ class Benchmark(object):
|
|||
# copy input files to working directory
|
||||
for d in self.inputs_dir:
|
||||
copyfiles(d, cwd)
|
||||
# generate LiveProcess object
|
||||
from m5.objects import LiveProcess
|
||||
return LiveProcess(**process_args)
|
||||
# generate Process object
|
||||
from m5.objects import Process
|
||||
return Process(**process_args)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -750,5 +750,5 @@ if __name__ == '__main__':
|
|||
print 'class: %s' % bench.__name__
|
||||
x = bench('alpha', 'tru64', input_set)
|
||||
print '%s: %s' % (x, input_set)
|
||||
pprint(x.makeLiveProcessArgs())
|
||||
pprint(x.makeProcessArgs())
|
||||
print
|
||||
|
|
|
@ -63,13 +63,17 @@ def build_switch(options):
|
|||
link.int0 = switch.interface[i]
|
||||
|
||||
return switch
|
||||
# Add options
|
||||
parser = optparse.OptionParser()
|
||||
Options.addCommonOptions(parser)
|
||||
Options.addFSOptions(parser)
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
system = build_switch(options)
|
||||
root = Root(full_system = True, system = system)
|
||||
Simulation.run(options, root, None, None)
|
||||
def main():
|
||||
# Add options
|
||||
parser = optparse.OptionParser()
|
||||
Options.addCommonOptions(parser)
|
||||
Options.addFSOptions(parser)
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
system = build_switch(options)
|
||||
root = Root(full_system = True, system = system)
|
||||
Simulation.run(options, root, None, None)
|
||||
|
||||
if __name__ == "__m5_main__":
|
||||
main()
|
||||
|
|
|
@ -80,7 +80,7 @@ except:
|
|||
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_x64",
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_8x8",
|
||||
choices=MemConfig.mem_names(),
|
||||
help = "type of memory to use")
|
||||
parser.add_option("--mem-size", action="store", type="string",
|
||||
|
@ -252,6 +252,7 @@ system.tgen = TrafficGen(config_file = cfg_file_name,
|
|||
|
||||
# add a communication monitor
|
||||
system.monitor = CommMonitor()
|
||||
system.monitor.footprint = MemFootprintProbe()
|
||||
|
||||
# connect the traffic generator to the system
|
||||
system.tgen.port = system.monitor.slave
|
||||
|
|
|
@ -53,8 +53,8 @@ from common import MemConfig
|
|||
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
# Use a single-channel DDR3-1600 x64 by default
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_x64",
|
||||
# Use a single-channel DDR3-1600 x64 (8x8 topology) by default
|
||||
parser.add_option("--mem-type", type="choice", default="DDR3_1600_8x8",
|
||||
choices=MemConfig.mem_names(),
|
||||
help = "type of memory to use")
|
||||
|
||||
|
|
|
@ -392,9 +392,9 @@ else:
|
|||
# OpenCL driver
|
||||
driver = ClDriver(filename="hsa", codefile=kernel_files)
|
||||
for cpu in cpu_list:
|
||||
cpu.workload = LiveProcess(executable = executable,
|
||||
cmd = [options.cmd] + options.options.split(),
|
||||
drivers = [driver])
|
||||
cpu.workload = Process(executable = executable,
|
||||
cmd = [options.cmd] + options.options.split(),
|
||||
drivers = [driver])
|
||||
for cp in cp_list:
|
||||
cp.workload = host_cpu.workload
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016 ARM Limited
|
||||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -44,6 +44,8 @@ m5.util.addToPath('../../')
|
|||
from common.Caches import *
|
||||
from common import CpuConfig
|
||||
|
||||
have_kvm = "kvm" in CpuConfig.cpu_names()
|
||||
|
||||
class L1I(L1_ICache):
|
||||
tag_latency = 1
|
||||
data_latency = 1
|
||||
|
@ -170,6 +172,14 @@ class AtomicCluster(CpuCluster):
|
|||
def addL1(self):
|
||||
pass
|
||||
|
||||
class KvmCluster(CpuCluster):
|
||||
def __init__(self, system, num_cpus, cpu_clock, cpu_voltage="1.0V"):
|
||||
cpu_config = [ CpuConfig.get("kvm"), None, None, None, None ]
|
||||
super(KvmCluster, self).__init__(system, num_cpus, cpu_clock,
|
||||
cpu_voltage, *cpu_config)
|
||||
def addL1(self):
|
||||
pass
|
||||
|
||||
|
||||
class SimpleSystem(LinuxArmSystem):
|
||||
cache_line_size = 64
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
# to a hardware implementation of the functionality of the software
|
||||
# licensed hereunder. You may use the software subject to the license
|
||||
# terms below provided that you ensure that this notice is replicated
|
||||
# unmodified and in its entirety in all distributions of the software,
|
||||
# modified or unmodified, in source code or in binary form.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Gabor Dozsa
|
||||
|
||||
# This configuration file extends the example ARM big.LITTLE(tm)
|
||||
# configuration to enabe dist-gem5 siulations of big.LITTLE systems.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
|
||||
import fs_bigLITTLE as bL
|
||||
m5.util.addToPath("../../dist")
|
||||
import sw
|
||||
|
||||
|
||||
def addOptions(parser):
|
||||
# Options for distributed simulation (i.e. dist-gem5)
|
||||
parser.add_argument("--dist", action="store_true", help="Distributed gem5"\
|
||||
" simulation.")
|
||||
parser.add_argument("--is-switch", action="store_true",
|
||||
help="Select the network switch simulator process for"\
|
||||
" a distributed gem5 run.")
|
||||
parser.add_argument("--dist-rank", default=0, action="store", type=int,
|
||||
help="Rank of this system within the dist gem5 run.")
|
||||
parser.add_argument("--dist-size", default=0, action="store", type=int,
|
||||
help="Number of gem5 processes within the dist gem5"\
|
||||
" run.")
|
||||
parser.add_argument("--dist-server-name",
|
||||
default="127.0.0.1",
|
||||
action="store", type=str,
|
||||
help="Name of the message server host\nDEFAULT:"\
|
||||
" localhost")
|
||||
parser.add_argument("--dist-server-port",
|
||||
default=2200,
|
||||
action="store", type=int,
|
||||
help="Message server listen port\nDEFAULT: 2200")
|
||||
parser.add_argument("--dist-sync-repeat",
|
||||
default="0us",
|
||||
action="store", type=str,
|
||||
help="Repeat interval for synchronisation barriers"\
|
||||
" among dist-gem5 processes\nDEFAULT:"\
|
||||
" --ethernet-linkdelay")
|
||||
parser.add_argument("--dist-sync-start",
|
||||
default="1000000000000t",
|
||||
action="store", type=str,
|
||||
help="Time to schedule the first dist synchronisation"\
|
||||
" barrier\nDEFAULT:1000000000000t")
|
||||
parser.add_argument("--ethernet-linkspeed", default="10Gbps",
|
||||
action="store", type=str,
|
||||
help="Link speed in bps\nDEFAULT: 10Gbps")
|
||||
parser.add_argument("--ethernet-linkdelay", default="10us",
|
||||
action="store", type=str,
|
||||
help="Link delay in seconds\nDEFAULT: 10us")
|
||||
parser.add_argument("--etherdump", action="store", type=str, default="",
|
||||
help="Specify the filename to dump a pcap capture of"\
|
||||
" the ethernet traffic")
|
||||
# Used by util/dist/gem5-dist.sh
|
||||
parser.add_argument("--checkpoint-dir", type=str,
|
||||
default=m5.options.outdir,
|
||||
help="Directory to save/read checkpoints")
|
||||
|
||||
|
||||
def addEthernet(system, options):
|
||||
# create NIC
|
||||
dev = IGbE_e1000()
|
||||
system.attach_pci(dev)
|
||||
system.ethernet = dev
|
||||
|
||||
# create distributed ethernet link
|
||||
system.etherlink = DistEtherLink(speed = options.ethernet_linkspeed,
|
||||
delay = options.ethernet_linkdelay,
|
||||
dist_rank = options.dist_rank,
|
||||
dist_size = options.dist_size,
|
||||
server_name = options.dist_server_name,
|
||||
server_port = options.dist_server_port,
|
||||
sync_start = options.dist_sync_start,
|
||||
sync_repeat = options.dist_sync_repeat)
|
||||
system.etherlink.int0 = Parent.system.ethernet.interface
|
||||
if options.etherdump:
|
||||
system.etherdump = EtherDump(file=options.etherdump)
|
||||
system.etherlink.dump = system.etherdump
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generic ARM big.LITTLE configuration with "\
|
||||
"dist-gem5 support")
|
||||
bL.addOptions(parser)
|
||||
addOptions(parser)
|
||||
options = parser.parse_args()
|
||||
|
||||
if options.is_switch:
|
||||
root = Root(full_system = True,
|
||||
system = sw.build_switch(options))
|
||||
else:
|
||||
root = bL.build(options)
|
||||
addEthernet(root.system, options)
|
||||
|
||||
bL.instantiate(options, checkpoint_dir=options.checkpoint_dir)
|
||||
bL.run(options.checkpoint_dir)
|
||||
|
||||
|
||||
if __name__ == "__m5_main__":
|
||||
main()
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016 ARM Limited
|
||||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -44,6 +44,7 @@ import argparse
|
|||
import os
|
||||
import sys
|
||||
import m5
|
||||
import m5.util
|
||||
from m5.objects import *
|
||||
|
||||
m5.util.addToPath("../../")
|
||||
|
@ -52,6 +53,7 @@ from common import SysPaths
|
|||
from common import CpuConfig
|
||||
|
||||
import devices
|
||||
from devices import AtomicCluster, KvmCluster
|
||||
|
||||
|
||||
default_dtb = 'armv8_gem5_v1_big_little_2_2.dtb'
|
||||
|
@ -61,6 +63,21 @@ default_rcs = 'bootscript.rcS'
|
|||
|
||||
default_mem_size= "2GB"
|
||||
|
||||
def _to_ticks(value):
|
||||
"""Helper function to convert a latency from string format to Ticks"""
|
||||
|
||||
return m5.ticks.fromSeconds(m5.util.convert.anyToLatency(value))
|
||||
|
||||
def _using_pdes(root):
|
||||
"""Determine if the simulator is using multiple parallel event queues"""
|
||||
|
||||
for obj in root.descendants():
|
||||
if not m5.proxy.isproxy(obj.eventq_index) and \
|
||||
obj.eventq_index != root.eventq_index:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class BigCluster(devices.CpuCluster):
|
||||
def __init__(self, system, num_cpus, cpu_clock,
|
||||
|
@ -107,11 +124,17 @@ def createSystem(caches, kernel, bootscript, disks=[]):
|
|||
|
||||
return sys
|
||||
|
||||
cpu_types = {
|
||||
"atomic" : (AtomicCluster, AtomicCluster),
|
||||
"timing" : (BigCluster, LittleCluster),
|
||||
}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generic ARM big.LITTLE configuration")
|
||||
# Only add the KVM CPU if it has been compiled into gem5
|
||||
if devices.have_kvm:
|
||||
cpu_types["kvm"] = (KvmCluster, KvmCluster)
|
||||
|
||||
|
||||
def addOptions(parser):
|
||||
parser.add_argument("--restore-from", type=str, default=None,
|
||||
help="Restore from checkpoint")
|
||||
parser.add_argument("--dtb", type=str, default=default_dtb,
|
||||
|
@ -122,8 +145,9 @@ def main():
|
|||
help="Disks to instantiate")
|
||||
parser.add_argument("--bootscript", type=str, default=default_rcs,
|
||||
help="Linux bootscript")
|
||||
parser.add_argument("--atomic", action="store_true", default=False,
|
||||
help="Use atomic CPUs")
|
||||
parser.add_argument("--cpu-type", type=str, choices=cpu_types.keys(),
|
||||
default="timing",
|
||||
help="CPU simulation mode. Default: %(default)s")
|
||||
parser.add_argument("--kernel-init", type=str, default="/sbin/init",
|
||||
help="Override init")
|
||||
parser.add_argument("--big-cpus", type=int, default=1,
|
||||
|
@ -138,11 +162,14 @@ def main():
|
|||
help="Big CPU clock frequency")
|
||||
parser.add_argument("--little-cpu-clock", type=str, default="1GHz",
|
||||
help="Little CPU clock frequency")
|
||||
parser.add_argument("--sim-quantum", type=str, default="1ms",
|
||||
help="Simulation quantum for parallel simulation. " \
|
||||
"Default: %(default)s")
|
||||
return parser
|
||||
|
||||
def build(options):
|
||||
m5.ticks.fixGlobalFrequency()
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
kernel_cmd = [
|
||||
"earlyprintk=pl011,0x1c090000",
|
||||
"console=ttyAMA0",
|
||||
|
@ -167,35 +194,31 @@ def main():
|
|||
root.system = system
|
||||
system.boot_osflags = " ".join(kernel_cmd)
|
||||
|
||||
AtomicCluster = devices.AtomicCluster
|
||||
|
||||
if options.big_cpus + options.little_cpus == 0:
|
||||
m5.util.panic("Empty CPU clusters")
|
||||
|
||||
big_model, little_model = cpu_types[options.cpu_type]
|
||||
|
||||
all_cpus = []
|
||||
# big cluster
|
||||
if options.big_cpus > 0:
|
||||
if options.atomic:
|
||||
system.bigCluster = AtomicCluster(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
else:
|
||||
system.bigCluster = BigCluster(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
mem_mode = system.bigCluster.memoryMode()
|
||||
system.bigCluster = big_model(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
system.mem_mode = system.bigCluster.memoryMode()
|
||||
all_cpus += system.bigCluster.cpus
|
||||
|
||||
# little cluster
|
||||
if options.little_cpus > 0:
|
||||
if options.atomic:
|
||||
system.littleCluster = AtomicCluster(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
system.littleCluster = little_model(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
system.mem_mode = system.littleCluster.memoryMode()
|
||||
all_cpus += system.littleCluster.cpus
|
||||
|
||||
else:
|
||||
system.littleCluster = LittleCluster(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
mem_mode = system.littleCluster.memoryMode()
|
||||
# Figure out the memory mode
|
||||
if options.big_cpus > 0 and options.little_cpus > 0 and \
|
||||
system.littleCluster.memoryMode() != system.littleCluster.memoryMode():
|
||||
m5.util.panic("Memory mode missmatch among CPU clusters")
|
||||
|
||||
if options.big_cpus > 0 and options.little_cpus > 0:
|
||||
if system.bigCluster.memoryMode() != system.littleCluster.memoryMode():
|
||||
m5.util.panic("Memory mode missmatch among CPU clusters")
|
||||
system.mem_mode = mem_mode
|
||||
|
||||
# create caches
|
||||
system.addCaches(options.caches, options.last_cache_level)
|
||||
|
@ -205,23 +228,65 @@ def main():
|
|||
if options.little_cpus > 0 and system.littleCluster.requireCaches():
|
||||
m5.util.panic("Little CPU model requires caches")
|
||||
|
||||
# Create a KVM VM and do KVM-specific configuration
|
||||
if issubclass(big_model, KvmCluster):
|
||||
_build_kvm(system, all_cpus)
|
||||
|
||||
# Linux device tree
|
||||
system.dtb_filename = SysPaths.binary(options.dtb)
|
||||
|
||||
return root
|
||||
|
||||
def _build_kvm(system, cpus):
|
||||
system.kvm_vm = KvmVM()
|
||||
|
||||
# Assign KVM CPUs to their own event queues / threads. This
|
||||
# has to be done after creating caches and other child objects
|
||||
# since these mustn't inherit the CPU event queue.
|
||||
if len(cpus) > 1:
|
||||
device_eq = 0
|
||||
first_cpu_eq = 1
|
||||
for idx, cpu in enumerate(cpus):
|
||||
# Child objects usually inherit the parent's event
|
||||
# queue. Override that and use the same event queue for
|
||||
# all devices.
|
||||
for obj in cpu.descendants():
|
||||
obj.eventq_index = device_eq
|
||||
cpu.eventq_index = first_cpu_eq + idx
|
||||
|
||||
|
||||
|
||||
def instantiate(options, checkpoint_dir=None):
|
||||
# Setup the simulation quantum if we are running in PDES-mode
|
||||
# (e.g., when using KVM)
|
||||
root = Root.getInstance()
|
||||
if root and _using_pdes(root):
|
||||
m5.util.inform("Running in PDES mode with a %s simulation quantum.",
|
||||
options.sim_quantum)
|
||||
root.sim_quantum = _to_ticks(options.sim_quantum)
|
||||
|
||||
# Get and load from the chkpt or simpoint checkpoint
|
||||
if options.restore_from is not None:
|
||||
m5.instantiate(options.restore_from)
|
||||
if options.restore_from:
|
||||
if checkpoint_dir and not os.path.isabs(options.restore_from):
|
||||
cpt = os.path.join(checkpoint_dir, options.restore_from)
|
||||
else:
|
||||
cpt = options.restore_from
|
||||
|
||||
m5.util.inform("Restoring from checkpoint %s", cpt)
|
||||
m5.instantiate(cpt)
|
||||
else:
|
||||
m5.instantiate()
|
||||
|
||||
|
||||
def run(checkpoint_dir=m5.options.outdir):
|
||||
# start simulation (and drop checkpoints when requested)
|
||||
while True:
|
||||
event = m5.simulate()
|
||||
exit_msg = event.getCause()
|
||||
if exit_msg == "checkpoint":
|
||||
print "Dropping checkpoint at tick %d" % m5.curTick()
|
||||
cpt_dir = os.path.join(m5.options.outdir, "cpt.%d" % m5.curTick())
|
||||
m5.checkpoint(os.path.join(cpt_dir))
|
||||
cpt_dir = os.path.join(checkpoint_dir, "cpt.%d" % m5.curTick())
|
||||
m5.checkpoint(cpt_dir)
|
||||
print "Checkpoint done."
|
||||
else:
|
||||
print exit_msg, " @ ", m5.curTick()
|
||||
|
@ -230,5 +295,15 @@ def main():
|
|||
sys.exit(event.getCode())
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generic ARM big.LITTLE configuration")
|
||||
addOptions(parser)
|
||||
options = parser.parse_args()
|
||||
root = build(options)
|
||||
instantiate(options)
|
||||
run()
|
||||
|
||||
|
||||
if __name__ == "__m5_main__":
|
||||
main()
|
||||
|
|
|
@ -143,7 +143,7 @@ def build_test_system(np):
|
|||
for i in xrange(np)]
|
||||
|
||||
if is_kvm_cpu(TestCPUClass) or is_kvm_cpu(FutureClass):
|
||||
test_sys.vm = KvmVM()
|
||||
test_sys.kvm_vm = KvmVM()
|
||||
|
||||
if options.ruby:
|
||||
# Check for timing mode because ruby does not support atomic accesses
|
||||
|
@ -280,7 +280,7 @@ def build_drive_system(np):
|
|||
drive_sys.kernel = binary(options.kernel)
|
||||
|
||||
if is_kvm_cpu(DriveCPUClass):
|
||||
drive_sys.vm = KvmVM()
|
||||
drive_sys.kvm_vm = KvmVM()
|
||||
|
||||
drive_sys.iobridge = Bridge(delay='50ns',
|
||||
ranges = drive_sys.mem_ranges)
|
||||
|
|
|
@ -13,8 +13,8 @@ from common import HMC
|
|||
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
# Use a HMC_2500_x32 by default
|
||||
parser.add_option("--mem-type", type = "choice", default = "HMC_2500_x32",
|
||||
# Use a HMC_2500_1x32 (1 channel, 32-bits wide) by default
|
||||
parser.add_option("--mem-type", type = "choice", default = "HMC_2500_1x32",
|
||||
choices = MemConfig.mem_names(),
|
||||
help = "type of memory to use")
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@ cfg_file.close()
|
|||
proto_tester = TrafficGen(config_file = cfg_file_name)
|
||||
|
||||
# Set up the system along with a DRAM controller
|
||||
system = System(physmem = DDR3_1600_x64())
|
||||
system = System(physmem = DDR3_1600_8x8())
|
||||
|
||||
system.voltage_domain = VoltageDomain(voltage = '1V')
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ def get_processes(options):
|
|||
|
||||
idx = 0
|
||||
for wrkld in workloads:
|
||||
process = LiveProcess()
|
||||
process = Process()
|
||||
process.executable = wrkld
|
||||
process.cwd = os.getcwd()
|
||||
|
||||
|
@ -154,7 +154,7 @@ if options.bench:
|
|||
else:
|
||||
exec("workload = %s(buildEnv['TARGET_ISA', 'linux', '%s')" % (
|
||||
app, options.spec_input))
|
||||
multiprocesses.append(workload.makeLiveProcess())
|
||||
multiprocesses.append(workload.makeProcess())
|
||||
except:
|
||||
print >>sys.stderr, "Unable to find workload for %s: %s" % (
|
||||
buildEnv['TARGET_ISA'], app)
|
||||
|
@ -209,7 +209,7 @@ for cpu in system.cpu:
|
|||
|
||||
if is_kvm_cpu(CPUClass) or is_kvm_cpu(FutureClass):
|
||||
if buildEnv['TARGET_ISA'] == 'x86':
|
||||
system.vm = KvmVM()
|
||||
system.kvm_vm = KvmVM()
|
||||
for process in multiprocesses:
|
||||
process.useArchPT = True
|
||||
process.kvmInSE = True
|
||||
|
|
|
@ -75,7 +75,7 @@ if m5.defines.buildEnv['TARGET_ISA'] == "x86":
|
|||
system.cpu.interrupts[0].int_slave = system.membus.master
|
||||
|
||||
# Create a DDR3 memory controller and connect it to the membus
|
||||
system.mem_ctrl = DDR3_1600_x64()
|
||||
system.mem_ctrl = DDR3_1600_8x8()
|
||||
system.mem_ctrl.range = system.mem_ranges[0]
|
||||
system.mem_ctrl.port = system.membus.master
|
||||
|
||||
|
@ -89,7 +89,7 @@ isa = str(m5.defines.buildEnv['TARGET_ISA']).lower()
|
|||
binary = 'tests/test-progs/hello/bin/' + isa + '/linux/hello'
|
||||
|
||||
# Create a process for a simple "Hello World" application
|
||||
process = LiveProcess()
|
||||
process = Process()
|
||||
# Set the command
|
||||
# cmd is a list which begins with the executable (like argv)
|
||||
process.cmd = [binary]
|
||||
|
|
|
@ -128,12 +128,12 @@ if m5.defines.buildEnv['TARGET_ISA'] == "x86":
|
|||
system.system_port = system.membus.slave
|
||||
|
||||
# Create a DDR3 memory controller
|
||||
system.mem_ctrl = DDR3_1600_x64()
|
||||
system.mem_ctrl = DDR3_1600_8x8()
|
||||
system.mem_ctrl.range = system.mem_ranges[0]
|
||||
system.mem_ctrl.port = system.membus.master
|
||||
|
||||
# Create a process for a simple "Hello World" application
|
||||
process = LiveProcess()
|
||||
process = Process()
|
||||
# Set the command
|
||||
# cmd is a list which begins with the executable (like argv)
|
||||
process.cmd = [binary]
|
||||
|
|
|
@ -76,56 +76,56 @@ if args:
|
|||
# --------------------
|
||||
# Define Splash2 Benchmarks
|
||||
# ====================
|
||||
class Cholesky(LiveProcess):
|
||||
class Cholesky(Process):
|
||||
executable = options.rootdir + '/kernels/cholesky/CHOLESKY'
|
||||
cmd = 'CHOLESKY -p' + str(options.numcpus) + ' '\
|
||||
+ options.rootdir + '/kernels/cholesky/inputs/tk23.O'
|
||||
|
||||
class FFT(LiveProcess):
|
||||
class FFT(Process):
|
||||
executable = options.rootdir + 'kernels/fft/FFT'
|
||||
cmd = 'FFT -p' + str(options.numcpus) + ' -m18'
|
||||
|
||||
class LU_contig(LiveProcess):
|
||||
class LU_contig(Process):
|
||||
executable = options.rootdir + 'kernels/lu/contiguous_blocks/LU'
|
||||
cmd = 'LU -p' + str(options.numcpus)
|
||||
|
||||
class LU_noncontig(LiveProcess):
|
||||
class LU_noncontig(Process):
|
||||
executable = options.rootdir + 'kernels/lu/non_contiguous_blocks/LU'
|
||||
cmd = 'LU -p' + str(options.numcpus)
|
||||
|
||||
class Radix(LiveProcess):
|
||||
class Radix(Process):
|
||||
executable = options.rootdir + 'kernels/radix/RADIX'
|
||||
cmd = 'RADIX -n524288 -p' + str(options.numcpus)
|
||||
|
||||
class Barnes(LiveProcess):
|
||||
class Barnes(Process):
|
||||
executable = options.rootdir + 'apps/barnes/BARNES'
|
||||
cmd = 'BARNES'
|
||||
input = options.rootdir + 'apps/barnes/input.p' + str(options.numcpus)
|
||||
|
||||
class FMM(LiveProcess):
|
||||
class FMM(Process):
|
||||
executable = options.rootdir + 'apps/fmm/FMM'
|
||||
cmd = 'FMM'
|
||||
input = options.rootdir + 'apps/fmm/inputs/input.2048.p' + str(options.numcpus)
|
||||
|
||||
class Ocean_contig(LiveProcess):
|
||||
class Ocean_contig(Process):
|
||||
executable = options.rootdir + 'apps/ocean/contiguous_partitions/OCEAN'
|
||||
cmd = 'OCEAN -p' + str(options.numcpus)
|
||||
|
||||
class Ocean_noncontig(LiveProcess):
|
||||
class Ocean_noncontig(Process):
|
||||
executable = options.rootdir + 'apps/ocean/non_contiguous_partitions/OCEAN'
|
||||
cmd = 'OCEAN -p' + str(options.numcpus)
|
||||
|
||||
class Raytrace(LiveProcess):
|
||||
class Raytrace(Process):
|
||||
executable = options.rootdir + 'apps/raytrace/RAYTRACE'
|
||||
cmd = 'RAYTRACE -p' + str(options.numcpus) + ' ' \
|
||||
+ options.rootdir + 'apps/raytrace/inputs/teapot.env'
|
||||
|
||||
class Water_nsquared(LiveProcess):
|
||||
class Water_nsquared(Process):
|
||||
executable = options.rootdir + 'apps/water-nsquared/WATER-NSQUARED'
|
||||
cmd = 'WATER-NSQUARED'
|
||||
input = options.rootdir + 'apps/water-nsquared/input.p' + str(options.numcpus)
|
||||
|
||||
class Water_spatial(LiveProcess):
|
||||
class Water_spatial(Process):
|
||||
executable = options.rootdir + 'apps/water-spatial/WATER-SPATIAL'
|
||||
cmd = 'WATER-SPATIAL'
|
||||
input = options.rootdir + 'apps/water-spatial/input.p' + str(options.numcpus)
|
||||
|
|
|
@ -77,39 +77,39 @@ if not options.numcpus:
|
|||
# --------------------
|
||||
# Define Splash2 Benchmarks
|
||||
# ====================
|
||||
class Cholesky(LiveProcess):
|
||||
class Cholesky(Process):
|
||||
cwd = options.rootdir + '/kernels/cholesky'
|
||||
executable = options.rootdir + '/kernels/cholesky/CHOLESKY'
|
||||
cmd = ['CHOLESKY', '-p' + str(options.numcpus),
|
||||
options.rootdir + '/kernels/cholesky/inputs/tk23.O']
|
||||
|
||||
class FFT(LiveProcess):
|
||||
class FFT(Process):
|
||||
cwd = options.rootdir + '/kernels/fft'
|
||||
executable = options.rootdir + '/kernels/fft/FFT'
|
||||
cmd = ['FFT', '-p', str(options.numcpus), '-m18']
|
||||
|
||||
class LU_contig(LiveProcess):
|
||||
class LU_contig(Process):
|
||||
executable = options.rootdir + '/kernels/lu/contiguous_blocks/LU'
|
||||
cmd = ['LU', '-p', str(options.numcpus)]
|
||||
cwd = options.rootdir + '/kernels/lu/contiguous_blocks'
|
||||
|
||||
class LU_noncontig(LiveProcess):
|
||||
class LU_noncontig(Process):
|
||||
executable = options.rootdir + '/kernels/lu/non_contiguous_blocks/LU'
|
||||
cmd = ['LU', '-p', str(options.numcpus)]
|
||||
cwd = options.rootdir + '/kernels/lu/non_contiguous_blocks'
|
||||
|
||||
class Radix(LiveProcess):
|
||||
class Radix(Process):
|
||||
executable = options.rootdir + '/kernels/radix/RADIX'
|
||||
cmd = ['RADIX', '-n524288', '-p', str(options.numcpus)]
|
||||
cwd = options.rootdir + '/kernels/radix'
|
||||
|
||||
class Barnes(LiveProcess):
|
||||
class Barnes(Process):
|
||||
executable = options.rootdir + '/apps/barnes/BARNES'
|
||||
cmd = ['BARNES']
|
||||
input = options.rootdir + '/apps/barnes/input.p' + str(options.numcpus)
|
||||
cwd = options.rootdir + '/apps/barnes'
|
||||
|
||||
class FMM(LiveProcess):
|
||||
class FMM(Process):
|
||||
executable = options.rootdir + '/apps/fmm/FMM'
|
||||
cmd = ['FMM']
|
||||
if str(options.numcpus) == '1':
|
||||
|
@ -118,23 +118,23 @@ class FMM(LiveProcess):
|
|||
input = options.rootdir + '/apps/fmm/inputs/input.2048.p' + str(options.numcpus)
|
||||
cwd = options.rootdir + '/apps/fmm'
|
||||
|
||||
class Ocean_contig(LiveProcess):
|
||||
class Ocean_contig(Process):
|
||||
executable = options.rootdir + '/apps/ocean/contiguous_partitions/OCEAN'
|
||||
cmd = ['OCEAN', '-p', str(options.numcpus)]
|
||||
cwd = options.rootdir + '/apps/ocean/contiguous_partitions'
|
||||
|
||||
class Ocean_noncontig(LiveProcess):
|
||||
class Ocean_noncontig(Process):
|
||||
executable = options.rootdir + '/apps/ocean/non_contiguous_partitions/OCEAN'
|
||||
cmd = ['OCEAN', '-p', str(options.numcpus)]
|
||||
cwd = options.rootdir + '/apps/ocean/non_contiguous_partitions'
|
||||
|
||||
class Raytrace(LiveProcess):
|
||||
class Raytrace(Process):
|
||||
executable = options.rootdir + '/apps/raytrace/RAYTRACE'
|
||||
cmd = ['RAYTRACE', '-p' + str(options.numcpus),
|
||||
options.rootdir + '/apps/raytrace/inputs/teapot.env']
|
||||
cwd = options.rootdir + '/apps/raytrace'
|
||||
|
||||
class Water_nsquared(LiveProcess):
|
||||
class Water_nsquared(Process):
|
||||
executable = options.rootdir + '/apps/water-nsquared/WATER-NSQUARED'
|
||||
cmd = ['WATER-NSQUARED']
|
||||
if options.numcpus==1:
|
||||
|
@ -143,7 +143,7 @@ class Water_nsquared(LiveProcess):
|
|||
input = options.rootdir + '/apps/water-nsquared/input.p' + str(options.numcpus)
|
||||
cwd = options.rootdir + '/apps/water-nsquared'
|
||||
|
||||
class Water_spatial(LiveProcess):
|
||||
class Water_spatial(Process):
|
||||
executable = options.rootdir + '/apps/water-spatial/WATER-SPATIAL'
|
||||
cmd = ['WATER-SPATIAL']
|
||||
if options.numcpus==1:
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
#!/bin/sh
|
||||
# From Gerrit Code Review 2.13.5-2617-gba50ae91fd
|
||||
#
|
||||
# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
|
||||
#
|
||||
# Copyright (C) 2009 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
unset GREP_OPTIONS
|
||||
|
||||
CHANGE_ID_AFTER="Bug|Depends-On|Issue|Test|Feature|Fixes|Fixed"
|
||||
MSG="$1"
|
||||
|
||||
# Check for, and add if missing, a unique Change-Id
|
||||
#
|
||||
add_ChangeId() {
|
||||
clean_message=`sed -e '
|
||||
/^diff --git .*/{
|
||||
s///
|
||||
q
|
||||
}
|
||||
/^Signed-off-by:/d
|
||||
/^#/d
|
||||
' "$MSG" | git stripspace`
|
||||
if test -z "$clean_message"
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
# Do not add Change-Id to temp commits
|
||||
if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!'
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
if test "false" = "`git config --bool --get gerrit.createChangeId`"
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
# Does Change-Id: already exist? if so, exit (no change).
|
||||
if grep -i '^Change-Id:' "$MSG" >/dev/null
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
id=`_gen_ChangeId`
|
||||
T="$MSG.tmp.$$"
|
||||
AWK=awk
|
||||
if [ -x /usr/xpg4/bin/awk ]; then
|
||||
# Solaris AWK is just too broken
|
||||
AWK=/usr/xpg4/bin/awk
|
||||
fi
|
||||
|
||||
# Get core.commentChar from git config or use default symbol
|
||||
commentChar=`git config --get core.commentChar`
|
||||
commentChar=${commentChar:-#}
|
||||
|
||||
# How this works:
|
||||
# - parse the commit message as (textLine+ blankLine*)*
|
||||
# - assume textLine+ to be a footer until proven otherwise
|
||||
# - exception: the first block is not footer (as it is the title)
|
||||
# - read textLine+ into a variable
|
||||
# - then count blankLines
|
||||
# - once the next textLine appears, print textLine+ blankLine* as these
|
||||
# aren't footer
|
||||
# - in END, the last textLine+ block is available for footer parsing
|
||||
$AWK '
|
||||
BEGIN {
|
||||
# while we start with the assumption that textLine+
|
||||
# is a footer, the first block is not.
|
||||
isFooter = 0
|
||||
footerComment = 0
|
||||
blankLines = 0
|
||||
}
|
||||
|
||||
# Skip lines starting with commentChar without any spaces before it.
|
||||
/^'"$commentChar"'/ { next }
|
||||
|
||||
# Skip the line starting with the diff command and everything after it,
|
||||
# up to the end of the file, assuming it is only patch data.
|
||||
# If more than one line before the diff was empty, strip all but one.
|
||||
/^diff --git / {
|
||||
blankLines = 0
|
||||
while (getline) { }
|
||||
next
|
||||
}
|
||||
|
||||
# Count blank lines outside footer comments
|
||||
/^$/ && (footerComment == 0) {
|
||||
blankLines++
|
||||
next
|
||||
}
|
||||
|
||||
# Catch footer comment
|
||||
/^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
|
||||
footerComment = 1
|
||||
}
|
||||
|
||||
/]$/ && (footerComment == 1) {
|
||||
footerComment = 2
|
||||
}
|
||||
|
||||
# We have a non-blank line after blank lines. Handle this.
|
||||
(blankLines > 0) {
|
||||
print lines
|
||||
for (i = 0; i < blankLines; i++) {
|
||||
print ""
|
||||
}
|
||||
|
||||
lines = ""
|
||||
blankLines = 0
|
||||
isFooter = 1
|
||||
footerComment = 0
|
||||
}
|
||||
|
||||
# Detect that the current block is not the footer
|
||||
(footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
|
||||
isFooter = 0
|
||||
}
|
||||
|
||||
{
|
||||
# We need this information about the current last comment line
|
||||
if (footerComment == 2) {
|
||||
footerComment = 0
|
||||
}
|
||||
if (lines != "") {
|
||||
lines = lines "\n";
|
||||
}
|
||||
lines = lines $0
|
||||
}
|
||||
|
||||
# Footer handling:
|
||||
# If the last block is considered a footer, splice in the Change-Id at the
|
||||
# right place.
|
||||
# Look for the right place to inject Change-Id by considering
|
||||
# CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
|
||||
# then Change-Id, then everything else (eg. Signed-off-by:).
|
||||
#
|
||||
# Otherwise just print the last block, a new line and the Change-Id as a
|
||||
# block of its own.
|
||||
END {
|
||||
unprinted = 1
|
||||
if (isFooter == 0) {
|
||||
print lines "\n"
|
||||
lines = ""
|
||||
}
|
||||
changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
|
||||
numlines = split(lines, footer, "\n")
|
||||
for (line = 1; line <= numlines; line++) {
|
||||
if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
|
||||
unprinted = 0
|
||||
print "Change-Id: I'"$id"'"
|
||||
}
|
||||
print footer[line]
|
||||
}
|
||||
if (unprinted) {
|
||||
print "Change-Id: I'"$id"'"
|
||||
}
|
||||
}' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T"
|
||||
}
|
||||
_gen_ChangeIdInput() {
|
||||
echo "tree `git write-tree`"
|
||||
if parent=`git rev-parse "HEAD^0" 2>/dev/null`
|
||||
then
|
||||
echo "parent $parent"
|
||||
fi
|
||||
echo "author `git var GIT_AUTHOR_IDENT`"
|
||||
echo "committer `git var GIT_COMMITTER_IDENT`"
|
||||
echo
|
||||
printf '%s' "$clean_message"
|
||||
}
|
||||
_gen_ChangeId() {
|
||||
_gen_ChangeIdInput |
|
||||
git hash-object -t commit --stdin
|
||||
}
|
||||
|
||||
|
||||
add_ChangeId
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
|
||||
# All rights reserved.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
|
||||
# All rights reserved.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# calc.py
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# calc.py
|
||||
|
|
|
@ -483,7 +483,7 @@ class DictImporter(object):
|
|||
if fullname == 'm5.objects':
|
||||
return self
|
||||
|
||||
if fullname.startswith('m5.internal'):
|
||||
if fullname.startswith('_m5'):
|
||||
return None
|
||||
|
||||
source = self.modules.get(fullname, None)
|
||||
|
@ -588,14 +588,14 @@ def makeDefinesPyFile(target, source, env):
|
|||
|
||||
code = code_formatter()
|
||||
code("""
|
||||
import m5.internal
|
||||
import _m5.core
|
||||
import m5.util
|
||||
|
||||
buildEnv = m5.util.SmartDict($build_env)
|
||||
|
||||
compileDate = m5.internal.core.compileDate
|
||||
compileDate = _m5.core.compileDate
|
||||
_globals = globals()
|
||||
for key,val in m5.internal.core.__dict__.iteritems():
|
||||
for key,val in _m5.core.__dict__.iteritems():
|
||||
if key.startswith('flag_'):
|
||||
flag = key[5:]
|
||||
_globals[flag] = val
|
||||
|
@ -773,13 +773,13 @@ if GetOption('with_cxx_config'):
|
|||
# Generate any needed param SWIG wrapper files
|
||||
params_i_files = []
|
||||
for name,param in sorted(params_to_swig.iteritems()):
|
||||
i_file = File('python/m5/internal/%s.i' % (param.swig_module_name()))
|
||||
i_file = File('python/_m5/%s.i' % (param.swig_module_name()))
|
||||
params_i_files.append(i_file)
|
||||
env.Command(i_file, Value(name),
|
||||
MakeAction(createParamSwigWrapper, Transform("SW PARAM")))
|
||||
env.Depends(i_file, depends)
|
||||
env.Depends(SWIG, i_file)
|
||||
SwigSource('m5.internal', i_file)
|
||||
SwigSource('_m5', i_file)
|
||||
|
||||
# Generate all enum header files
|
||||
for name,enum in sorted(all_enums.iteritems()):
|
||||
|
@ -799,22 +799,22 @@ for name,enum in sorted(all_enums.iteritems()):
|
|||
env.Depends(hh_file, depends + extra_deps)
|
||||
env.Depends(SWIG, hh_file)
|
||||
|
||||
i_file = File('python/m5/internal/enum_%s.i' % name)
|
||||
i_file = File('python/_m5/enum_%s.i' % name)
|
||||
env.Command(i_file, Value(name),
|
||||
MakeAction(createEnumSwigWrapper, Transform("ENUMSWIG")))
|
||||
env.Depends(i_file, depends + extra_deps)
|
||||
env.Depends(SWIG, i_file)
|
||||
SwigSource('m5.internal', i_file)
|
||||
SwigSource('_m5', i_file)
|
||||
|
||||
# Generate SimObject SWIG wrapper files
|
||||
for name,simobj in sorted(sim_objects.iteritems()):
|
||||
py_source = PySource.modules[simobj.__module__]
|
||||
extra_deps = [ py_source.tnode ]
|
||||
i_file = File('python/m5/internal/param_%s.i' % name)
|
||||
i_file = File('python/_m5/param_%s.i' % name)
|
||||
env.Command(i_file, Value(name),
|
||||
MakeAction(createSimObjectSwigWrapper, Transform("SO SWIG")))
|
||||
env.Depends(i_file, depends + extra_deps)
|
||||
SwigSource('m5.internal', i_file)
|
||||
SwigSource('_m5', i_file)
|
||||
|
||||
# Generate the main swig init file
|
||||
def makeEmbeddedSwigInit(package):
|
||||
|
|
|
@ -840,7 +840,7 @@ decode OPCODE default Unknown::unknown() {
|
|||
exitSimLoop("halt instruction encountered");
|
||||
}}, IsNonSpeculative);
|
||||
0x83: callsys({{
|
||||
xc->syscall(R0);
|
||||
xc->syscall(R0, &fault);
|
||||
}}, IsSerializeAfter, IsNonSpeculative, IsSyscall);
|
||||
// Read uniq reg into ABI return value register (r0)
|
||||
0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess);
|
||||
|
|
|
@ -46,7 +46,7 @@ using namespace AlphaISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -66,7 +66,7 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
/// borrowed from Tru64, the subcases that get used appear to be
|
||||
/// different in practice from those used by Tru64 processes.
|
||||
static SyscallReturn
|
||||
osf_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -95,7 +95,7 @@ osf_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
|
||||
/// Target osf_setsysinfo() handler.
|
||||
static SyscallReturn
|
||||
osf_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -440,7 +440,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
|
|||
/* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
|
||||
/* 310 */ SyscallDesc("syslog", unimplementedFunc),
|
||||
/* 311 */ SyscallDesc("reboot", unimplementedFunc),
|
||||
/* 312 */ SyscallDesc("clone", cloneFunc),
|
||||
/* 312 */ SyscallDesc("clone", cloneFunc<AlphaLinux>),
|
||||
/* 313 */ SyscallDesc("uselib", unimplementedFunc),
|
||||
/* 314 */ SyscallDesc("mlock", unimplementedFunc),
|
||||
/* 315 */ SyscallDesc("munlock", unimplementedFunc),
|
||||
|
@ -572,9 +572,9 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
|
|||
/* 441 */ SyscallDesc("keyctl", unimplementedFunc)
|
||||
};
|
||||
|
||||
AlphaLinuxProcess::AlphaLinuxProcess(LiveProcessParams * params,
|
||||
AlphaLinuxProcess::AlphaLinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: AlphaLiveProcess(params, objFile),
|
||||
: AlphaProcess(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
{
|
||||
//init_regs->intRegFile[0] = 0;
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
namespace AlphaISA {
|
||||
|
||||
/// A process with emulated Alpha/Linux syscalls.
|
||||
class AlphaLinuxProcess : public AlphaLiveProcess
|
||||
class AlphaLinuxProcess : public AlphaProcess
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
AlphaLinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
AlphaLinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
virtual SyscallDesc* getDesc(int callnum);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Loader.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
|
@ -46,28 +47,31 @@
|
|||
using namespace AlphaISA;
|
||||
using namespace std;
|
||||
|
||||
AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams *params,
|
||||
ObjectFile *objFile)
|
||||
: LiveProcess(params, objFile)
|
||||
AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
|
||||
: Process(params, objFile)
|
||||
{
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set up stack. On Alpha, stack goes below text section. This
|
||||
// code should get moved to some architecture-specific spot.
|
||||
stack_base = objFile->textBase() - (409600+4096);
|
||||
Addr stack_base = objFile->textBase() - (409600+4096);
|
||||
|
||||
// Set up region for mmaps. Tru64 seems to start just above 0 and
|
||||
// grow up from there.
|
||||
mmap_end = 0x10000;
|
||||
// Set up region for mmaps.
|
||||
Addr mmap_end = 0x10000;
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
||||
AlphaProcess::argsInit(int intSize, int pageSize)
|
||||
{
|
||||
// Patch the ld_bias for dynamic executables.
|
||||
updateBias();
|
||||
|
@ -130,15 +134,16 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
|||
space_needed = 32*1024;
|
||||
|
||||
// set bottom of stack
|
||||
stack_min = stack_base - space_needed;
|
||||
memState->setStackMin(memState->getStackBase() - space_needed);
|
||||
// align it
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
stack_size = stack_base - stack_min;
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
|
||||
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
|
||||
// map memory
|
||||
allocateMem(stack_min, roundUp(stack_size, pageSize));
|
||||
allocateMem(memState->getStackMin(), roundUp(memState->getStackSize(),
|
||||
pageSize));
|
||||
|
||||
// map out initial stack contents
|
||||
Addr argv_array_base = stack_min + intSize; // room for argc
|
||||
Addr argv_array_base = memState->getStackMin() + intSize; // room for argc
|
||||
Addr envp_array_base = argv_array_base + argv_array_size;
|
||||
Addr auxv_array_base = envp_array_base + envp_array_size;
|
||||
Addr arg_data_base = auxv_array_base + auxv_array_size;
|
||||
|
@ -153,7 +158,7 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
|||
else
|
||||
panic("Unknown int size");
|
||||
|
||||
initVirtMem.writeBlob(stack_min, (uint8_t*)&argc, intSize);
|
||||
initVirtMem.writeBlob(memState->getStackMin(), (uint8_t*)&argc, intSize);
|
||||
|
||||
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
|
||||
copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
|
||||
|
@ -170,13 +175,13 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
|||
|
||||
setSyscallArg(tc, 0, argc);
|
||||
setSyscallArg(tc, 1, argv_array_base);
|
||||
tc->setIntReg(StackPointerReg, stack_min);
|
||||
tc->setIntReg(StackPointerReg, memState->getStackMin());
|
||||
|
||||
tc->pcState(getStartPC());
|
||||
}
|
||||
|
||||
void
|
||||
AlphaLiveProcess::setupASNReg()
|
||||
AlphaProcess::setupASNReg()
|
||||
{
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
tc->setMiscRegNoEffect(IPR_DTB_ASN, _pid << 57);
|
||||
|
@ -184,9 +189,9 @@ AlphaLiveProcess::setupASNReg()
|
|||
|
||||
|
||||
void
|
||||
AlphaLiveProcess::loadState(CheckpointIn &cp)
|
||||
AlphaProcess::loadState(CheckpointIn &cp)
|
||||
{
|
||||
LiveProcess::loadState(cp);
|
||||
Process::loadState(cp);
|
||||
// need to set up ASN after unserialization since _pid value may
|
||||
// come from checkpoint
|
||||
setupASNReg();
|
||||
|
@ -194,13 +199,13 @@ AlphaLiveProcess::loadState(CheckpointIn &cp)
|
|||
|
||||
|
||||
void
|
||||
AlphaLiveProcess::initState()
|
||||
AlphaProcess::initState()
|
||||
{
|
||||
// need to set up ASN before further initialization since init
|
||||
// will involve writing to virtual memory addresses
|
||||
setupASNReg();
|
||||
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
|
||||
argsInit(MachineBytes, PageBytes);
|
||||
|
||||
|
@ -214,22 +219,21 @@ AlphaLiveProcess::initState()
|
|||
}
|
||||
|
||||
AlphaISA::IntReg
|
||||
AlphaLiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
AlphaProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 6);
|
||||
return tc->readIntReg(FirstArgumentReg + i++);
|
||||
}
|
||||
|
||||
void
|
||||
AlphaLiveProcess::setSyscallArg(ThreadContext *tc,
|
||||
int i, AlphaISA::IntReg val)
|
||||
AlphaProcess::setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val)
|
||||
{
|
||||
assert(i < 6);
|
||||
tc->setIntReg(FirstArgumentReg + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
AlphaLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
AlphaProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
// check for error condition. Alpha syscall convention is to
|
||||
// indicate success/failure in reg a3 (r19) and put the
|
||||
|
|
|
@ -35,13 +35,13 @@
|
|||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class AlphaLiveProcess : public LiveProcess
|
||||
class AlphaProcess : public Process
|
||||
{
|
||||
private:
|
||||
void setupASNReg();
|
||||
|
||||
protected:
|
||||
AlphaLiveProcess(LiveProcessParams *params, ObjectFile *objFile);
|
||||
AlphaProcess(ProcessParams *params, ObjectFile *objFile);
|
||||
|
||||
void loadState(CheckpointIn &cp) override;
|
||||
void initState() override;
|
||||
|
@ -51,12 +51,12 @@ class AlphaLiveProcess : public LiveProcess
|
|||
public:
|
||||
AlphaISA::IntReg getSyscallArg(ThreadContext *tc, int &i) override;
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val) override;
|
||||
void setSyscallReturn(ThreadContext *tc,
|
||||
SyscallReturn return_value) override;
|
||||
|
||||
// override default implementation in LiveProcess as the mmap
|
||||
// override default implementation in Process as the mmap
|
||||
// region for Alpha platforms grows upward
|
||||
virtual bool mmapGrowsDown() const override { return false; }
|
||||
};
|
||||
|
|
|
@ -784,7 +784,8 @@ SupervisorCall::invoke(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
callNum = tc->readIntReg(INTREG_X8);
|
||||
else
|
||||
callNum = tc->readIntReg(INTREG_R7);
|
||||
tc->syscall(callNum);
|
||||
Fault fault;
|
||||
tc->syscall(callNum, &fault);
|
||||
|
||||
// Advance the PC since that won't happen automatically.
|
||||
PCState pc = tc->pcState();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2012-2013, 2016 ARM Limited
|
||||
* Copyright (c) 2010, 2012-2013, 2016-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -566,6 +566,31 @@ class IllegalInstSetStateFault : public ArmFaultVals<IllegalInstSetStateFault>
|
|||
IllegalInstSetStateFault();
|
||||
};
|
||||
|
||||
/*
|
||||
* Explicitly declare template static member variables avoid warnings in some clang versions
|
||||
*/
|
||||
template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorCall>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<HypervisorCall>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<VirtualDataAbort>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<HypervisorTrap>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<VirtualInterrupt>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<VirtualFastInterrupt>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SupervisorTrap>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SecureMonitorTrap>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<PCAlignmentFault>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SPAlignmentFault>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<SystemError>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<FlushPipe>::vals;
|
||||
template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals;
|
||||
|
||||
|
||||
} // namespace ArmISA
|
||||
|
||||
#endif // __ARM_FAULTS_HH__
|
||||
|
|
|
@ -53,7 +53,7 @@ using namespace std;
|
|||
using namespace ArmISA;
|
||||
|
||||
static SyscallReturn
|
||||
issetugidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
issetugidFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
|
||||
|
@ -61,7 +61,7 @@ issetugidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
}
|
||||
|
||||
static SyscallReturn
|
||||
sysctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
sysctlFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -1206,9 +1206,9 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 547 */ SyscallDesc("unused#547", unimplementedFunc),
|
||||
};
|
||||
|
||||
ArmFreebsdProcess32::ArmFreebsdProcess32(LiveProcessParams * params,
|
||||
ArmFreebsdProcess32::ArmFreebsdProcess32(ProcessParams * params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess32(params, objFile, _arch)
|
||||
: ArmProcess32(params, objFile, _arch)
|
||||
{
|
||||
SyscallTable table;
|
||||
|
||||
|
@ -1218,9 +1218,9 @@ ArmFreebsdProcess32::ArmFreebsdProcess32(LiveProcessParams * params,
|
|||
syscallTables.push_back(table);
|
||||
}
|
||||
|
||||
ArmFreebsdProcess64::ArmFreebsdProcess64(LiveProcessParams * params,
|
||||
ArmFreebsdProcess64::ArmFreebsdProcess64(ProcessParams * params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess64(params, objFile, _arch)
|
||||
: ArmProcess64(params, objFile, _arch)
|
||||
{
|
||||
SyscallTable table;
|
||||
|
||||
|
@ -1269,13 +1269,13 @@ ArmFreebsdProcess64::getDesc(int callnum)
|
|||
void
|
||||
ArmFreebsdProcess32::initState()
|
||||
{
|
||||
ArmLiveProcess32::initState();
|
||||
ArmProcess32::initState();
|
||||
// The 32 bit equivalent of the comm page would be set up here.
|
||||
}
|
||||
|
||||
void
|
||||
ArmFreebsdProcess64::initState()
|
||||
{
|
||||
ArmLiveProcess64::initState();
|
||||
ArmProcess64::initState();
|
||||
// The 64 bit equivalent of the comm page would be set up here.
|
||||
}
|
||||
|
|
|
@ -55,16 +55,16 @@ class ArmFreebsdProcessBits
|
|||
};
|
||||
|
||||
/// A process with emulated Arm/Freebsd syscalls.
|
||||
class ArmFreebsdProcess32 : public ArmLiveProcess32, public ArmFreebsdProcessBits
|
||||
class ArmFreebsdProcess32 : public ArmProcess32, public ArmFreebsdProcessBits
|
||||
{
|
||||
public:
|
||||
ArmFreebsdProcess32(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
ArmFreebsdProcess32(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using ArmLiveProcess::getSyscallArg;
|
||||
using ArmProcess::getSyscallArg;
|
||||
|
||||
/// A page to hold "kernel" provided functions. The name might be wrong.
|
||||
static const Addr commPage;
|
||||
|
@ -73,11 +73,11 @@ class ArmFreebsdProcess32 : public ArmLiveProcess32, public ArmFreebsdProcessBit
|
|||
};
|
||||
|
||||
/// A process with emulated Arm/Freebsd syscalls.
|
||||
class ArmFreebsdProcess64 : public ArmLiveProcess64, public ArmFreebsdProcessBits
|
||||
class ArmFreebsdProcess64 : public ArmProcess64, public ArmFreebsdProcessBits
|
||||
{
|
||||
public:
|
||||
ArmFreebsdProcess64(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
ArmFreebsdProcess64(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
SyscallDesc* getDesc(int callnum);
|
||||
|
|
|
@ -594,7 +594,8 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
|
|||
warn_once("The ccsidr register isn't implemented and "
|
||||
"always reads as 0.\n");
|
||||
break;
|
||||
case MISCREG_CTR:
|
||||
case MISCREG_CTR: // AArch32, ARMv7, top bit set
|
||||
case MISCREG_CTR_EL0: // AArch64
|
||||
{
|
||||
//all caches have the same line size in gem5
|
||||
//4 byte words in ARM
|
||||
|
|
|
@ -50,7 +50,7 @@ let {{
|
|||
_in = bits(resTemp, intWidth - 1);
|
||||
_iz = ((resTemp & mask(intWidth)) == 0);
|
||||
CondCodesNZ = (_in << 1) | _iz;
|
||||
DPRINTF(Arm, "(in, iz) = (%%d, %%d)\\n", _in, _iz);
|
||||
DPRINTF(Arm, "(in, iz) = (%d, %d)\\n", _in, _iz);
|
||||
'''
|
||||
if overflow and overflow != "none":
|
||||
code += '''
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// -*- mode:c++ -*-
|
||||
|
||||
// Copyright (c) 2010-2013 ARM Limited
|
||||
// Copyright (c) 2010-2013,2017 ARM Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// The license below extends only to copyright in the software and shall
|
||||
|
@ -814,7 +814,9 @@ let {{
|
|||
|
||||
mrc14code = '''
|
||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(op1);
|
||||
if (!canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
if (!can_read || undefined) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -836,7 +838,9 @@ let {{
|
|||
|
||||
mcr14code = '''
|
||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest);
|
||||
if (!canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
if (undefined || !can_write) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -861,12 +865,13 @@ let {{
|
|||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||
Hcptr, imm);
|
||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
||||
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -891,12 +896,14 @@ let {{
|
|||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||
Hcptr, imm);
|
||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
||||
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -920,12 +927,13 @@ let {{
|
|||
MiscRegIndex miscReg = (MiscRegIndex)
|
||||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
||||
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -949,12 +957,14 @@ let {{
|
|||
MiscRegIndex miscReg = (MiscRegIndex)
|
||||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
||||
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2015 ARM Limited
|
||||
# Copyright (c) 2015, 2017 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -38,18 +38,8 @@
|
|||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
|
||||
from Gic import BaseGic
|
||||
from KvmVM import KvmVM
|
||||
from System import System
|
||||
from Gic import Pl390
|
||||
|
||||
class KvmGic(BaseGic):
|
||||
type = 'KvmGic'
|
||||
class MuxingKvmGic(Pl390):
|
||||
type = 'MuxingKvmGic'
|
||||
cxx_header = "arch/arm/kvm/gic.hh"
|
||||
|
||||
dist_addr = Param.Addr(0x1f001000, "Address for distributor")
|
||||
cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
|
||||
it_lines = Param.UInt32(128, "Number of interrupt lines supported")
|
||||
|
||||
system = Param.System(Parent.any,
|
||||
'System this interrupt controller belongs to')
|
||||
kvmVM = Param.KvmVM(Parent.any, 'KVM VM (i.e., shared memory domain)')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
* Copyright (c) 2015, 2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -65,6 +65,8 @@ static_assert(NUM_QREGS == 32, "Unexpected number of aarch64 vector regs.");
|
|||
#define INT_REG(name) CORE_REG(name, U64)
|
||||
#define SIMD_REG(name) CORE_REG(name, U128)
|
||||
|
||||
#define SYS_MPIDR_EL1 ARM64_SYS_REG(0b11, 0b000, 0b0000, 0b0000, 0b101)
|
||||
|
||||
constexpr uint64_t
|
||||
kvmXReg(const int num)
|
||||
{
|
||||
|
@ -102,7 +104,6 @@ const std::vector<ArmV8KvmCPU::IntRegInfo> ArmV8KvmCPU::intRegMap = {
|
|||
};
|
||||
|
||||
const std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegMap = {
|
||||
MiscRegInfo(INT_REG(regs.pstate), MISCREG_CPSR, "PSTATE"),
|
||||
MiscRegInfo(INT_REG(elr_el1), MISCREG_ELR_EL1, "ELR(EL1)"),
|
||||
MiscRegInfo(INT_REG(spsr[KVM_SPSR_EL1]), MISCREG_SPSR_EL1, "SPSR(EL1)"),
|
||||
MiscRegInfo(INT_REG(spsr[KVM_SPSR_ABT]), MISCREG_SPSR_ABT, "SPSR(ABT)"),
|
||||
|
@ -113,6 +114,10 @@ const std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegMap = {
|
|||
MiscRegInfo(INT_REG(fp_regs.fpcr), MISCREG_FPCR, "FPCR"),
|
||||
};
|
||||
|
||||
const std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegIdMap = {
|
||||
MiscRegInfo(SYS_MPIDR_EL1, MISCREG_MPIDR_EL1, "MPIDR(EL1)"),
|
||||
};
|
||||
|
||||
ArmV8KvmCPU::ArmV8KvmCPU(ArmV8KvmCPUParams *params)
|
||||
: BaseArmKvmCPU(params)
|
||||
{
|
||||
|
@ -122,6 +127,19 @@ ArmV8KvmCPU::~ArmV8KvmCPU()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
ArmV8KvmCPU::startup()
|
||||
{
|
||||
BaseArmKvmCPU::startup();
|
||||
|
||||
// Override ID registers that KVM should "inherit" from gem5.
|
||||
for (const auto &ri : miscRegIdMap) {
|
||||
const uint64_t value(tc->readMiscReg(ri.idx));
|
||||
DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
|
||||
setOneReg(ri.kvm, value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArmV8KvmCPU::dump() const
|
||||
{
|
||||
|
@ -136,9 +154,14 @@ ArmV8KvmCPU::dump() const
|
|||
for (const auto &ri : intRegMap)
|
||||
inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
|
||||
|
||||
inform(" %s: %s\n", "PSTATE", getAndFormatOneReg(INT_REG(regs.pstate)));
|
||||
|
||||
for (const auto &ri : miscRegMap)
|
||||
inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
|
||||
|
||||
for (const auto &ri : miscRegIdMap)
|
||||
inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
|
||||
|
||||
for (const auto ® : getRegList()) {
|
||||
const uint64_t arch(reg & KVM_REG_ARCH_MASK);
|
||||
if (arch != KVM_REG_ARM64) {
|
||||
|
@ -188,6 +211,20 @@ void
|
|||
ArmV8KvmCPU::updateKvmState()
|
||||
{
|
||||
DPRINTF(KvmContext, "In updateKvmState():\n");
|
||||
|
||||
// update pstate register state
|
||||
CPSR cpsr(tc->readMiscReg(MISCREG_CPSR));
|
||||
cpsr.nz = tc->readCCReg(CCREG_NZ);
|
||||
cpsr.c = tc->readCCReg(CCREG_C);
|
||||
cpsr.v = tc->readCCReg(CCREG_V);
|
||||
if (cpsr.width) {
|
||||
cpsr.ge = tc->readCCReg(CCREG_GE);
|
||||
} else {
|
||||
cpsr.ge = 0;
|
||||
}
|
||||
DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
|
||||
setOneReg(INT_REG(regs.pstate), cpsr);
|
||||
|
||||
for (const auto &ri : miscRegMap) {
|
||||
const uint64_t value(tc->readMiscReg(ri.idx));
|
||||
DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
|
||||
|
@ -231,7 +268,18 @@ ArmV8KvmCPU::updateThreadContext()
|
|||
{
|
||||
DPRINTF(KvmContext, "In updateThreadContext():\n");
|
||||
|
||||
// Update core misc regs first as they (particularly PSTATE/CPSR)
|
||||
// Update pstate thread context
|
||||
const CPSR cpsr(tc->readMiscRegNoEffect(MISCREG_CPSR));
|
||||
DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
|
||||
tc->setMiscRegNoEffect(MISCREG_CPSR, cpsr);
|
||||
tc->setCCReg(CCREG_NZ, cpsr.nz);
|
||||
tc->setCCReg(CCREG_C, cpsr.c);
|
||||
tc->setCCReg(CCREG_V, cpsr.v);
|
||||
if (cpsr.width) {
|
||||
tc->setCCReg(CCREG_GE, cpsr.ge);
|
||||
}
|
||||
|
||||
// Update core misc regs first as they
|
||||
// affect how other registers are mapped.
|
||||
for (const auto &ri : miscRegMap) {
|
||||
const auto value(getOneRegU64(ri.kvm));
|
||||
|
@ -242,7 +290,13 @@ ArmV8KvmCPU::updateThreadContext()
|
|||
for (int i = 0; i < NUM_XREGS; ++i) {
|
||||
const auto value(getOneRegU64(kvmXReg(i)));
|
||||
DPRINTF(KvmContext, " X%i := 0x%x\n", i, value);
|
||||
tc->setIntReg(INTREG_X0 + i, value);
|
||||
// KVM64 returns registers in 64-bit layout. If we are in aarch32
|
||||
// mode, we need to map these to banked ARM32 registers.
|
||||
if (inAArch64(tc)) {
|
||||
tc->setIntReg(INTREG_X0 + i, value);
|
||||
} else {
|
||||
tc->setIntRegFlat(IntReg64Map[INTREG_X0 + i], value);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &ri : intRegMap) {
|
||||
|
@ -266,7 +320,6 @@ ArmV8KvmCPU::updateThreadContext()
|
|||
tc->setMiscRegNoEffect(ri.idx, value);
|
||||
}
|
||||
|
||||
const CPSR cpsr(tc->readMiscRegNoEffect(MISCREG_CPSR));
|
||||
PCState pc(getOneRegU64(INT_REG(regs.pc)));
|
||||
pc.aarch64(inAArch64(tc));
|
||||
pc.thumb(cpsr.t);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
* Copyright (c) 2015, 2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -83,6 +83,8 @@ class ArmV8KvmCPU : public BaseArmKvmCPU
|
|||
ArmV8KvmCPU(ArmV8KvmCPUParams *params);
|
||||
virtual ~ArmV8KvmCPU();
|
||||
|
||||
void startup() override;
|
||||
|
||||
void dump() const override;
|
||||
|
||||
protected:
|
||||
|
@ -132,6 +134,8 @@ class ArmV8KvmCPU : public BaseArmKvmCPU
|
|||
static const std::vector<ArmV8KvmCPU::IntRegInfo> intRegMap;
|
||||
/** Mapping between gem5 misc registers registers and registers in kvm */
|
||||
static const std::vector<ArmV8KvmCPU::MiscRegInfo> miscRegMap;
|
||||
/** Mapping between gem5 ID misc registers registers and registers in kvm */
|
||||
static const std::vector<ArmV8KvmCPU::MiscRegInfo> miscRegIdMap;
|
||||
|
||||
/** Cached mapping between system registers in kvm and misc regs in gem5 */
|
||||
mutable std::vector<ArmV8KvmCPU::MiscRegInfo> sysRegMap;
|
||||
|
|
|
@ -79,6 +79,9 @@ BaseArmKvmCPU::startup()
|
|||
memset(&target_config, 0, sizeof(target_config));
|
||||
|
||||
vm.kvmArmPreferredTarget(target_config);
|
||||
if (!((ArmSystem *)system)->highestELIs64()) {
|
||||
target_config.features[0] |= (1 << KVM_ARM_VCPU_EL1_32BIT);
|
||||
}
|
||||
kvmArmVCpuInit(target_config);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2016 ARM Limited
|
||||
* Copyright (c) 2015-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -35,14 +35,17 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Andreas Sandberg
|
||||
* Curtis Dunham
|
||||
*/
|
||||
|
||||
#include "arch/arm/kvm/gic.hh"
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
#include "arch/arm/kvm/base_cpu.hh"
|
||||
#include "debug/GIC.hh"
|
||||
#include "debug/Interrupt.hh"
|
||||
#include "params/KvmGic.hh"
|
||||
#include "params/MuxingKvmGic.hh"
|
||||
|
||||
KvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr,
|
||||
unsigned it_lines)
|
||||
|
@ -102,83 +105,350 @@ KvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
|
|||
vm.setIRQLine(line, high);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
|
||||
{
|
||||
uint64_t reg;
|
||||
|
||||
KvmGic::KvmGic(const KvmGicParams *p)
|
||||
: BaseGic(p),
|
||||
assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
|
||||
const uint32_t attr(
|
||||
(vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
|
||||
(offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
|
||||
|
||||
kdev.getAttrPtr(group, attr, ®);
|
||||
return (uint32_t) reg;
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
|
||||
unsigned value)
|
||||
{
|
||||
uint64_t reg = value;
|
||||
|
||||
assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
|
||||
const uint32_t attr(
|
||||
(vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
|
||||
(offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
|
||||
|
||||
kdev.setAttrPtr(group, attr, ®);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
MuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
|
||||
: Pl390(p),
|
||||
system(*p->system),
|
||||
kernelGic(*p->kvmVM, p->cpu_addr, p->dist_addr, p->it_lines),
|
||||
addrRanges{kernelGic.distRange, kernelGic.cpuRange}
|
||||
kernelGic(nullptr),
|
||||
usingKvm(false)
|
||||
{
|
||||
}
|
||||
|
||||
KvmGic::~KvmGic()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
panic("Checkpointing unsupported\n");
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
panic("Checkpointing unsupported\n");
|
||||
}
|
||||
|
||||
Tick
|
||||
KvmGic::read(PacketPtr pkt)
|
||||
{
|
||||
panic("KvmGic: PIO from gem5 is currently unsupported\n");
|
||||
}
|
||||
|
||||
Tick
|
||||
KvmGic::write(PacketPtr pkt)
|
||||
{
|
||||
panic("KvmGic: PIO from gem5 is currently unsupported\n");
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::sendInt(uint32_t num)
|
||||
{
|
||||
DPRINTF(Interrupt, "Set SPI %d\n", num);
|
||||
kernelGic.setSPI(num);
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::clearInt(uint32_t num)
|
||||
{
|
||||
DPRINTF(Interrupt, "Clear SPI %d\n", num);
|
||||
kernelGic.clearSPI(num);
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::sendPPInt(uint32_t num, uint32_t cpu)
|
||||
{
|
||||
DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
|
||||
kernelGic.setPPI(cpu, num);
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::clearPPInt(uint32_t num, uint32_t cpu)
|
||||
{
|
||||
DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
|
||||
kernelGic.clearPPI(cpu, num);
|
||||
}
|
||||
|
||||
void
|
||||
KvmGic::verifyMemoryMode() const
|
||||
{
|
||||
if (!(system.isAtomicMode() && system.bypassCaches())) {
|
||||
fatal("The in-kernel KVM GIC can only be used with KVM CPUs, but the "
|
||||
"current memory mode does not support KVM.\n");
|
||||
if (auto vm = system.getKvmVM()) {
|
||||
kernelGic = new KvmKernelGicV2(*vm, p->cpu_addr, p->dist_addr,
|
||||
p->it_lines);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
KvmGic *
|
||||
KvmGicParams::create()
|
||||
MuxingKvmGic::~MuxingKvmGic()
|
||||
{
|
||||
return new KvmGic(this);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::loadState(CheckpointIn &cp)
|
||||
{
|
||||
Pl390::loadState(cp);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::startup()
|
||||
{
|
||||
Pl390::startup();
|
||||
usingKvm = (kernelGic != nullptr) && validKvmEnvironment();
|
||||
if (usingKvm)
|
||||
fromPl390ToKvm();
|
||||
}
|
||||
|
||||
DrainState
|
||||
MuxingKvmGic::drain()
|
||||
{
|
||||
if (usingKvm)
|
||||
fromKvmToPl390();
|
||||
return Pl390::drain();
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::drainResume()
|
||||
{
|
||||
Pl390::drainResume();
|
||||
bool use_kvm = (kernelGic != nullptr) && validKvmEnvironment();
|
||||
if (use_kvm != usingKvm) {
|
||||
// Should only occur due to CPU switches
|
||||
if (use_kvm) // from simulation to KVM emulation
|
||||
fromPl390ToKvm();
|
||||
// otherwise, drain() already sync'd the state back to the Pl390
|
||||
|
||||
usingKvm = use_kvm;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
// drain() already ensured Pl390 updated with KvmGic state if necessary
|
||||
Pl390::serialize(cp);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
Pl390::unserialize(cp);
|
||||
}
|
||||
|
||||
Tick
|
||||
MuxingKvmGic::read(PacketPtr pkt)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::read(pkt);
|
||||
|
||||
panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
|
||||
}
|
||||
|
||||
Tick
|
||||
MuxingKvmGic::write(PacketPtr pkt)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::write(pkt);
|
||||
|
||||
panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::sendInt(uint32_t num)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::sendInt(num);
|
||||
|
||||
DPRINTF(Interrupt, "Set SPI %d\n", num);
|
||||
kernelGic->setSPI(num);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearInt(uint32_t num)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::clearInt(num);
|
||||
|
||||
DPRINTF(Interrupt, "Clear SPI %d\n", num);
|
||||
kernelGic->clearSPI(num);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::sendPPInt(uint32_t num, uint32_t cpu)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::sendPPInt(num, cpu);
|
||||
DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
|
||||
kernelGic->setPPI(cpu, num);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearPPInt(uint32_t num, uint32_t cpu)
|
||||
{
|
||||
if (!usingKvm)
|
||||
return Pl390::clearPPInt(num, cpu);
|
||||
|
||||
DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
|
||||
kernelGic->clearPPI(cpu, num);
|
||||
}
|
||||
|
||||
bool
|
||||
MuxingKvmGic::validKvmEnvironment() const
|
||||
{
|
||||
if (system.threadContexts.empty())
|
||||
return false;
|
||||
|
||||
for (auto tc : system.threadContexts) {
|
||||
if (dynamic_cast<BaseArmKvmCPU*>(tc->getCpuPtr()) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto val = from->readDistributor(ctx, daddr);
|
||||
DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
|
||||
to->writeDistributor(ctx, daddr, val);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto val = from->readCpu(ctx, daddr);
|
||||
DPRINTF(GIC, "copy cpu 0x%x 0x%08x\n", daddr, val);
|
||||
to->writeCpu(ctx, daddr, val);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx)
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
copyDistRegister(from, to, ctx, a);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx)
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
to->writeDistributor(ctx, a, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
copyDistRegister(from, to, 0, a);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
to->writeDistributor(0, a, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
|
||||
{
|
||||
Addr set, clear;
|
||||
size_t size;
|
||||
|
||||
/// CPU state (GICC_*)
|
||||
// Copy CPU Interface Control Register (CTLR),
|
||||
// Interrupt Priority Mask Register (PMR), and
|
||||
// Binary Point Register (BPR)
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx) {
|
||||
copyCpuRegister(from, to, ctx, GICC_CTLR);
|
||||
copyCpuRegister(from, to, ctx, GICC_PMR);
|
||||
copyCpuRegister(from, to, ctx, GICC_BPR);
|
||||
}
|
||||
|
||||
|
||||
/// Distributor state (GICD_*)
|
||||
// Copy Distributor Control Register (CTLR)
|
||||
copyDistRegister(from, to, 0, GICD_CTLR);
|
||||
|
||||
// Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISENABLER.start();
|
||||
clear = Pl390::GICD_ICENABLER.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISPENDR.start();
|
||||
clear = Pl390::GICD_ICPENDR.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISACTIVER.start();
|
||||
clear = Pl390::GICD_ICACTIVER.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
|
||||
set = Pl390::GICD_IPRIORITYR.start();
|
||||
copyBankedDistRange(from, to, set, 32);
|
||||
|
||||
set += 32;
|
||||
size = Pl390::itLines - 32;
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
|
||||
set = Pl390::GICD_ITARGETSR.start() + 32;
|
||||
size = Pl390::itLines - 32;
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt configuration registers (ICFGRn)
|
||||
set = Pl390::GICD_ICFGR.start();
|
||||
size = Pl390::itLines / 4;
|
||||
copyDistRange(from, to, set, size);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::fromPl390ToKvm()
|
||||
{
|
||||
copyGicState(static_cast<Pl390*>(this), kernelGic);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::fromKvmToPl390()
|
||||
{
|
||||
copyGicState(kernelGic, static_cast<Pl390*>(this));
|
||||
|
||||
// the values read for the Interrupt Priority Mask Register (PMR)
|
||||
// have been shifted by three bits due to its having been emulated by
|
||||
// a VGIC with only 5 PMR bits in its VMCR register. Presently the
|
||||
// Linux kernel does not repair this inaccuracy, so we correct it here.
|
||||
for (int cpu = 0; cpu < system._numContexts; ++cpu) {
|
||||
cpuPriority[cpu] <<= 3;
|
||||
assert((cpuPriority[cpu] & ~0xff) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
MuxingKvmGic *
|
||||
MuxingKvmGicParams::create()
|
||||
{
|
||||
return new MuxingKvmGic(this);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2016 ARM Limited
|
||||
* Copyright (c) 2015-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -35,6 +35,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Andreas Sandberg
|
||||
* Curtis Dunham
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_KVM_GIC_HH__
|
||||
|
@ -43,7 +44,7 @@
|
|||
#include "arch/arm/system.hh"
|
||||
#include "cpu/kvm/device.hh"
|
||||
#include "cpu/kvm/vm.hh"
|
||||
#include "dev/arm/base_gic.hh"
|
||||
#include "dev/arm/gic_pl390.hh"
|
||||
#include "dev/platform.hh"
|
||||
|
||||
/**
|
||||
|
@ -53,7 +54,7 @@
|
|||
* model. It exposes an API that is similar to that of
|
||||
* software-emulated GIC models in gem5.
|
||||
*/
|
||||
class KvmKernelGicV2
|
||||
class KvmKernelGicV2 : public BaseGicRegisters
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
@ -65,7 +66,7 @@ class KvmKernelGicV2
|
|||
* @param vm KVM VM representing this system
|
||||
* @param cpu_addr GIC CPU interface base address
|
||||
* @param dist_addr GIC distributor base address
|
||||
* @param it_liens Number of interrupt lines to support
|
||||
* @param it_lines Number of interrupt lines to support
|
||||
*/
|
||||
KvmKernelGicV2(KvmVM &vm, Addr cpu_addr, Addr dist_addr,
|
||||
unsigned it_lines);
|
||||
|
@ -116,6 +117,14 @@ class KvmKernelGicV2
|
|||
/** Address range for the distributor interface */
|
||||
const AddrRange distRange;
|
||||
|
||||
/** BaseGicRegisters interface */
|
||||
uint32_t readDistributor(ContextID ctx, Addr daddr) override;
|
||||
uint32_t readCpu(ContextID ctx, Addr daddr) override;
|
||||
|
||||
void writeDistributor(ContextID ctx, Addr daddr,
|
||||
uint32_t data) override;
|
||||
void writeCpu(ContextID ctx, Addr daddr, uint32_t data) override;
|
||||
|
||||
/* @} */
|
||||
|
||||
protected:
|
||||
|
@ -129,6 +138,26 @@ class KvmKernelGicV2
|
|||
*/
|
||||
void setIntState(unsigned type, unsigned vcpu, unsigned irq, bool high);
|
||||
|
||||
/**
|
||||
* Get value of GIC register "from" a cpu
|
||||
*
|
||||
* @param group Distributor or CPU (KVM_DEV_ARM_VGIC_GRP_{DIST,CPU}_REGS)
|
||||
* @param vcpu CPU id within KVM
|
||||
* @param offset register offset
|
||||
*/
|
||||
uint32_t getGicReg(unsigned group, unsigned vcpu, unsigned offset);
|
||||
|
||||
/**
|
||||
* Set value of GIC register "from" a cpu
|
||||
*
|
||||
* @param group Distributor or CPU (KVM_DEV_ARM_VGIC_GRP_{DIST,CPU}_REGS)
|
||||
* @param vcpu CPU id within KVM
|
||||
* @param offset register offset
|
||||
* @param value value to set register to
|
||||
*/
|
||||
void setGicReg(unsigned group, unsigned vcpu, unsigned offset,
|
||||
unsigned value);
|
||||
|
||||
/** KVM VM in the parent system */
|
||||
KvmVM &vm;
|
||||
|
||||
|
@ -136,48 +165,29 @@ class KvmKernelGicV2
|
|||
KvmDevice kdev;
|
||||
};
|
||||
|
||||
struct KvmGicParams;
|
||||
|
||||
/**
|
||||
* In-kernel GIC model.
|
||||
*
|
||||
* When using a KVM-based CPU model, it is possible to offload GIC
|
||||
* emulation to the kernel. This reduces some overheads when the guest
|
||||
* accesses the GIC and makes it possible to use in-kernel
|
||||
* architected/generic timer emulation.
|
||||
*
|
||||
* This device uses interfaces with the kernel GicV2 model that is
|
||||
* documented in Documentation/virtual/kvm/devices/arm-vgic.txt in the
|
||||
* Linux kernel sources.
|
||||
*
|
||||
* This GIC model has the following known limitations:
|
||||
* <ul>
|
||||
* <li>Checkpointing is not supported.
|
||||
* <li>This model only works with kvm. Simulated CPUs are not
|
||||
* supported since this would require the kernel to inject
|
||||
* interrupt into the simulated CPU.
|
||||
* </ul>
|
||||
*
|
||||
* @warn This GIC model cannot be used with simulated CPUs!
|
||||
*/
|
||||
class KvmGic : public BaseGic
|
||||
struct MuxingKvmGicParams;
|
||||
|
||||
class MuxingKvmGic : public Pl390
|
||||
{
|
||||
public: // SimObject / Serializable / Drainable
|
||||
KvmGic(const KvmGicParams *p);
|
||||
~KvmGic();
|
||||
MuxingKvmGic(const MuxingKvmGicParams *p);
|
||||
~MuxingKvmGic();
|
||||
|
||||
void startup() override { verifyMemoryMode(); }
|
||||
void drainResume() override { verifyMemoryMode(); }
|
||||
void loadState(CheckpointIn &cp) override;
|
||||
|
||||
void startup() override;
|
||||
DrainState drain() override;
|
||||
void drainResume() override;
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
public: // PioDevice
|
||||
AddrRangeList getAddrRanges() const { return addrRanges; }
|
||||
Tick read(PacketPtr pkt) override;
|
||||
Tick write(PacketPtr pkt) override;
|
||||
|
||||
public: // BaseGic
|
||||
public: // Pl390
|
||||
void sendInt(uint32_t num) override;
|
||||
void clearInt(uint32_t num) override;
|
||||
|
||||
|
@ -185,24 +195,37 @@ class KvmGic : public BaseGic
|
|||
void clearPPInt(uint32_t num, uint32_t cpu) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Do memory mode sanity checks
|
||||
*
|
||||
* This method only really exists to warn users that try to switch
|
||||
* to a simulate CPU. There is no fool proof method to detect
|
||||
* simulated CPUs, but checking that we're in atomic mode and
|
||||
* bypassing caches should be robust enough.
|
||||
*/
|
||||
void verifyMemoryMode() const;
|
||||
/** Verify gem5 configuration will support KVM emulation */
|
||||
bool validKvmEnvironment() const;
|
||||
|
||||
/** System this interrupt controller belongs to */
|
||||
System &system;
|
||||
|
||||
/** Kernel GIC device */
|
||||
KvmKernelGicV2 kernelGic;
|
||||
KvmKernelGicV2 *kernelGic;
|
||||
|
||||
/** Union of all memory */
|
||||
const AddrRangeList addrRanges;
|
||||
private:
|
||||
bool usingKvm;
|
||||
|
||||
/** Multiplexing implementation */
|
||||
void fromPl390ToKvm();
|
||||
void fromKvmToPl390();
|
||||
|
||||
void copyGicState(BaseGicRegisters* from, BaseGicRegisters* to);
|
||||
|
||||
void copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr);
|
||||
void copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr);
|
||||
|
||||
void copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void clearBankedDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void clearDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
};
|
||||
|
||||
#endif // __ARCH_ARM_KVM_GIC_HH__
|
||||
|
|
|
@ -61,7 +61,7 @@ using namespace ArmISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc32(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc32(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -79,7 +79,7 @@ unameFunc32(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc64(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc64(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -97,7 +97,7 @@ unameFunc64(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
|
||||
/// Target set_tls() handler.
|
||||
static SyscallReturn
|
||||
setTLSFunc32(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
setTLSFunc32(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -110,7 +110,7 @@ setTLSFunc32(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
}
|
||||
|
||||
static SyscallReturn
|
||||
setTLSFunc64(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
setTLSFunc64(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -241,7 +241,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 117 */ SyscallDesc("ipc", unimplementedFunc),
|
||||
/* 118 */ SyscallDesc("fsync", unimplementedFunc),
|
||||
/* 119 */ SyscallDesc("sigreturn", unimplementedFunc),
|
||||
/* 120 */ SyscallDesc("clone", cloneFunc),
|
||||
/* 120 */ SyscallDesc("clone", cloneFunc<ArmLinux32>),
|
||||
/* 121 */ SyscallDesc("setdomainname", unimplementedFunc),
|
||||
/* 122 */ SyscallDesc("uname", unameFunc32),
|
||||
/* 123 */ SyscallDesc("unused#123", unimplementedFunc),
|
||||
|
@ -1589,9 +1589,9 @@ static SyscallDesc privSyscallDescs64[] = {
|
|||
/* 5 */ SyscallDesc("set_tls", setTLSFunc64)
|
||||
};
|
||||
|
||||
ArmLinuxProcess32::ArmLinuxProcess32(LiveProcessParams * params,
|
||||
ArmLinuxProcess32::ArmLinuxProcess32(ProcessParams * params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess32(params, objFile, _arch)
|
||||
: ArmProcess32(params, objFile, _arch)
|
||||
{
|
||||
SyscallTable table;
|
||||
|
||||
|
@ -1608,9 +1608,9 @@ ArmLinuxProcess32::ArmLinuxProcess32(LiveProcessParams * params,
|
|||
syscallTables.push_back(table);
|
||||
}
|
||||
|
||||
ArmLinuxProcess64::ArmLinuxProcess64(LiveProcessParams * params,
|
||||
ArmLinuxProcess64::ArmLinuxProcess64(ProcessParams * params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess64(params, objFile, _arch)
|
||||
: ArmProcess64(params, objFile, _arch)
|
||||
{
|
||||
SyscallTable table;
|
||||
|
||||
|
@ -1667,7 +1667,7 @@ ArmLinuxProcess64::getDesc(int callnum)
|
|||
void
|
||||
ArmLinuxProcess32::initState()
|
||||
{
|
||||
ArmLiveProcess32::initState();
|
||||
ArmProcess32::initState();
|
||||
allocateMem(commPage, PageBytes);
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
|
||||
|
@ -1714,6 +1714,6 @@ ArmLinuxProcess32::initState()
|
|||
void
|
||||
ArmLinuxProcess64::initState()
|
||||
{
|
||||
ArmLiveProcess64::initState();
|
||||
ArmProcess64::initState();
|
||||
// The 64 bit equivalent of the comm page would be set up here.
|
||||
}
|
||||
|
|
|
@ -65,16 +65,16 @@ class ArmLinuxProcessBits
|
|||
};
|
||||
|
||||
/// A process with emulated Arm/Linux syscalls.
|
||||
class ArmLinuxProcess32 : public ArmLiveProcess32, public ArmLinuxProcessBits
|
||||
class ArmLinuxProcess32 : public ArmProcess32, public ArmLinuxProcessBits
|
||||
{
|
||||
public:
|
||||
ArmLinuxProcess32(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ArmLinuxProcess32(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using ArmLiveProcess::getSyscallArg;
|
||||
using ArmProcess::getSyscallArg;
|
||||
|
||||
/// A page to hold "kernel" provided functions. The name might be wrong.
|
||||
static const Addr commPage;
|
||||
|
@ -83,10 +83,10 @@ class ArmLinuxProcess32 : public ArmLiveProcess32, public ArmLinuxProcessBits
|
|||
};
|
||||
|
||||
/// A process with emulated Arm/Linux syscalls.
|
||||
class ArmLinuxProcess64 : public ArmLiveProcess64, public ArmLinuxProcessBits
|
||||
class ArmLinuxProcess64 : public ArmProcess64, public ArmLinuxProcessBits
|
||||
{
|
||||
public:
|
||||
ArmLinuxProcess64(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ArmLinuxProcess64(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013, 2015-2016 ARM Limited
|
||||
* Copyright (c) 2010-2013, 2015-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -41,6 +41,8 @@
|
|||
|
||||
#include "arch/arm/miscregs.hh"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "arch/arm/isa.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
@ -1967,11 +1969,12 @@ decodeCP15Reg64(unsigned crm, unsigned opc1)
|
|||
return MISCREG_CP15_UNIMPL;
|
||||
}
|
||||
|
||||
bool
|
||||
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||
std::tuple<bool, bool>
|
||||
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||
{
|
||||
bool secure = !scr.ns;
|
||||
bool canRead;
|
||||
bool canRead = false;
|
||||
bool undefined = false;
|
||||
|
||||
switch (cpsr.mode) {
|
||||
case MODE_USER:
|
||||
|
@ -1995,18 +1998,19 @@ canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
|||
canRead = miscRegInfo[reg][MISCREG_HYP_RD];
|
||||
break;
|
||||
default:
|
||||
panic("Unrecognized mode setting in CPSR.\n");
|
||||
undefined = true;
|
||||
}
|
||||
// can't do permissions checkes on the root of a banked pair of regs
|
||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||
return canRead;
|
||||
return std::make_tuple(canRead, undefined);
|
||||
}
|
||||
|
||||
bool
|
||||
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||
std::tuple<bool, bool>
|
||||
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||
{
|
||||
bool secure = !scr.ns;
|
||||
bool canWrite;
|
||||
bool canWrite = false;
|
||||
bool undefined = false;
|
||||
|
||||
switch (cpsr.mode) {
|
||||
case MODE_USER:
|
||||
|
@ -2030,11 +2034,11 @@ canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
|||
canWrite = miscRegInfo[reg][MISCREG_HYP_WR];
|
||||
break;
|
||||
default:
|
||||
panic("Unrecognized mode setting in CPSR.\n");
|
||||
undefined = true;
|
||||
}
|
||||
// can't do permissions checkes on the root of a banked pair of regs
|
||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||
return canWrite;
|
||||
return std::make_tuple(canWrite, undefined);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2016 ARM Limited
|
||||
* Copyright (c) 2010-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -44,6 +44,7 @@
|
|||
#define __ARCH_ARM_MISCREGS_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <tuple>
|
||||
|
||||
#include "base/bitunion.hh"
|
||||
#include "base/compiler.hh"
|
||||
|
@ -1847,13 +1848,37 @@ namespace ArmISA
|
|||
EndBitUnion(CPTR)
|
||||
|
||||
|
||||
// Checks read access permissions to coproc. registers
|
||||
bool canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
ThreadContext *tc);
|
||||
/**
|
||||
* Check for permission to read coprocessor registers.
|
||||
*
|
||||
* Checks whether an instruction at the current program mode has
|
||||
* permissions to read the coprocessor registers. This function
|
||||
* returns whether the check is undefined and if not whether the
|
||||
* read access is permitted.
|
||||
*
|
||||
* @param the misc reg indicating the coprocessor
|
||||
* @param the SCR
|
||||
* @param the CPSR
|
||||
* @return a tuple of booleans: can_read, undefined
|
||||
*/
|
||||
std::tuple<bool, bool> canReadCoprocReg(MiscRegIndex reg, SCR scr,
|
||||
CPSR cpsr);
|
||||
|
||||
// Checks write access permissions to coproc. registers
|
||||
bool canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
ThreadContext *tc);
|
||||
/**
|
||||
* Check for permission to write coprocessor registers.
|
||||
*
|
||||
* Checks whether an instruction at the current program mode has
|
||||
* permissions to write the coprocessor registers. This function
|
||||
* returns whether the check is undefined and if not whether the
|
||||
* write access is permitted.
|
||||
*
|
||||
* @param the misc reg indicating the coprocessor
|
||||
* @param the SCR
|
||||
* @param the CPSR
|
||||
* @return a tuple of booleans: can_write, undefined
|
||||
*/
|
||||
std::tuple<bool, bool> canWriteCoprocReg(MiscRegIndex reg, SCR scr,
|
||||
CPSR cpsr);
|
||||
|
||||
// Checks read access permissions to AArch64 system registers
|
||||
bool canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Stack.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
|
@ -59,50 +60,46 @@
|
|||
using namespace std;
|
||||
using namespace ArmISA;
|
||||
|
||||
ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: LiveProcess(params, objFile), arch(_arch)
|
||||
ArmProcess::ArmProcess(ProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: Process(params, objFile), arch(_arch)
|
||||
{
|
||||
}
|
||||
|
||||
ArmLiveProcess32::ArmLiveProcess32(LiveProcessParams *params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess(params, objFile, _arch)
|
||||
ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: ArmProcess(params, objFile, _arch)
|
||||
{
|
||||
stack_base = 0xbf000000L;
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr stack_base = 0xbf000000L;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
Addr mmap_end = 0x40000000L;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set up region for mmaps. For now, start at bottom of kuseg space.
|
||||
mmap_end = 0x40000000L;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
ArmLiveProcess64::ArmLiveProcess64(LiveProcessParams *params,
|
||||
ObjectFile *objFile, ObjectFile::Arch _arch)
|
||||
: ArmLiveProcess(params, objFile, _arch)
|
||||
ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: ArmProcess(params, objFile, _arch)
|
||||
{
|
||||
stack_base = 0x7fffff0000L;
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr stack_base = 0x7fffff0000L;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
Addr mmap_end = 0x4000000000L;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set up region for mmaps. For now, start at bottom of kuseg space.
|
||||
mmap_end = 0x4000000000L;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
ArmLiveProcess32::initState()
|
||||
ArmProcess32::initState()
|
||||
{
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
argsInit<uint32_t>(PageBytes, INTREG_SP);
|
||||
for (int i = 0; i < contextIds.size(); i++) {
|
||||
ThreadContext * tc = system->getThreadContext(contextIds[i]);
|
||||
|
@ -119,9 +116,9 @@ ArmLiveProcess32::initState()
|
|||
}
|
||||
|
||||
void
|
||||
ArmLiveProcess64::initState()
|
||||
ArmProcess64::initState()
|
||||
{
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
argsInit<uint64_t>(PageBytes, INTREG_SP0);
|
||||
for (int i = 0; i < contextIds.size(); i++) {
|
||||
ThreadContext * tc = system->getThreadContext(contextIds[i]);
|
||||
|
@ -142,7 +139,7 @@ ArmLiveProcess64::initState()
|
|||
|
||||
template <class IntType>
|
||||
void
|
||||
ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
||||
ArmProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
||||
{
|
||||
int intSize = sizeof(IntType);
|
||||
|
||||
|
@ -299,15 +296,16 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
|||
|
||||
int space_needed = frame_size + aux_padding;
|
||||
|
||||
stack_min = stack_base - space_needed;
|
||||
stack_min = roundDown(stack_min, align);
|
||||
stack_size = stack_base - stack_min;
|
||||
memState->setStackMin(memState->getStackBase() - space_needed);
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), align));
|
||||
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
|
||||
|
||||
// map memory
|
||||
allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
|
||||
allocateMem(roundDown(memState->getStackMin(), pageSize),
|
||||
roundUp(memState->getStackSize(), pageSize));
|
||||
|
||||
// map out initial stack contents
|
||||
IntType sentry_base = stack_base - sentry_size;
|
||||
IntType sentry_base = memState->getStackBase() - sentry_size;
|
||||
IntType aux_data_base = sentry_base - aux_data_size;
|
||||
IntType env_data_base = aux_data_base - env_data_size;
|
||||
IntType arg_data_base = env_data_base - arg_data_size;
|
||||
|
@ -328,7 +326,7 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
|||
DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
|
||||
DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
|
||||
DPRINTF(Stack, "0x%x - argc \n", argc_base);
|
||||
DPRINTF(Stack, "0x%x - stack min\n", stack_min);
|
||||
DPRINTF(Stack, "0x%x - stack min\n", memState->getStackMin());
|
||||
|
||||
// write contents to stack
|
||||
|
||||
|
@ -374,7 +372,7 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
|||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
//Set the stack pointer register
|
||||
tc->setIntReg(spIndex, stack_min);
|
||||
tc->setIntReg(spIndex, memState->getStackMin());
|
||||
//A pointer to a function to run when the program exits. We'll set this
|
||||
//to zero explicitly to make sure this isn't used.
|
||||
tc->setIntReg(ArgumentReg0, 0);
|
||||
|
@ -400,26 +398,26 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
|||
pc.set(getStartPC() & ~mask(1));
|
||||
tc->pcState(pc);
|
||||
|
||||
//Align the "stack_min" to a page boundary.
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
//Align the "stackMin" to a page boundary.
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
|
||||
}
|
||||
|
||||
ArmISA::IntReg
|
||||
ArmLiveProcess32::getSyscallArg(ThreadContext *tc, int &i)
|
||||
ArmProcess32::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 6);
|
||||
return tc->readIntReg(ArgumentReg0 + i++);
|
||||
}
|
||||
|
||||
ArmISA::IntReg
|
||||
ArmLiveProcess64::getSyscallArg(ThreadContext *tc, int &i)
|
||||
ArmProcess64::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 8);
|
||||
return tc->readIntReg(ArgumentReg0 + i++);
|
||||
}
|
||||
|
||||
ArmISA::IntReg
|
||||
ArmLiveProcess32::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
ArmProcess32::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
{
|
||||
assert(width == 32 || width == 64);
|
||||
if (width == 32)
|
||||
|
@ -438,29 +436,28 @@ ArmLiveProcess32::getSyscallArg(ThreadContext *tc, int &i, int width)
|
|||
}
|
||||
|
||||
ArmISA::IntReg
|
||||
ArmLiveProcess64::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
ArmProcess64::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
{
|
||||
return getSyscallArg(tc, i);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ArmLiveProcess32::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val)
|
||||
ArmProcess32::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val)
|
||||
{
|
||||
assert(i < 6);
|
||||
tc->setIntReg(ArgumentReg0 + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
ArmLiveProcess64::setSyscallArg(ThreadContext *tc,
|
||||
int i, ArmISA::IntReg val)
|
||||
ArmProcess64::setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val)
|
||||
{
|
||||
assert(i < 8);
|
||||
tc->setIntReg(ArgumentReg0 + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
ArmLiveProcess32::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
ArmProcess32::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
|
||||
if (objFile->getOpSys() == ObjectFile::FreeBSD) {
|
||||
|
@ -477,7 +474,7 @@ ArmLiveProcess32::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
|||
}
|
||||
|
||||
void
|
||||
ArmLiveProcess64::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
ArmProcess64::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
|
||||
if (objFile->getOpSys() == ObjectFile::FreeBSD) {
|
||||
|
|
|
@ -51,25 +51,23 @@
|
|||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class LiveProcess;
|
||||
class ObjectFile;
|
||||
class System;
|
||||
|
||||
class ArmLiveProcess : public LiveProcess
|
||||
class ArmProcess : public Process
|
||||
{
|
||||
protected:
|
||||
ObjectFile::Arch arch;
|
||||
ArmLiveProcess(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
ArmProcess(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
template<class IntType>
|
||||
void argsInit(int pageSize, ArmISA::IntRegIndex spIndex);
|
||||
};
|
||||
|
||||
class ArmLiveProcess32 : public ArmLiveProcess
|
||||
class ArmProcess32 : public ArmProcess
|
||||
{
|
||||
protected:
|
||||
ArmLiveProcess32(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
ArmProcess32(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
|
||||
|
@ -81,11 +79,11 @@ class ArmLiveProcess32 : public ArmLiveProcess
|
|||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
};
|
||||
|
||||
class ArmLiveProcess64 : public ArmLiveProcess
|
||||
class ArmProcess64 : public ArmProcess
|
||||
{
|
||||
protected:
|
||||
ArmLiveProcess64(LiveProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
ArmProcess64(ProcessParams * params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch);
|
||||
|
||||
void initState();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2012-2016 ARM Limited
|
||||
* Copyright (c) 2010, 2012-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -1342,7 +1342,10 @@ TableWalker::memAttrsAArch64(ThreadContext *tc, TlbEntry &te,
|
|||
attr_hi == 2 ? 2 : 1;
|
||||
te.innerAttrs = attr_lo == 1 ? 0 :
|
||||
attr_lo == 2 ? 6 : 5;
|
||||
te.nonCacheable = (attr_hi == 1) || (attr_lo == 1);
|
||||
// Treat write-through memory as uncacheable, this is safe
|
||||
// but for performance reasons not optimal.
|
||||
te.nonCacheable = (attr_hi == 1) || (attr_hi == 2) ||
|
||||
(attr_lo == 1) || (attr_lo == 2);
|
||||
}
|
||||
} else {
|
||||
uint8_t attrIndx = lDescriptor.attrIndx();
|
||||
|
@ -1377,9 +1380,25 @@ TableWalker::memAttrsAArch64(ThreadContext *tc, TlbEntry &te,
|
|||
|
||||
// Cacheability
|
||||
te.nonCacheable = false;
|
||||
if (te.mtype == TlbEntry::MemoryType::Device || // Device memory
|
||||
attr_hi == 0x8 || // Normal memory, Outer Non-cacheable
|
||||
attr_lo == 0x8) { // Normal memory, Inner Non-cacheable
|
||||
if (te.mtype == TlbEntry::MemoryType::Device) { // Device memory
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
// Treat write-through memory as uncacheable, this is safe
|
||||
// but for performance reasons not optimal.
|
||||
switch (attr_hi) {
|
||||
case 0x1 ... 0x3: // Normal Memory, Outer Write-through transient
|
||||
case 0x4: // Normal memory, Outer Non-cacheable
|
||||
case 0x8 ... 0xb: // Normal Memory, Outer Write-through non-transient
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
switch (attr_lo) {
|
||||
case 0x1 ... 0x3: // Normal Memory, Inner Write-through transient
|
||||
case 0x9 ... 0xb: // Normal Memory, Inner Write-through non-transient
|
||||
warn_if(!attr_hi, "Unpredictable behavior");
|
||||
case 0x4: // Device-nGnRE memory or
|
||||
// Normal memory, Inner Non-cacheable
|
||||
case 0x8: // Device-nGRE memory or
|
||||
// Normal memory, Inner Write-through non-transient
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013, 2016 ARM Limited
|
||||
* Copyright (c) 2010-2013, 2016-2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -642,12 +642,15 @@ TLB::checkPermissions(TlbEntry *te, RequestPtr req, Mode mode)
|
|||
DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x"
|
||||
" domain: %#x write:%d\n", dacr,
|
||||
static_cast<uint8_t>(te->domain), is_write);
|
||||
if (is_fetch)
|
||||
if (is_fetch) {
|
||||
// Use PC value instead of vaddr because vaddr might
|
||||
// be aligned to cache line and should not be the
|
||||
// address reported in FAR
|
||||
return std::make_shared<PrefetchAbort>(
|
||||
vaddr,
|
||||
req->getPC(),
|
||||
ArmFault::DomainLL + te->lookupLevel,
|
||||
isStage2, tranMethod);
|
||||
else
|
||||
} else
|
||||
return std::make_shared<DataAbort>(
|
||||
vaddr, te->domain, is_write,
|
||||
ArmFault::DomainLL + te->lookupLevel,
|
||||
|
@ -735,8 +738,10 @@ TLB::checkPermissions(TlbEntry *te, RequestPtr req, Mode mode)
|
|||
DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d "
|
||||
"priv:%d write:%d ns:%d sif:%d sctlr.afe: %d \n",
|
||||
ap, is_priv, is_write, te->ns, scr.sif,sctlr.afe);
|
||||
// Use PC value instead of vaddr because vaddr might be aligned to
|
||||
// cache line and should not be the address reported in FAR
|
||||
return std::make_shared<PrefetchAbort>(
|
||||
vaddr,
|
||||
req->getPC(),
|
||||
ArmFault::PermissionLL + te->lookupLevel,
|
||||
isStage2, tranMethod);
|
||||
} else if (abt | hapAbt) {
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
#ifndef __ARCH_GENERIC_MEMHELPERS_HH__
|
||||
#define __ARCH_GENERIC_MEMHELPERS_HH__
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "base/types.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
#include "sim/insttracer.hh"
|
||||
|
|
|
@ -148,6 +148,12 @@ class SimplePCState : public PCStateBase
|
|||
npc(val + sizeof(MachInst));
|
||||
};
|
||||
|
||||
void
|
||||
setNPC(Addr val)
|
||||
{
|
||||
npc(val);
|
||||
}
|
||||
|
||||
SimplePCState() {}
|
||||
SimplePCState(Addr val) { set(val); }
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
#include "base/misc.hh"
|
||||
#include "gpu-compute/misc.hh"
|
||||
|
||||
class Wavefront;
|
||||
|
||||
namespace HsailISA
|
||||
{
|
||||
typedef uint64_t MiscReg;
|
||||
|
@ -51,7 +49,7 @@ namespace HsailISA
|
|||
class GPUISA
|
||||
{
|
||||
public:
|
||||
GPUISA(Wavefront &wf) : wavefront(wf)
|
||||
GPUISA()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -74,9 +72,6 @@ namespace HsailISA
|
|||
{
|
||||
return old_pc + sizeof(RawMachInst);
|
||||
}
|
||||
|
||||
private:
|
||||
Wavefront &wavefront;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace HsailISA
|
|||
{
|
||||
public:
|
||||
HsailGPUStaticInst(const BrigObject *obj, const std::string &opcode);
|
||||
void generateDisassembly();
|
||||
void generateDisassembly() override;
|
||||
int instSize() const override { return sizeof(RawMachInst); }
|
||||
bool isValid() const override { return true; }
|
||||
|
||||
|
|
|
@ -1318,8 +1318,6 @@ class ISAParser(Grammar):
|
|||
print >>f, '#if !defined(__SPLIT) || (__SPLIT == 1)'
|
||||
self.splits[f] = 1
|
||||
# ensure requisite #include's
|
||||
elif filename in ['decoder-g.cc.inc', 'exec-g.cc.inc']:
|
||||
print >>f, '#include "decoder.hh"'
|
||||
elif filename == 'decoder-g.hh.inc':
|
||||
print >>f, '#include "base/bitfield.hh"'
|
||||
|
||||
|
@ -1360,12 +1358,15 @@ class ISAParser(Grammar):
|
|||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
fn = 'decoder.hh'
|
||||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
fn = 'decode-method.cc.inc'
|
||||
# is guaranteed to have been written for parse to complete
|
||||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
inc.append("decoder.hh")
|
||||
print >>dep, file+':', ' '.join(inc)
|
||||
|
||||
extn = re.compile('(\.[^\.]+)$')
|
||||
|
@ -1386,6 +1387,10 @@ class ISAParser(Grammar):
|
|||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
fn = 'decoder.hh'
|
||||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
fn = 'decoder-ns.cc.inc'
|
||||
assert(fn in self.files)
|
||||
print >>f, 'namespace %s {' % self.namespace
|
||||
|
@ -1395,7 +1400,6 @@ class ISAParser(Grammar):
|
|||
print >>f, '}'
|
||||
inc.append(fn)
|
||||
|
||||
inc.append("decoder.hh")
|
||||
print >>dep, file+':', ' '.join(inc)
|
||||
|
||||
# instruction execution per-CPU model
|
||||
|
@ -1416,6 +1420,10 @@ class ISAParser(Grammar):
|
|||
|
||||
f.write(cpu.includes+"\n")
|
||||
|
||||
fn = 'decoder.hh'
|
||||
f.write('#include "%s"\n' % fn)
|
||||
inc.append(fn)
|
||||
|
||||
fn = 'exec-ns.cc.inc'
|
||||
assert(fn in self.files)
|
||||
print >>f, 'namespace %s {' % self.namespace
|
||||
|
|
|
@ -164,7 +164,7 @@ decode OPCODE_HI default Unknown::unknown() {
|
|||
0x2: movz({{ Rd = (Rt == 0) ? Rs : Rd; }});
|
||||
0x3: movn({{ Rd = (Rt != 0) ? Rs : Rd; }});
|
||||
0x4: decode FullSystemInt {
|
||||
0: syscall_se({{ xc->syscall(R2); }},
|
||||
0: syscall_se({{ xc->syscall(R2, &fault); }},
|
||||
IsSerializeAfter, IsNonSpeculative);
|
||||
default: syscall({{ fault = std::make_shared<SystemCallFault>(); }});
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ using namespace MipsISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -69,7 +69,7 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
/// borrowed from Tru64, the subcases that get used appear to be
|
||||
/// different in practice from those used by Tru64 processes.
|
||||
static SyscallReturn
|
||||
sys_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -98,7 +98,7 @@ sys_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
|
||||
/// Target sys_setsysinfo() handler.
|
||||
static SyscallReturn
|
||||
sys_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
sys_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -128,7 +128,7 @@ sys_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
}
|
||||
|
||||
static SyscallReturn
|
||||
setThreadAreaFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
setThreadAreaFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -460,10 +460,10 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
|
|||
/* 319 */ SyscallDesc("eventfd", unimplementedFunc)
|
||||
};
|
||||
|
||||
MipsLinuxProcess::MipsLinuxProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: MipsLiveProcess(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
MipsLinuxProcess::MipsLinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: MipsProcess(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
{ }
|
||||
|
||||
SyscallDesc*
|
||||
|
|
|
@ -37,11 +37,11 @@
|
|||
#include "sim/eventq.hh"
|
||||
|
||||
/// A process with emulated Mips/Linux syscalls.
|
||||
class MipsLinuxProcess : public MipsLiveProcess
|
||||
class MipsLinuxProcess : public MipsProcess
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
MipsLinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
MipsLinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
virtual SyscallDesc* getDesc(int callnum);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Loader.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
|
@ -47,36 +48,41 @@
|
|||
using namespace std;
|
||||
using namespace MipsISA;
|
||||
|
||||
MipsLiveProcess::MipsLiveProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: LiveProcess(params, objFile)
|
||||
MipsProcess::MipsProcess(ProcessParams * params, ObjectFile *objFile)
|
||||
: Process(params, objFile)
|
||||
{
|
||||
// Set up stack. On MIPS, stack starts at the top of kuseg
|
||||
// user address space. MIPS stack grows down from here
|
||||
stack_base = 0x7FFFFFFF;
|
||||
Addr stack_base = 0x7FFFFFFF;
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set up region for mmaps. Start it 1GB above the top of the heap.
|
||||
mmap_end = brk_point + 0x40000000L;
|
||||
Addr mmap_end = brk_point + 0x40000000L;
|
||||
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
MipsLiveProcess::initState()
|
||||
MipsProcess::initState()
|
||||
{
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
|
||||
argsInit<uint32_t>(PageBytes);
|
||||
}
|
||||
|
||||
template<class IntType>
|
||||
void
|
||||
MipsLiveProcess::argsInit(int pageSize)
|
||||
MipsProcess::argsInit(int pageSize)
|
||||
{
|
||||
int intSize = sizeof(IntType);
|
||||
|
||||
|
@ -140,15 +146,16 @@ MipsLiveProcess::argsInit(int pageSize)
|
|||
env_data_size;
|
||||
|
||||
// set bottom of stack
|
||||
stack_min = stack_base - space_needed;
|
||||
memState->setStackMin(memState->getStackBase() - space_needed);
|
||||
// align it
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
stack_size = stack_base - stack_min;
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
|
||||
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
|
||||
// map memory
|
||||
allocateMem(stack_min, roundUp(stack_size, pageSize));
|
||||
allocateMem(memState->getStackMin(), roundUp(memState->getStackSize(),
|
||||
pageSize));
|
||||
|
||||
// map out initial stack contents
|
||||
IntType argv_array_base = stack_min + intSize; // room for argc
|
||||
// map out initial stack contents; leave room for argc
|
||||
IntType argv_array_base = memState->getStackMin() + intSize;
|
||||
IntType envp_array_base = argv_array_base + argv_array_size;
|
||||
IntType auxv_array_base = envp_array_base + envp_array_size;
|
||||
IntType arg_data_base = auxv_array_base + auxv_array_size;
|
||||
|
@ -159,7 +166,7 @@ MipsLiveProcess::argsInit(int pageSize)
|
|||
|
||||
argc = htog((IntType)argc);
|
||||
|
||||
initVirtMem.writeBlob(stack_min, (uint8_t*)&argc, intSize);
|
||||
initVirtMem.writeBlob(memState->getStackMin(), (uint8_t*)&argc, intSize);
|
||||
|
||||
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
|
||||
|
||||
|
@ -184,29 +191,28 @@ MipsLiveProcess::argsInit(int pageSize)
|
|||
|
||||
setSyscallArg(tc, 0, argc);
|
||||
setSyscallArg(tc, 1, argv_array_base);
|
||||
tc->setIntReg(StackPointerReg, stack_min);
|
||||
tc->setIntReg(StackPointerReg, memState->getStackMin());
|
||||
|
||||
tc->pcState(getStartPC());
|
||||
}
|
||||
|
||||
|
||||
MipsISA::IntReg
|
||||
MipsLiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
MipsProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 6);
|
||||
return tc->readIntReg(FirstArgumentReg + i++);
|
||||
}
|
||||
|
||||
void
|
||||
MipsLiveProcess::setSyscallArg(ThreadContext *tc,
|
||||
int i, MipsISA::IntReg val)
|
||||
MipsProcess::setSyscallArg(ThreadContext *tc, int i, MipsISA::IntReg val)
|
||||
{
|
||||
assert(i < 6);
|
||||
tc->setIntReg(FirstArgumentReg + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
MipsLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
MipsProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
if (sysret.successful()) {
|
||||
// no error
|
||||
|
|
|
@ -38,14 +38,12 @@
|
|||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class LiveProcess;
|
||||
class ObjectFile;
|
||||
class System;
|
||||
|
||||
class MipsLiveProcess : public LiveProcess
|
||||
class MipsProcess : public Process
|
||||
{
|
||||
protected:
|
||||
MipsLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
MipsProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
void initState();
|
||||
|
||||
|
@ -55,7 +53,7 @@ class MipsLiveProcess : public LiveProcess
|
|||
public:
|
||||
MipsISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, MipsISA::IntReg val);
|
||||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
};
|
||||
|
|
|
@ -512,7 +512,7 @@ decode OPCODE default Unknown::unknown() {
|
|||
55: stfdu({{ Mem_df = Fs; }});
|
||||
}
|
||||
|
||||
17: IntOp::sc({{ xc->syscall(R0); }},
|
||||
17: IntOp::sc({{ xc->syscall(R0, &fault); }},
|
||||
[ IsSyscall, IsNonSpeculative, IsSerializeAfter ]);
|
||||
|
||||
format FloatArithOp {
|
||||
|
|
|
@ -49,7 +49,7 @@ using namespace PowerISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -415,10 +415,10 @@ SyscallDesc PowerLinuxProcess::syscallDescs[] = {
|
|||
/* 346 */ SyscallDesc("epoll_pwait", unimplementedFunc),
|
||||
};
|
||||
|
||||
PowerLinuxProcess::PowerLinuxProcess(LiveProcessParams * params,
|
||||
PowerLinuxProcess::PowerLinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: PowerLiveProcess(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
: PowerProcess(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -434,7 +434,7 @@ PowerLinuxProcess::getDesc(int callnum)
|
|||
void
|
||||
PowerLinuxProcess::initState()
|
||||
{
|
||||
PowerLiveProcess::initState();
|
||||
PowerProcess::initState();
|
||||
}
|
||||
|
||||
PowerISA::IntReg
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
#include "arch/power/process.hh"
|
||||
|
||||
/// A process with emulated PPC/Linux syscalls.
|
||||
class PowerLinuxProcess : public PowerLiveProcess
|
||||
class PowerLinuxProcess : public PowerProcess
|
||||
{
|
||||
public:
|
||||
PowerLinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
PowerLinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
virtual SyscallDesc* getDesc(int callnum);
|
||||
|
||||
|
@ -47,7 +47,7 @@ class PowerLinuxProcess : public PowerLiveProcess
|
|||
|
||||
PowerISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, PowerISA::IntReg val);
|
||||
|
||||
/// Array of syscall descriptors, indexed by call number.
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Stack.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
#include "sim/system.hh"
|
||||
|
@ -47,25 +48,30 @@
|
|||
using namespace std;
|
||||
using namespace PowerISA;
|
||||
|
||||
PowerLiveProcess::PowerLiveProcess(LiveProcessParams *params,
|
||||
ObjectFile *objFile)
|
||||
: LiveProcess(params, objFile)
|
||||
PowerProcess::PowerProcess(ProcessParams *params, ObjectFile *objFile)
|
||||
: Process(params, objFile)
|
||||
{
|
||||
stack_base = 0xbf000000L;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
Addr stack_base = 0xbf000000L;
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up region for mmaps. For now, start at bottom of kuseg space.
|
||||
mmap_end = 0x70000000L;
|
||||
Addr mmap_end = 0x70000000L;
|
||||
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
PowerLiveProcess::initState()
|
||||
PowerProcess::initState()
|
||||
{
|
||||
Process::initState();
|
||||
|
||||
|
@ -73,7 +79,7 @@ PowerLiveProcess::initState()
|
|||
}
|
||||
|
||||
void
|
||||
PowerLiveProcess::argsInit(int intSize, int pageSize)
|
||||
PowerProcess::argsInit(int intSize, int pageSize)
|
||||
{
|
||||
typedef AuxVector<uint32_t> auxv_t;
|
||||
std::vector<auxv_t> auxv;
|
||||
|
@ -185,15 +191,17 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
|
|||
|
||||
int space_needed = frame_size + aux_padding;
|
||||
|
||||
stack_min = stack_base - space_needed;
|
||||
Addr stack_min = memState->getStackBase() - space_needed;
|
||||
stack_min = roundDown(stack_min, align);
|
||||
stack_size = stack_base - stack_min;
|
||||
|
||||
memState->setStackSize(memState->getStackBase() - stack_min);
|
||||
|
||||
// map memory
|
||||
allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
|
||||
allocateMem(roundDown(stack_min, pageSize),
|
||||
roundUp(memState->getStackSize(), pageSize));
|
||||
|
||||
// map out initial stack contents
|
||||
uint32_t sentry_base = stack_base - sentry_size;
|
||||
uint32_t sentry_base = memState->getStackBase() - sentry_size;
|
||||
uint32_t aux_data_base = sentry_base - aux_data_size;
|
||||
uint32_t env_data_base = aux_data_base - env_data_size;
|
||||
uint32_t arg_data_base = env_data_base - arg_data_size;
|
||||
|
@ -262,26 +270,25 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
|
|||
tc->pcState(getStartPC());
|
||||
|
||||
//Align the "stack_min" to a page boundary.
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
memState->setStackMin(roundDown(stack_min, pageSize));
|
||||
}
|
||||
|
||||
PowerISA::IntReg
|
||||
PowerLiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
PowerProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 5);
|
||||
return tc->readIntReg(ArgumentReg0 + i++);
|
||||
}
|
||||
|
||||
void
|
||||
PowerLiveProcess::setSyscallArg(ThreadContext *tc,
|
||||
int i, PowerISA::IntReg val)
|
||||
PowerProcess::setSyscallArg(ThreadContext *tc, int i, PowerISA::IntReg val)
|
||||
{
|
||||
assert(i < 5);
|
||||
tc->setIntReg(ArgumentReg0 + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
PowerLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
PowerProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
Cr cr = tc->readIntReg(INTREG_CR);
|
||||
if (sysret.successful()) {
|
||||
|
|
|
@ -39,14 +39,12 @@
|
|||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class LiveProcess;
|
||||
class ObjectFile;
|
||||
class System;
|
||||
|
||||
class PowerLiveProcess : public LiveProcess
|
||||
class PowerProcess : public Process
|
||||
{
|
||||
protected:
|
||||
PowerLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
PowerProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
void initState();
|
||||
|
||||
|
@ -54,7 +52,7 @@ class PowerLiveProcess : public LiveProcess
|
|||
void argsInit(int intSize, int pageSize);
|
||||
PowerISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, PowerISA::IntReg val);
|
||||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
};
|
||||
|
|
|
@ -87,5 +87,6 @@ BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
void
|
||||
SyscallFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
||||
{
|
||||
tc->syscall(tc->readIntReg(SyscallNumReg));
|
||||
Fault *fault = NoFault;
|
||||
tc->syscall(tc->readIntReg(SyscallNumReg), fault);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ using namespace RiscvISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -126,8 +126,8 @@ std::map<int, SyscallDesc> RiscvLinuxProcess::syscallDescs = {
|
|||
{2011, SyscallDesc("getmainvars", unimplementedFunc)},
|
||||
};
|
||||
|
||||
RiscvLinuxProcess::RiscvLinuxProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile) : RiscvLiveProcess(params, objFile)
|
||||
RiscvLinuxProcess::RiscvLinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile) : RiscvProcess(params, objFile)
|
||||
{}
|
||||
|
||||
SyscallDesc*
|
||||
|
|
|
@ -41,11 +41,11 @@
|
|||
#include "sim/eventq.hh"
|
||||
|
||||
/// A process with emulated Riscv/Linux syscalls.
|
||||
class RiscvLinuxProcess : public RiscvLiveProcess
|
||||
class RiscvLinuxProcess : public RiscvProcess
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
RiscvLinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
RiscvLinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
virtual SyscallDesc* getDesc(int callnum);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Loader.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
|
@ -50,33 +51,38 @@
|
|||
using namespace std;
|
||||
using namespace RiscvISA;
|
||||
|
||||
RiscvLiveProcess::RiscvLiveProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile) : LiveProcess(params, objFile)
|
||||
RiscvProcess::RiscvProcess(ProcessParams * params,
|
||||
ObjectFile *objFile) : Process(params, objFile)
|
||||
{
|
||||
// Set up stack. On RISC-V, stack starts at the top of kuseg
|
||||
// user address space. RISC-V stack grows down from here
|
||||
stack_base = 0x7FFFFFFF;
|
||||
Addr stack_base = 0x7FFFFFFF;
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
brk_point = objFile->bssBase() + objFile->bssSize();
|
||||
Addr brk_point = objFile->bssBase() + objFile->bssSize();
|
||||
|
||||
// Set up region for mmaps. Start it 1GB above the top of the heap.
|
||||
mmap_end = brk_point + 0x40000000L;
|
||||
Addr mmap_end = brk_point + 0x40000000L;
|
||||
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
RiscvLiveProcess::initState()
|
||||
RiscvProcess::initState()
|
||||
{
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
|
||||
argsInit<uint64_t>(PageBytes);
|
||||
}
|
||||
|
||||
template<class IntType> void
|
||||
RiscvLiveProcess::argsInit(int pageSize)
|
||||
RiscvProcess::argsInit(int pageSize)
|
||||
{
|
||||
updateBias();
|
||||
|
||||
|
@ -123,18 +129,24 @@ RiscvLiveProcess::argsInit(int pageSize)
|
|||
env_data_size += env.size() + 1;
|
||||
int auxv_array_size = 2 * sizeof(IntType)*auxv.size();
|
||||
|
||||
stack_size = sizeof(IntType) + argv_array_size + 2 * sizeof(Addr) +
|
||||
arg_data_size + 2 * sizeof(Addr);
|
||||
Addr stack_size = sizeof(IntType) + argv_array_size + 2 * sizeof(Addr) +
|
||||
sizeof(Addr) + arg_data_size + 2 * sizeof(Addr);
|
||||
if (!envp.empty()) {
|
||||
stack_size += 2 * sizeof(Addr) + envp_array_size + 2 * sizeof(Addr) +
|
||||
env_data_size;
|
||||
stack_size += 2 * sizeof(Addr) + envp_array_size + 2 *
|
||||
sizeof(Addr) + env_data_size;
|
||||
}
|
||||
if (!auxv.empty())
|
||||
stack_size += 2 * sizeof(Addr) + auxv_array_size;
|
||||
stack_min = roundDown(stack_base - stack_size, pageSize);
|
||||
allocateMem(stack_min, roundUp(stack_size, pageSize));
|
||||
|
||||
Addr argv_array_base = stack_min + sizeof(IntType);
|
||||
memState->setStackSize(stack_size);
|
||||
|
||||
Addr stack_min = roundDown(memState->getStackBase() -
|
||||
stack_size, pageSize);
|
||||
allocateMem(stack_min, roundUp(memState->getStackSize(), pageSize));
|
||||
|
||||
memState->setStackMin(stack_min);
|
||||
|
||||
Addr argv_array_base = memState->getStackMin() + sizeof(IntType);
|
||||
Addr arg_data_base = argv_array_base + argv_array_size + 2 * sizeof(Addr);
|
||||
Addr envp_array_base = arg_data_base + arg_data_size;
|
||||
if (!envp.empty())
|
||||
|
@ -159,7 +171,7 @@ RiscvLiveProcess::argsInit(int pageSize)
|
|||
}
|
||||
}
|
||||
|
||||
Addr sp = stack_min;
|
||||
Addr sp = memState->getStackMin();
|
||||
initVirtMem.writeBlob(sp, (uint8_t *)&argc, sizeof(IntType));
|
||||
sp += sizeof(IntType);
|
||||
for (Addr arg_pointer: arg_pointers) {
|
||||
|
@ -210,24 +222,30 @@ RiscvLiveProcess::argsInit(int pageSize)
|
|||
}
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
tc->setIntReg(StackPointerReg, stack_min);
|
||||
tc->setIntReg(StackPointerReg, memState->getStackMin());
|
||||
tc->pcState(getStartPC());
|
||||
}
|
||||
|
||||
RiscvISA::IntReg
|
||||
RiscvLiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
RiscvProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
return tc->readIntReg(SyscallArgumentRegs[i++]);
|
||||
// RISC-V only has four system call argument registers by convention, so
|
||||
// if a larger index is requested return 0
|
||||
RiscvISA::IntReg retval = 0;
|
||||
if (i < 4)
|
||||
retval = tc->readIntReg(SyscallArgumentRegs[i]);
|
||||
i++;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
RiscvLiveProcess::setSyscallArg(ThreadContext *tc, int i, RiscvISA::IntReg val)
|
||||
RiscvProcess::setSyscallArg(ThreadContext *tc, int i, RiscvISA::IntReg val)
|
||||
{
|
||||
tc->setIntReg(SyscallArgumentRegs[i], val);
|
||||
}
|
||||
|
||||
void
|
||||
RiscvLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
RiscvProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
if (sysret.successful()) {
|
||||
// no error
|
||||
|
|
|
@ -38,14 +38,13 @@
|
|||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class LiveProcess;
|
||||
class ObjectFile;
|
||||
class System;
|
||||
|
||||
class RiscvLiveProcess : public LiveProcess
|
||||
class RiscvProcess : public Process
|
||||
{
|
||||
protected:
|
||||
RiscvLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
RiscvProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
void initState();
|
||||
|
||||
|
@ -55,7 +54,7 @@ class RiscvLiveProcess : public LiveProcess
|
|||
public:
|
||||
RiscvISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, RiscvISA::IntReg val);
|
||||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
};
|
||||
|
|
|
@ -50,9 +50,9 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "arch/isa_traits.hh"
|
||||
#include "arch/riscv/generated/max_inst_regs.hh"
|
||||
#include "base/types.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
namespace RiscvISA {
|
||||
|
||||
|
|
|
@ -628,9 +628,43 @@ FastInstructionAccessMMUMiss::invoke(ThreadContext *tc,
|
|||
if (!success) {
|
||||
panic("Tried to execute unmapped address %#x.\n", vaddr);
|
||||
} else {
|
||||
Addr alignedVaddr = p->pTable->pageAlign(vaddr);
|
||||
tc->getITBPtr()->insert(alignedVaddr, 0 /*partition id*/,
|
||||
p->_pid /*context id*/, false, entry.pte);
|
||||
Addr alignedvaddr = p->pTable->pageAlign(vaddr);
|
||||
|
||||
// Grab fields used during instruction translation to figure out
|
||||
// which context to use.
|
||||
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
|
||||
|
||||
// Inside a VM, a real address is the address that guest OS would
|
||||
// interpret to be a physical address. To map to the physical address,
|
||||
// it still needs to undergo a translation. The instruction
|
||||
// translation code in the SPARC ITLB code assumes that the context is
|
||||
// zero (kernel-level) if real addressing is being used.
|
||||
bool is_real_address = !bits(tlbdata, 4);
|
||||
|
||||
// The SPARC ITLB code assumes that traps are executed in context
|
||||
// zero so we carry that assumption through here.
|
||||
bool trapped = bits(tlbdata, 18, 16) > 0;
|
||||
|
||||
// The primary context acts as a PASID. It allows the MMU to
|
||||
// distinguish between virtual addresses that would alias to the
|
||||
// same physical address (if two or more processes shared the same
|
||||
// virtual address mapping).
|
||||
int primary_context = bits(tlbdata, 47, 32);
|
||||
|
||||
// The partition id distinguishes between virtualized environments.
|
||||
int const partition_id = 0;
|
||||
|
||||
// Given the assumptions in the translateInst code in the SPARC ITLB,
|
||||
// the logic works out to the following for the context.
|
||||
int context_id = (is_real_address || trapped) ? 0 : primary_context;
|
||||
|
||||
// Insert the TLB entry.
|
||||
// The entry specifying whether the address is "real" is set to
|
||||
// false for syscall emulation mode regardless of whether the
|
||||
// address is real in preceding code. Not sure sure that this is
|
||||
// correct, but also not sure if it matters at all.
|
||||
tc->getITBPtr()->insert(alignedvaddr, partition_id, context_id,
|
||||
false, entry.pte);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,9 +686,73 @@ FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
if (!success) {
|
||||
panic("Tried to access unmapped address %#x.\n", vaddr);
|
||||
} else {
|
||||
Addr alignedVaddr = p->pTable->pageAlign(vaddr);
|
||||
tc->getDTBPtr()->insert(alignedVaddr, 0 /*partition id*/,
|
||||
p->_pid /*context id*/, false, entry.pte);
|
||||
Addr alignedvaddr = p->pTable->pageAlign(vaddr);
|
||||
|
||||
// Grab fields used during data translation to figure out
|
||||
// which context to use.
|
||||
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
|
||||
|
||||
// The primary context acts as a PASID. It allows the MMU to
|
||||
// distinguish between virtual addresses that would alias to the
|
||||
// same physical address (if two or more processes shared the same
|
||||
// virtual address mapping). There's a secondary context used in the
|
||||
// DTLB translation code, but it should __probably__ be zero for
|
||||
// syscall emulation code. (The secondary context is used by Solaris
|
||||
// to allow kernel privilege code to access user space code:
|
||||
// [ISBN 0-13-022496-0]:PG199.)
|
||||
int primary_context = bits(tlbdata, 47, 32);
|
||||
|
||||
// "Hyper-Privileged Mode" is in use. There are three main modes of
|
||||
// operation for Sparc: Hyper-Privileged Mode, Privileged Mode, and
|
||||
// User Mode.
|
||||
int hpriv = bits(tlbdata, 0);
|
||||
|
||||
// Reset, Error and Debug state is in use. Something horrible has
|
||||
// happened or the system is operating in Reset Mode.
|
||||
int red = bits(tlbdata, 1);
|
||||
|
||||
// Inside a VM, a real address is the address that guest OS would
|
||||
// interpret to be a physical address. To map to the physical address,
|
||||
// it still needs to undergo a translation. The instruction
|
||||
// translation code in the SPARC ITLB code assumes that the context is
|
||||
// zero (kernel-level) if real addressing is being used.
|
||||
int is_real_address = !bits(tlbdata, 5);
|
||||
|
||||
// Grab the address space identifier register from the thread context.
|
||||
// XXX: Inspecting how setMiscReg and setMiscRegNoEffect behave for
|
||||
// MISCREG_ASI causes me to think that the ASI register implementation
|
||||
// might be bugged. The NoEffect variant changes the ASI register
|
||||
// value in the architectural state while the normal variant changes
|
||||
// the context field in the thread context's currently decoded request
|
||||
// but does not directly affect the ASI register value in the
|
||||
// architectural state. The ASI values and the context field in the
|
||||
// request packet seem to have completely different uses.
|
||||
MiscReg reg_asi = tc->readMiscRegNoEffect(MISCREG_ASI);
|
||||
ASI asi = static_cast<ASI>(reg_asi);
|
||||
|
||||
// The SPARC DTLB code assumes that traps are executed in context
|
||||
// zero if the asi value is ASI_IMPLICIT (which is 0x0). There's also
|
||||
// an assumption that the nucleus address space is being used, but
|
||||
// the context is the relevant issue since we need to pass it to TLB.
|
||||
bool trapped = bits(tlbdata, 18, 16) > 0;
|
||||
|
||||
// Given the assumptions in the translateData code in the SPARC DTLB,
|
||||
// the logic works out to the following for the context.
|
||||
int context_id = ((!hpriv && !red && is_real_address) ||
|
||||
asiIsReal(asi) ||
|
||||
(trapped && asi == ASI_IMPLICIT))
|
||||
? 0 : primary_context;
|
||||
|
||||
// The partition id distinguishes between virtualized environments.
|
||||
int const partition_id = 0;
|
||||
|
||||
// Insert the TLB entry.
|
||||
// The entry specifying whether the address is "real" is set to
|
||||
// false for syscall emulation mode regardless of whether the
|
||||
// address is real in preceding code. Not sure sure that this is
|
||||
// correct, but also not sure if it matters at all.
|
||||
tc->getDTBPtr()->insert(alignedvaddr, partition_id, context_id,
|
||||
false, entry.pte);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,12 +768,11 @@ SpillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
|
||||
Process *p = tc->getProcessPtr();
|
||||
|
||||
//XXX This will only work in faults from a SparcLiveProcess
|
||||
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
||||
assert(lp);
|
||||
SparcProcess *sp = dynamic_cast<SparcProcess *>(p);
|
||||
assert(sp);
|
||||
|
||||
// Then adjust the PC and NPC
|
||||
tc->pcState(lp->readSpillStart());
|
||||
tc->pcState(sp->readSpillStart());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -690,12 +787,11 @@ FillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
|
||||
Process *p = tc->getProcessPtr();
|
||||
|
||||
//XXX This will only work in faults from a SparcLiveProcess
|
||||
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
||||
assert(lp);
|
||||
SparcProcess *sp = dynamic_cast<SparcProcess *>(p);
|
||||
assert(sp);
|
||||
|
||||
// Then adjust the PC and NPC
|
||||
tc->pcState(lp->readFillStart());
|
||||
tc->pcState(sp->readFillStart());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -712,10 +808,11 @@ TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst)
|
|||
|
||||
Process *p = tc->getProcessPtr();
|
||||
|
||||
SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
|
||||
assert(lp);
|
||||
SparcProcess *sp = dynamic_cast<SparcProcess *>(p);
|
||||
assert(sp);
|
||||
|
||||
lp->handleTrap(_n, tc);
|
||||
Fault fault;
|
||||
sp->handleTrap(_n, tc, &fault);
|
||||
|
||||
// We need to explicitly advance the pc, since that's not done for us
|
||||
// on a faulting instruction
|
||||
|
|
|
@ -60,35 +60,37 @@ SparcLinuxProcess::getDesc32(int callnum)
|
|||
return &syscall32Descs[callnum];
|
||||
}
|
||||
|
||||
Sparc32LinuxProcess::Sparc32LinuxProcess(LiveProcessParams * params,
|
||||
Sparc32LinuxProcess::Sparc32LinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: Sparc32LiveProcess(params, objFile)
|
||||
: Sparc32Process(params, objFile)
|
||||
{}
|
||||
|
||||
void Sparc32LinuxProcess::handleTrap(int trapNum, ThreadContext *tc)
|
||||
void Sparc32LinuxProcess::handleTrap(int trapNum, ThreadContext *tc,
|
||||
Fault *fault)
|
||||
{
|
||||
switch (trapNum) {
|
||||
case 0x10: //Linux 32 bit syscall trap
|
||||
tc->syscall(tc->readIntReg(1));
|
||||
tc->syscall(tc->readIntReg(1), fault);
|
||||
break;
|
||||
default:
|
||||
SparcLiveProcess::handleTrap(trapNum, tc);
|
||||
SparcProcess::handleTrap(trapNum, tc, fault);
|
||||
}
|
||||
}
|
||||
|
||||
Sparc64LinuxProcess::Sparc64LinuxProcess(LiveProcessParams * params,
|
||||
Sparc64LinuxProcess::Sparc64LinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: Sparc64LiveProcess(params, objFile)
|
||||
: Sparc64Process(params, objFile)
|
||||
{}
|
||||
|
||||
void Sparc64LinuxProcess::handleTrap(int trapNum, ThreadContext *tc)
|
||||
void Sparc64LinuxProcess::handleTrap(int trapNum, ThreadContext *tc,
|
||||
Fault *fault)
|
||||
{
|
||||
switch (trapNum) {
|
||||
// case 0x10: // Linux 32 bit syscall trap
|
||||
case 0x6d: // Linux 64 bit syscall trap
|
||||
tc->syscall(tc->readIntReg(1));
|
||||
tc->syscall(tc->readIntReg(1), fault);
|
||||
break;
|
||||
default:
|
||||
SparcLiveProcess::handleTrap(trapNum, tc);
|
||||
SparcProcess::handleTrap(trapNum, tc, fault);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,11 +58,11 @@ class SparcLinuxProcess
|
|||
};
|
||||
|
||||
/// A process with emulated SPARC/Linux syscalls.
|
||||
class Sparc32LinuxProcess : public SparcLinuxProcess, public Sparc32LiveProcess
|
||||
class Sparc32LinuxProcess : public SparcLinuxProcess, public Sparc32Process
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
Sparc32LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
Sparc32LinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
SyscallDesc*
|
||||
getDesc(int callnum)
|
||||
|
@ -70,15 +70,15 @@ class Sparc32LinuxProcess : public SparcLinuxProcess, public Sparc32LiveProcess
|
|||
return SparcLinuxProcess::getDesc32(callnum);
|
||||
}
|
||||
|
||||
void handleTrap(int trapNum, ThreadContext *tc);
|
||||
void handleTrap(int trapNum, ThreadContext *tc, Fault *fault);
|
||||
};
|
||||
|
||||
/// A process with emulated 32 bit SPARC/Linux syscalls.
|
||||
class Sparc64LinuxProcess : public SparcLinuxProcess, public Sparc64LiveProcess
|
||||
class Sparc64LinuxProcess : public SparcLinuxProcess, public Sparc64Process
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
Sparc64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
Sparc64LinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
SyscallDesc*
|
||||
getDesc(int callnum)
|
||||
|
@ -86,11 +86,11 @@ class Sparc64LinuxProcess : public SparcLinuxProcess, public Sparc64LiveProcess
|
|||
return SparcLinuxProcess::getDesc(callnum);
|
||||
}
|
||||
|
||||
void handleTrap(int trapNum, ThreadContext *tc);
|
||||
void handleTrap(int trapNum, ThreadContext *tc, Fault *fault);
|
||||
};
|
||||
|
||||
SyscallReturn getresuidFunc(SyscallDesc *desc, int num,
|
||||
LiveProcess *p, ThreadContext *tc);
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
} // namespace SparcISA
|
||||
#endif // __SPARC_LINUX_PROCESS_HH__
|
||||
|
|
|
@ -32,15 +32,15 @@
|
|||
#include "sim/syscall_desc.hh"
|
||||
#include "sim/syscall_emul.hh"
|
||||
|
||||
class LiveProcess;
|
||||
class Process;
|
||||
class ThreadContext;
|
||||
|
||||
namespace SparcISA {
|
||||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
ThreadContext *tc)
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, index));
|
||||
|
@ -58,7 +58,7 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
|
||||
|
||||
SyscallReturn
|
||||
getresuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
|
||||
getresuidFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
{
|
||||
const IntReg id = htog(100);
|
||||
int index = 0;
|
||||
|
@ -305,7 +305,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
|
|||
/* 214 */ SyscallDesc("sysinfo", sysinfoFunc<Sparc32Linux>), // 32 bit
|
||||
/* 215 */ SyscallDesc("ipc", unimplementedFunc), // 32 bit
|
||||
/* 216 */ SyscallDesc("sigreturn", unimplementedFunc), // 32 bit
|
||||
/* 217 */ SyscallDesc("clone", cloneFunc),
|
||||
/* 217 */ SyscallDesc("clone", cloneFunc<Sparc32Linux>),
|
||||
/* 218 */ SyscallDesc("ioprio_get", unimplementedFunc), // 32 bit
|
||||
/* 219 */ SyscallDesc("adjtimex", unimplementedFunc), // 32 bit
|
||||
/* 220 */ SyscallDesc("sigprocmask", unimplementedFunc), // 32 bit
|
||||
|
@ -611,7 +611,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
|
|||
/* 214 */ SyscallDesc("sysinfo", sysinfoFunc<SparcLinux>),
|
||||
/* 215 */ SyscallDesc("ipc", unimplementedFunc),
|
||||
/* 216 */ SyscallDesc("sigreturn", unimplementedFunc),
|
||||
/* 217 */ SyscallDesc("clone", cloneFunc),
|
||||
/* 217 */ SyscallDesc("clone", cloneFunc<SparcLinux>),
|
||||
/* 218 */ SyscallDesc("ioprio_get", unimplementedFunc),
|
||||
/* 219 */ SyscallDesc("adjtimex", unimplementedFunc),
|
||||
/* 220 */ SyscallDesc("sigprocmask", unimplementedFunc),
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Stack.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
#include "sim/system.hh"
|
||||
|
@ -52,25 +53,17 @@ using namespace SparcISA;
|
|||
static const int FirstArgumentReg = 8;
|
||||
|
||||
|
||||
SparcLiveProcess::SparcLiveProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile, Addr _StackBias)
|
||||
: LiveProcess(params, objFile), StackBias(_StackBias)
|
||||
SparcProcess::SparcProcess(ProcessParams * params, ObjectFile *objFile,
|
||||
Addr _StackBias)
|
||||
: Process(params, objFile), StackBias(_StackBias)
|
||||
{
|
||||
|
||||
// XXX all the below need to be updated for SPARC - Ali
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// Initialize these to 0s
|
||||
fillStart = 0;
|
||||
spillStart = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc)
|
||||
SparcProcess::handleTrap(int trapNum, ThreadContext *tc, Fault *fault)
|
||||
{
|
||||
PCState pc = tc->pcState();
|
||||
switch (trapNum) {
|
||||
|
@ -111,9 +104,9 @@ SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc)
|
|||
}
|
||||
|
||||
void
|
||||
SparcLiveProcess::initState()
|
||||
SparcProcess::initState()
|
||||
{
|
||||
LiveProcess::initState();
|
||||
Process::initState();
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
// From the SPARC ABI
|
||||
|
@ -149,6 +142,9 @@ SparcLiveProcess::initState()
|
|||
// Set the ASI register to something fixed
|
||||
tc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
|
||||
|
||||
// Set the MMU Primary Context Register to hold the process' pid
|
||||
tc->setMiscReg(MISCREG_MMU_P_CONTEXT, _pid);
|
||||
|
||||
/*
|
||||
* T1 specific registers
|
||||
*/
|
||||
|
@ -157,9 +153,9 @@ SparcLiveProcess::initState()
|
|||
}
|
||||
|
||||
void
|
||||
Sparc32LiveProcess::initState()
|
||||
Sparc32Process::initState()
|
||||
{
|
||||
SparcLiveProcess::initState();
|
||||
SparcProcess::initState();
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
// The process runs in user mode with 32 bit addresses
|
||||
|
@ -172,9 +168,9 @@ Sparc32LiveProcess::initState()
|
|||
}
|
||||
|
||||
void
|
||||
Sparc64LiveProcess::initState()
|
||||
Sparc64Process::initState()
|
||||
{
|
||||
SparcLiveProcess::initState();
|
||||
SparcProcess::initState();
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
// The process runs in user mode
|
||||
|
@ -187,7 +183,7 @@ Sparc64LiveProcess::initState()
|
|||
|
||||
template<class IntType>
|
||||
void
|
||||
SparcLiveProcess::argsInit(int pageSize)
|
||||
SparcProcess::argsInit(int pageSize)
|
||||
{
|
||||
int intSize = sizeof(IntType);
|
||||
|
||||
|
@ -320,15 +316,16 @@ SparcLiveProcess::argsInit(int pageSize)
|
|||
aux_padding +
|
||||
frame_size;
|
||||
|
||||
stack_min = stack_base - space_needed;
|
||||
stack_min = roundDown(stack_min, align);
|
||||
stack_size = stack_base - stack_min;
|
||||
memState->setStackMin(memState->getStackBase() - space_needed);
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), align));
|
||||
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
|
||||
|
||||
// Allocate space for the stack
|
||||
allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
|
||||
allocateMem(roundDown(memState->getStackMin(), pageSize),
|
||||
roundUp(memState->getStackSize(), pageSize));
|
||||
|
||||
// map out initial stack contents
|
||||
IntType sentry_base = stack_base - sentry_size;
|
||||
IntType sentry_base = memState->getStackBase() - sentry_size;
|
||||
IntType file_name_base = sentry_base - file_name_size;
|
||||
IntType env_data_base = file_name_base - env_data_size;
|
||||
IntType arg_data_base = env_data_base - arg_data_size;
|
||||
|
@ -352,9 +349,9 @@ SparcLiveProcess::argsInit(int pageSize)
|
|||
DPRINTF(Stack, "%#x - argv array\n", argv_array_base);
|
||||
DPRINTF(Stack, "%#x - argc \n", argc_base);
|
||||
DPRINTF(Stack, "%#x - window save\n", window_save_base);
|
||||
DPRINTF(Stack, "%#x - stack min\n", stack_min);
|
||||
DPRINTF(Stack, "%#x - stack min\n", memState->getStackMin());
|
||||
|
||||
assert(window_save_base == stack_min);
|
||||
assert(window_save_base == memState->getStackMin());
|
||||
|
||||
// write contents to stack
|
||||
|
||||
|
@ -393,7 +390,7 @@ SparcLiveProcess::argsInit(int pageSize)
|
|||
// Set up space for the trap handlers into the processes address space.
|
||||
// Since the stack grows down and there is reserved address space abov
|
||||
// it, we can put stuff above it and stay out of the way.
|
||||
fillStart = stack_base;
|
||||
fillStart = memState->getStackBase();
|
||||
spillStart = fillStart + sizeof(MachInst) * numFillInsts;
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
|
@ -401,7 +398,7 @@ SparcLiveProcess::argsInit(int pageSize)
|
|||
// assert(NumArgumentRegs >= 2);
|
||||
// tc->setIntReg(ArgumentReg[0], argc);
|
||||
// tc->setIntReg(ArgumentReg[1], argv_array_base);
|
||||
tc->setIntReg(StackPointerReg, stack_min - StackBias);
|
||||
tc->setIntReg(StackPointerReg, memState->getStackMin() - StackBias);
|
||||
|
||||
// %g1 is a pointer to a function that should be run at exit. Since we
|
||||
// don't have anything like that, it should be set to 0.
|
||||
|
@ -410,15 +407,13 @@ SparcLiveProcess::argsInit(int pageSize)
|
|||
tc->pcState(getStartPC());
|
||||
|
||||
// Align the "stack_min" to a page boundary.
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
|
||||
// num_processes++;
|
||||
memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
|
||||
}
|
||||
|
||||
void
|
||||
Sparc64LiveProcess::argsInit(int intSize, int pageSize)
|
||||
Sparc64Process::argsInit(int intSize, int pageSize)
|
||||
{
|
||||
SparcLiveProcess::argsInit<uint64_t>(pageSize);
|
||||
SparcProcess::argsInit<uint64_t>(pageSize);
|
||||
|
||||
// Stuff the trap handlers into the process address space
|
||||
initVirtMem.writeBlob(fillStart,
|
||||
|
@ -428,9 +423,9 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize)
|
|||
}
|
||||
|
||||
void
|
||||
Sparc32LiveProcess::argsInit(int intSize, int pageSize)
|
||||
Sparc32Process::argsInit(int intSize, int pageSize)
|
||||
{
|
||||
SparcLiveProcess::argsInit<uint32_t>(pageSize);
|
||||
SparcProcess::argsInit<uint32_t>(pageSize);
|
||||
|
||||
// Stuff the trap handlers into the process address space
|
||||
initVirtMem.writeBlob(fillStart,
|
||||
|
@ -439,7 +434,7 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
|
|||
(uint8_t*)spillHandler32, sizeof(MachInst) * numSpillInsts);
|
||||
}
|
||||
|
||||
void Sparc32LiveProcess::flushWindows(ThreadContext *tc)
|
||||
void Sparc32Process::flushWindows(ThreadContext *tc)
|
||||
{
|
||||
IntReg Cansave = tc->readIntReg(NumIntArchRegs + 3);
|
||||
IntReg Canrestore = tc->readIntReg(NumIntArchRegs + 4);
|
||||
|
@ -474,7 +469,7 @@ void Sparc32LiveProcess::flushWindows(ThreadContext *tc)
|
|||
}
|
||||
|
||||
void
|
||||
Sparc64LiveProcess::flushWindows(ThreadContext *tc)
|
||||
Sparc64Process::flushWindows(ThreadContext *tc)
|
||||
{
|
||||
IntReg Cansave = tc->readIntReg(NumIntArchRegs + 3);
|
||||
IntReg Canrestore = tc->readIntReg(NumIntArchRegs + 4);
|
||||
|
@ -509,35 +504,35 @@ Sparc64LiveProcess::flushWindows(ThreadContext *tc)
|
|||
}
|
||||
|
||||
IntReg
|
||||
Sparc32LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
Sparc32Process::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 6);
|
||||
return bits(tc->readIntReg(FirstArgumentReg + i++), 31, 0);
|
||||
}
|
||||
|
||||
void
|
||||
Sparc32LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val)
|
||||
Sparc32Process::setSyscallArg(ThreadContext *tc, int i, IntReg val)
|
||||
{
|
||||
assert(i < 6);
|
||||
tc->setIntReg(FirstArgumentReg + i, bits(val, 31, 0));
|
||||
}
|
||||
|
||||
IntReg
|
||||
Sparc64LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
Sparc64Process::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < 6);
|
||||
return tc->readIntReg(FirstArgumentReg + i++);
|
||||
}
|
||||
|
||||
void
|
||||
Sparc64LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val)
|
||||
Sparc64Process::setSyscallArg(ThreadContext *tc, int i, IntReg val)
|
||||
{
|
||||
assert(i < 6);
|
||||
tc->setIntReg(FirstArgumentReg + i, val);
|
||||
}
|
||||
|
||||
void
|
||||
SparcLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
SparcProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
|
||||
{
|
||||
// check for error condition. SPARC syscall convention is to
|
||||
// indicate success/failure in reg the carry bit of the ccr
|
||||
|
|
|
@ -32,17 +32,17 @@
|
|||
#ifndef __SPARC_PROCESS_HH__
|
||||
#define __SPARC_PROCESS_HH__
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/sparc/isa_traits.hh"
|
||||
#include "base/loader/object_file.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
class ObjectFile;
|
||||
class System;
|
||||
|
||||
class SparcLiveProcess : public LiveProcess
|
||||
class SparcProcess : public Process
|
||||
{
|
||||
protected:
|
||||
|
||||
|
@ -51,8 +51,8 @@ class SparcLiveProcess : public LiveProcess
|
|||
// The locations of the fill and spill handlers
|
||||
Addr fillStart, spillStart;
|
||||
|
||||
SparcLiveProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile, Addr _StackBias);
|
||||
SparcProcess(ProcessParams * params, ObjectFile *objFile,
|
||||
Addr _StackBias);
|
||||
|
||||
void initState();
|
||||
|
||||
|
@ -62,7 +62,7 @@ class SparcLiveProcess : public LiveProcess
|
|||
public:
|
||||
|
||||
// Handles traps which request services from the operating system
|
||||
virtual void handleTrap(int trapNum, ThreadContext *tc);
|
||||
virtual void handleTrap(int trapNum, ThreadContext *tc, Fault *fault);
|
||||
|
||||
Addr readFillStart() { return fillStart; }
|
||||
Addr readSpillStart() { return spillStart; }
|
||||
|
@ -71,19 +71,34 @@ class SparcLiveProcess : public LiveProcess
|
|||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
};
|
||||
|
||||
class Sparc32LiveProcess : public SparcLiveProcess
|
||||
class Sparc32Process : public SparcProcess
|
||||
{
|
||||
protected:
|
||||
|
||||
Sparc32LiveProcess(LiveProcessParams * params, ObjectFile *objFile) :
|
||||
SparcLiveProcess(params, objFile, 0)
|
||||
Sparc32Process(ProcessParams * params, ObjectFile *objFile)
|
||||
: SparcProcess(params, objFile, 0)
|
||||
{
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, SparcISA::PageBytes);
|
||||
|
||||
// Reserve 8M for main stack.
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set up stack. On SPARC Linux, stack goes from the top of memory
|
||||
// downward, less the hole for the kernel address space.
|
||||
stack_base = (Addr)0xf0000000ULL;
|
||||
Addr stack_base = 0xf0000000ULL;
|
||||
|
||||
// Set pointer for next thread stack.
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up region for mmaps.
|
||||
mmap_end = 0x70000000;
|
||||
Addr mmap_end = 0x70000000;
|
||||
|
||||
memState = std::make_shared<MemState>(brk_point, stack_base,
|
||||
max_stack_size,
|
||||
next_thread_stack_base,
|
||||
mmap_end);
|
||||
}
|
||||
|
||||
void initState();
|
||||
|
@ -96,24 +111,38 @@ class Sparc32LiveProcess : public SparcLiveProcess
|
|||
|
||||
SparcISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
|
||||
void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val);
|
||||
};
|
||||
|
||||
class Sparc64LiveProcess : public SparcLiveProcess
|
||||
class Sparc64Process : public SparcProcess
|
||||
{
|
||||
protected:
|
||||
|
||||
Sparc64LiveProcess(LiveProcessParams * params, ObjectFile *objFile) :
|
||||
SparcLiveProcess(params, objFile, 2047)
|
||||
Sparc64Process(ProcessParams * params, ObjectFile *objFile)
|
||||
: SparcProcess(params, objFile, 2047)
|
||||
{
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, SparcISA::PageBytes);
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
// Set up stack. On SPARC Linux, stack goes from the top of memory
|
||||
// downward, less the hole for the kernel address space.
|
||||
stack_base = (Addr)0x80000000000ULL;
|
||||
Addr stack_base = 0x80000000000ULL;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up region for mmaps.
|
||||
mmap_end = 0xfffff80000000000ULL;
|
||||
Addr mmap_end = 0xfffff80000000000ULL;
|
||||
|
||||
memState = std::make_shared<MemState>(brk_point, stack_base,
|
||||
max_stack_size,
|
||||
next_thread_stack_base,
|
||||
mmap_end);
|
||||
}
|
||||
|
||||
void initState();
|
||||
|
@ -126,7 +155,7 @@ class Sparc64LiveProcess : public SparcLiveProcess
|
|||
|
||||
SparcISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
|
||||
void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val);
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace SparcISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -322,9 +322,9 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
|
|||
/* 255 */ SyscallDesc("umount2", unimplementedFunc)
|
||||
};
|
||||
|
||||
SparcSolarisProcess::SparcSolarisProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: Sparc64LiveProcess(params, objFile),
|
||||
SparcSolarisProcess::SparcSolarisProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: Sparc64Process(params, objFile),
|
||||
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
|
||||
{
|
||||
// The sparc syscall table must be <= 284 entries because that is all there
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
namespace SparcISA {
|
||||
|
||||
/// A process with emulated SPARC/Solaris syscalls.
|
||||
class SparcSolarisProcess : public Sparc64LiveProcess
|
||||
class SparcSolarisProcess : public Sparc64Process
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
SparcSolarisProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
SparcSolarisProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
|
||||
virtual SyscallDesc* getDesc(int callnum);
|
||||
|
||||
|
|
|
@ -400,8 +400,9 @@
|
|||
// will sign extend it, and there's no easy way to
|
||||
// specify only checking the first byte.
|
||||
0xffffffffffffff80:
|
||||
SyscallInst::int80('xc->syscall(Rax)',
|
||||
IsSyscall, IsNonSpeculative, IsSerializeAfter);
|
||||
SyscallInst::int80('xc->syscall(Rax, &fault)',
|
||||
IsSyscall, IsNonSpeculative,
|
||||
IsSerializeAfter);
|
||||
}
|
||||
|
||||
default: Inst::INT(Ib);
|
||||
|
|
|
@ -235,8 +235,9 @@
|
|||
}
|
||||
}
|
||||
0x05: decode FullSystemInt {
|
||||
0: SyscallInst::syscall('xc->syscall(Rax)',
|
||||
IsSyscall, IsNonSpeculative, IsSerializeAfter);
|
||||
0: SyscallInst::syscall('xc->syscall(Rax, &fault)',
|
||||
IsSyscall, IsNonSpeculative,
|
||||
IsSerializeAfter);
|
||||
default: decode MODE_MODE {
|
||||
0x0: decode MODE_SUBMODE {
|
||||
0x0: Inst::SYSCALL_64();
|
||||
|
@ -422,8 +423,9 @@
|
|||
0x2: Inst::RDMSR();
|
||||
0x3: rdpmc();
|
||||
0x4: decode FullSystemInt {
|
||||
0: SyscallInst::sysenter('xc->syscall(Rax)',
|
||||
IsSyscall, IsNonSpeculative, IsSerializeAfter);
|
||||
0: SyscallInst::sysenter('xc->syscall(Rax, &fault)',
|
||||
IsSyscall, IsNonSpeculative,
|
||||
IsSerializeAfter);
|
||||
default: sysenter();
|
||||
}
|
||||
0x5: sysexit();
|
||||
|
|
|
@ -45,7 +45,7 @@ def macroop CALL_NEAR_I
|
|||
limm t1, imm
|
||||
rdip t7
|
||||
# Check target of call
|
||||
st t7, ss, [0, t0, rsp], "-env.dataSize"
|
||||
stis t7, ss, [0, t0, rsp], "-env.dataSize"
|
||||
subi rsp, rsp, ssz
|
||||
wrip t7, t1
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ def macroop CALL_NEAR_R
|
|||
|
||||
rdip t1
|
||||
# Check target of call
|
||||
st t1, ss, [0, t0, rsp], "-env.dataSize"
|
||||
stis t1, ss, [0, t0, rsp], "-env.dataSize"
|
||||
subi rsp, rsp, ssz
|
||||
wripi reg, 0
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ def macroop POP_R {
|
|||
# Make the default data size of pops 64 bits in 64 bit mode
|
||||
.adjust_env oszIn64Override
|
||||
|
||||
ld t1, ss, [1, t0, rsp], dataSize=ssz
|
||||
ldis t1, ss, [1, t0, rsp], dataSize=ssz
|
||||
addi rsp, rsp, ssz, dataSize=asz
|
||||
mov reg, reg, t1
|
||||
};
|
||||
|
@ -49,7 +49,7 @@ def macroop POP_M {
|
|||
# Make the default data size of pops 64 bits in 64 bit mode
|
||||
.adjust_env oszIn64Override
|
||||
|
||||
ld t1, ss, [1, t0, rsp], dataSize=ssz
|
||||
ldis t1, ss, [1, t0, rsp], dataSize=ssz
|
||||
cda seg, sib, disp, dataSize=ssz
|
||||
addi rsp, rsp, ssz, dataSize=asz
|
||||
st t1, seg, sib, disp, dataSize=ssz
|
||||
|
@ -70,7 +70,7 @@ def macroop PUSH_R {
|
|||
# Make the default data size of pops 64 bits in 64 bit mode
|
||||
.adjust_env oszIn64Override
|
||||
|
||||
st reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||
stis reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||
subi rsp, rsp, ssz
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ def macroop PUSH_I {
|
|||
.adjust_env oszIn64Override
|
||||
|
||||
limm t1, imm
|
||||
st t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||
stis t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||
subi rsp, rsp, ssz
|
||||
};
|
||||
|
||||
|
@ -138,7 +138,7 @@ def macroop LEAVE {
|
|||
.adjust_env oszIn64Override
|
||||
|
||||
mov t1, t1, rbp, dataSize=ssz
|
||||
ld rbp, ss, [1, t0, t1], dataSize=ssz
|
||||
ldis rbp, ss, [1, t0, t1], dataSize=ssz
|
||||
mov rsp, rsp, t1, dataSize=ssz
|
||||
addi rsp, rsp, ssz, dataSize=ssz
|
||||
};
|
||||
|
@ -156,7 +156,7 @@ def macroop ENTER_I_I {
|
|||
# t1 is now the masked nesting level, and t2 is the amount of storage.
|
||||
|
||||
# Push rbp.
|
||||
st rbp, ss, [1, t0, rsp], "-env.dataSize"
|
||||
stis rbp, ss, [1, t0, rsp], "-env.dataSize"
|
||||
subi rsp, rsp, ssz
|
||||
|
||||
# Save the stack pointer for later
|
||||
|
@ -172,8 +172,8 @@ def macroop ENTER_I_I {
|
|||
|
||||
limm t4, "ULL(-1)", dataSize=8
|
||||
topOfLoop:
|
||||
ld t5, ss, [dsz, t4, rbp]
|
||||
st t5, ss, [1, t0, rsp], "-env.dataSize"
|
||||
ldis t5, ss, [dsz, t4, rbp]
|
||||
stis t5, ss, [1, t0, rsp], "-env.dataSize"
|
||||
subi rsp, rsp, ssz
|
||||
|
||||
# If we're not done yet, loop
|
||||
|
@ -183,7 +183,7 @@ topOfLoop:
|
|||
|
||||
bottomOfLoop:
|
||||
# Push the old rbp onto the stack
|
||||
st t6, ss, [1, t0, rsp], "-env.dataSize"
|
||||
stis t6, ss, [1, t0, rsp], "-env.dataSize"
|
||||
subi rsp, rsp, ssz
|
||||
|
||||
skipLoop:
|
||||
|
|
|
@ -315,7 +315,8 @@ def template MicroLdStSplitOpConstructor {{
|
|||
let {{
|
||||
class LdStOp(X86Microop):
|
||||
def __init__(self, data, segment, addr, disp,
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||
implicitStack):
|
||||
self.data = data
|
||||
[self.scale, self.index, self.base] = addr
|
||||
self.disp = disp
|
||||
|
@ -331,8 +332,11 @@ let {{
|
|||
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
||||
if nonSpec:
|
||||
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||
# For implicit stack operations, we should use *not* use the
|
||||
# alternative addressing mode for loads/stores if the prefix is set
|
||||
if not implicitStack:
|
||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||
|
||||
def getAllocator(self, microFlags):
|
||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock,
|
||||
|
@ -351,7 +355,8 @@ let {{
|
|||
|
||||
class BigLdStOp(X86Microop):
|
||||
def __init__(self, data, segment, addr, disp,
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||
implicitStack):
|
||||
self.data = data
|
||||
[self.scale, self.index, self.base] = addr
|
||||
self.disp = disp
|
||||
|
@ -367,8 +372,11 @@ let {{
|
|||
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
||||
if nonSpec:
|
||||
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||
# For implicit stack operations, we should use *not* use the
|
||||
# alternative addressing mode for loads/stores if the prefix is set
|
||||
if not implicitStack:
|
||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||
|
||||
def getAllocator(self, microFlags):
|
||||
allocString = '''
|
||||
|
@ -395,9 +403,11 @@ let {{
|
|||
|
||||
class LdStSplitOp(LdStOp):
|
||||
def __init__(self, data, segment, addr, disp,
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||
implicitStack):
|
||||
super(LdStSplitOp, self).__init__(0, segment, addr, disp,
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec)
|
||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||
implicitStack)
|
||||
(self.dataLow, self.dataHi) = data
|
||||
|
||||
def getAllocator(self, microFlags):
|
||||
|
@ -435,7 +445,8 @@ let {{
|
|||
calculateEA = 'EA = SegBase + ' + segmentEAExpr
|
||||
|
||||
def defineMicroLoadOp(mnemonic, code, bigCode='',
|
||||
mem_flags="0", big=True, nonSpec=False):
|
||||
mem_flags="0", big=True, nonSpec=False,
|
||||
implicitStack=False):
|
||||
global header_output
|
||||
global decoder_output
|
||||
global exec_output
|
||||
|
@ -460,17 +471,26 @@ let {{
|
|||
exec_output += MicroLoadInitiateAcc.subst(iop)
|
||||
exec_output += MicroLoadCompleteAcc.subst(iop)
|
||||
|
||||
if implicitStack:
|
||||
# For instructions that implicitly access the stack, the address
|
||||
# size is the same as the stack segment pointer size, not the
|
||||
# address size if specified by the instruction prefix
|
||||
addressSize = "env.stackSize"
|
||||
else:
|
||||
addressSize = "env.addressSize"
|
||||
|
||||
base = LdStOp
|
||||
if big:
|
||||
base = BigLdStOp
|
||||
class LoadOp(base):
|
||||
def __init__(self, data, segment, addr, disp = 0,
|
||||
dataSize="env.dataSize",
|
||||
addressSize="env.addressSize",
|
||||
atCPL0=False, prefetch=False, nonSpec=nonSpec):
|
||||
addressSize=addressSize,
|
||||
atCPL0=False, prefetch=False, nonSpec=nonSpec,
|
||||
implicitStack=implicitStack):
|
||||
super(LoadOp, self).__init__(data, segment, addr,
|
||||
disp, dataSize, addressSize, mem_flags,
|
||||
atCPL0, prefetch, nonSpec)
|
||||
atCPL0, prefetch, nonSpec, implicitStack)
|
||||
self.className = Name
|
||||
self.mnemonic = name
|
||||
|
||||
|
@ -478,6 +498,9 @@ let {{
|
|||
|
||||
defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);',
|
||||
'Data = Mem & mask(dataSize * 8);')
|
||||
defineMicroLoadOp('Ldis', 'Data = merge(Data, Mem, dataSize);',
|
||||
'Data = Mem & mask(dataSize * 8);',
|
||||
implicitStack=True)
|
||||
defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);',
|
||||
'Data = Mem & mask(dataSize * 8);',
|
||||
'(StoreCheck << FlagShift)')
|
||||
|
@ -544,10 +567,11 @@ let {{
|
|||
def __init__(self, data, segment, addr, disp = 0,
|
||||
dataSize="env.dataSize",
|
||||
addressSize="env.addressSize",
|
||||
atCPL0=False, prefetch=False, nonSpec=nonSpec):
|
||||
atCPL0=False, prefetch=False, nonSpec=nonSpec,
|
||||
implicitStack=False):
|
||||
super(LoadOp, self).__init__(data, segment, addr,
|
||||
disp, dataSize, addressSize, mem_flags,
|
||||
atCPL0, prefetch, nonSpec)
|
||||
atCPL0, prefetch, nonSpec, implicitStack)
|
||||
self.className = Name
|
||||
self.mnemonic = name
|
||||
|
||||
|
@ -574,7 +598,8 @@ let {{
|
|||
'(StoreCheck << FlagShift) | Request::LOCKED_RMW',
|
||||
nonSpec=True)
|
||||
|
||||
def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"):
|
||||
def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0",
|
||||
implicitStack=False):
|
||||
global header_output
|
||||
global decoder_output
|
||||
global exec_output
|
||||
|
@ -594,20 +619,30 @@ let {{
|
|||
exec_output += MicroStoreInitiateAcc.subst(iop)
|
||||
exec_output += MicroStoreCompleteAcc.subst(iop)
|
||||
|
||||
if implicitStack:
|
||||
# For instructions that implicitly access the stack, the address
|
||||
# size is the same as the stack segment pointer size, not the
|
||||
# address size if specified by the instruction prefix
|
||||
addressSize = "env.stackSize"
|
||||
else:
|
||||
addressSize = "env.addressSize"
|
||||
|
||||
class StoreOp(LdStOp):
|
||||
def __init__(self, data, segment, addr, disp = 0,
|
||||
dataSize="env.dataSize",
|
||||
addressSize="env.addressSize",
|
||||
atCPL0=False, nonSpec=False):
|
||||
addressSize=addressSize,
|
||||
atCPL0=False, nonSpec=False, implicitStack=implicitStack):
|
||||
super(StoreOp, self).__init__(data, segment, addr, disp,
|
||||
dataSize, addressSize, mem_flags, atCPL0, False,
|
||||
nonSpec)
|
||||
nonSpec, implicitStack)
|
||||
self.className = Name
|
||||
self.mnemonic = name
|
||||
|
||||
microopClasses[name] = StoreOp
|
||||
|
||||
defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
|
||||
defineMicroStoreOp('Stis', 'Mem = pick(Data, 2, dataSize);',
|
||||
implicitStack=True)
|
||||
defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);',
|
||||
mem_flags="Request::LOCKED_RMW")
|
||||
|
||||
|
@ -655,10 +690,10 @@ let {{
|
|||
def __init__(self, data, segment, addr, disp = 0,
|
||||
dataSize="env.dataSize",
|
||||
addressSize="env.addressSize",
|
||||
atCPL0=False, nonSpec=False):
|
||||
atCPL0=False, nonSpec=False, implicitStack=False):
|
||||
super(StoreOp, self).__init__(data, segment, addr, disp,
|
||||
dataSize, addressSize, mem_flags, atCPL0, False,
|
||||
nonSpec)
|
||||
nonSpec, implicitStack)
|
||||
self.className = Name
|
||||
self.mnemonic = name
|
||||
|
||||
|
@ -694,7 +729,7 @@ let {{
|
|||
def __init__(self, data, segment, addr, disp = 0,
|
||||
dataSize="env.dataSize", addressSize="env.addressSize"):
|
||||
super(LeaOp, self).__init__(data, segment, addr, disp,
|
||||
dataSize, addressSize, "0", False, False, False)
|
||||
dataSize, addressSize, "0", False, False, False, False)
|
||||
self.className = "Lea"
|
||||
self.mnemonic = "lea"
|
||||
|
||||
|
@ -715,7 +750,7 @@ let {{
|
|||
addressSize="env.addressSize"):
|
||||
super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
||||
addr, disp, dataSize, addressSize, "0", False, False,
|
||||
False)
|
||||
False, False)
|
||||
self.className = "Tia"
|
||||
self.mnemonic = "tia"
|
||||
|
||||
|
@ -727,10 +762,9 @@ let {{
|
|||
addressSize="env.addressSize", atCPL0=False):
|
||||
super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
||||
addr, disp, dataSize, addressSize, "Request::NO_ACCESS",
|
||||
atCPL0, False, False)
|
||||
atCPL0, False, False, False)
|
||||
self.className = "Cda"
|
||||
self.mnemonic = "cda"
|
||||
|
||||
microopClasses["cda"] = CdaOp
|
||||
}};
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ using namespace X86ISA;
|
|||
|
||||
/// Target uname() handler.
|
||||
static SyscallReturn
|
||||
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
unameFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
|
@ -72,7 +72,7 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
}
|
||||
|
||||
static SyscallReturn
|
||||
archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||
archPrctlFunc(SyscallDesc *desc, int callnum, Process *process,
|
||||
ThreadContext *tc)
|
||||
{
|
||||
enum ArchPrctlCodes
|
||||
|
@ -83,7 +83,7 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
GetGS = 0x1004
|
||||
};
|
||||
|
||||
//First argument is the code, second is the address
|
||||
// First argument is the code, second is the address
|
||||
int index = 0;
|
||||
int code = process->getSyscallArg(tc, index);
|
||||
uint64_t addr = process->getSyscallArg(tc, index);
|
||||
|
@ -91,7 +91,7 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
|||
SETranslatingPortProxy &p = tc->getMemProxy();
|
||||
switch(code)
|
||||
{
|
||||
//Each of these valid options should actually check addr.
|
||||
// Each of these valid options should actually check addr.
|
||||
case SetFS:
|
||||
tc->setMiscRegNoEffect(MISCREG_FS_BASE, addr);
|
||||
tc->setMiscRegNoEffect(MISCREG_FS_EFF_BASE, addr);
|
||||
|
@ -139,22 +139,22 @@ struct UserDesc64 {
|
|||
|
||||
static SyscallReturn
|
||||
setThreadArea32Func(SyscallDesc *desc, int callnum,
|
||||
LiveProcess *process, ThreadContext *tc)
|
||||
Process *process, ThreadContext *tc)
|
||||
{
|
||||
const int minTLSEntry = 6;
|
||||
const int numTLSEntries = 3;
|
||||
const int maxTLSEntry = minTLSEntry + numTLSEntries - 1;
|
||||
|
||||
X86LiveProcess *x86lp = dynamic_cast<X86LiveProcess *>(process);
|
||||
assert(x86lp);
|
||||
X86Process *x86p = dynamic_cast<X86Process *>(process);
|
||||
assert(x86p);
|
||||
|
||||
assert((maxTLSEntry + 1) * sizeof(uint64_t) <= x86lp->gdtSize());
|
||||
assert((maxTLSEntry + 1) * sizeof(uint64_t) <= x86p->gdtSize());
|
||||
|
||||
int argIndex = 0;
|
||||
TypedBufferArg<UserDesc32> userDesc(process->getSyscallArg(tc, argIndex));
|
||||
TypedBufferArg<uint64_t>
|
||||
gdt(x86lp->gdtStart() + minTLSEntry * sizeof(uint64_t),
|
||||
numTLSEntries * sizeof(uint64_t));
|
||||
gdt(x86p->gdtStart() + minTLSEntry * sizeof(uint64_t),
|
||||
numTLSEntries * sizeof(uint64_t));
|
||||
|
||||
if (!userDesc.copyIn(tc->getMemProxy()))
|
||||
return -EFAULT;
|
||||
|
@ -242,18 +242,18 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 19 */ SyscallDesc("readv", unimplementedFunc),
|
||||
/* 20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
|
||||
/* 21 */ SyscallDesc("access", ignoreFunc),
|
||||
/* 22 */ SyscallDesc("pipe", unimplementedFunc),
|
||||
/* 22 */ SyscallDesc("pipe", pipeFunc),
|
||||
/* 23 */ SyscallDesc("select", unimplementedFunc),
|
||||
/* 24 */ SyscallDesc("sched_yield", unimplementedFunc),
|
||||
/* 24 */ SyscallDesc("sched_yield", ignoreFunc),
|
||||
/* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
|
||||
/* 26 */ SyscallDesc("msync", unimplementedFunc),
|
||||
/* 27 */ SyscallDesc("mincore", unimplementedFunc),
|
||||
/* 28 */ SyscallDesc("madvise", unimplementedFunc),
|
||||
/* 28 */ SyscallDesc("madvise", ignoreFunc),
|
||||
/* 29 */ SyscallDesc("shmget", unimplementedFunc),
|
||||
/* 30 */ SyscallDesc("shmat", unimplementedFunc),
|
||||
/* 31 */ SyscallDesc("shmctl", unimplementedFunc),
|
||||
/* 32 */ SyscallDesc("dup", dupFunc),
|
||||
/* 33 */ SyscallDesc("dup2", unimplementedFunc),
|
||||
/* 33 */ SyscallDesc("dup2", dup2Func),
|
||||
/* 34 */ SyscallDesc("pause", unimplementedFunc),
|
||||
/* 35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce),
|
||||
/* 36 */ SyscallDesc("getitimer", unimplementedFunc),
|
||||
|
@ -276,10 +276,10 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 53 */ SyscallDesc("socketpair", unimplementedFunc),
|
||||
/* 54 */ SyscallDesc("setsockopt", unimplementedFunc),
|
||||
/* 55 */ SyscallDesc("getsockopt", unimplementedFunc),
|
||||
/* 56 */ SyscallDesc("clone", cloneFunc),
|
||||
/* 56 */ SyscallDesc("clone", cloneFunc<X86Linux64>),
|
||||
/* 57 */ SyscallDesc("fork", unimplementedFunc),
|
||||
/* 58 */ SyscallDesc("vfork", unimplementedFunc),
|
||||
/* 59 */ SyscallDesc("execve", unimplementedFunc),
|
||||
/* 59 */ SyscallDesc("execve", execveFunc<X86Linux64>),
|
||||
/* 60 */ SyscallDesc("exit", exitFunc),
|
||||
/* 61 */ SyscallDesc("wait4", unimplementedFunc),
|
||||
/* 62 */ SyscallDesc("kill", unimplementedFunc),
|
||||
|
@ -329,7 +329,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 106 */ SyscallDesc("setgid", unimplementedFunc),
|
||||
/* 107 */ SyscallDesc("geteuid", geteuidFunc),
|
||||
/* 108 */ SyscallDesc("getegid", getegidFunc),
|
||||
/* 109 */ SyscallDesc("setpgid", unimplementedFunc),
|
||||
/* 109 */ SyscallDesc("setpgid", setpgidFunc),
|
||||
/* 110 */ SyscallDesc("getppid", getppidFunc),
|
||||
/* 111 */ SyscallDesc("getpgrp", unimplementedFunc),
|
||||
/* 112 */ SyscallDesc("setsid", unimplementedFunc),
|
||||
|
@ -337,7 +337,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 114 */ SyscallDesc("setregid", unimplementedFunc),
|
||||
/* 115 */ SyscallDesc("getgroups", unimplementedFunc),
|
||||
/* 116 */ SyscallDesc("setgroups", unimplementedFunc),
|
||||
/* 117 */ SyscallDesc("setresuid", unimplementedFunc),
|
||||
/* 117 */ SyscallDesc("setresuid", ignoreFunc),
|
||||
/* 118 */ SyscallDesc("getresuid", unimplementedFunc),
|
||||
/* 119 */ SyscallDesc("setresgid", unimplementedFunc),
|
||||
/* 120 */ SyscallDesc("getresgid", unimplementedFunc),
|
||||
|
@ -361,7 +361,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 138 */ SyscallDesc("fstatfs", unimplementedFunc),
|
||||
/* 139 */ SyscallDesc("sysfs", unimplementedFunc),
|
||||
/* 140 */ SyscallDesc("getpriority", unimplementedFunc),
|
||||
/* 141 */ SyscallDesc("setpriority", unimplementedFunc),
|
||||
/* 141 */ SyscallDesc("setpriority", ignoreFunc),
|
||||
/* 142 */ SyscallDesc("sched_setparam", unimplementedFunc),
|
||||
/* 143 */ SyscallDesc("sched_getparam", unimplementedFunc),
|
||||
/* 144 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
|
||||
|
@ -406,7 +406,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 183 */ SyscallDesc("afs_syscall", unimplementedFunc),
|
||||
/* 184 */ SyscallDesc("tuxcall", unimplementedFunc),
|
||||
/* 185 */ SyscallDesc("security", unimplementedFunc),
|
||||
/* 186 */ SyscallDesc("gettid", unimplementedFunc),
|
||||
/* 186 */ SyscallDesc("gettid", gettidFunc),
|
||||
/* 187 */ SyscallDesc("readahead", unimplementedFunc),
|
||||
/* 188 */ SyscallDesc("setxattr", unimplementedFunc),
|
||||
/* 189 */ SyscallDesc("lsetxattr", unimplementedFunc),
|
||||
|
@ -424,7 +424,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 201 */ SyscallDesc("time", timeFunc<X86Linux64>),
|
||||
/* 202 */ SyscallDesc("futex", futexFunc<X86Linux64>),
|
||||
/* 203 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
|
||||
/* 204 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
|
||||
/* 204 */ SyscallDesc("sched_getaffinity", ignoreFunc),
|
||||
/* 205 */ SyscallDesc("set_thread_area", unimplementedFunc),
|
||||
/* 206 */ SyscallDesc("io_setup", unimplementedFunc),
|
||||
/* 207 */ SyscallDesc("io_destroy", unimplementedFunc),
|
||||
|
@ -438,7 +438,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 215 */ SyscallDesc("epoll_wait_old", unimplementedFunc),
|
||||
/* 216 */ SyscallDesc("remap_file_pages", unimplementedFunc),
|
||||
/* 217 */ SyscallDesc("getdents64", unimplementedFunc),
|
||||
/* 218 */ SyscallDesc("set_tid_address", unimplementedFunc),
|
||||
/* 218 */ SyscallDesc("set_tid_address", setTidAddressFunc),
|
||||
/* 219 */ SyscallDesc("restart_syscall", unimplementedFunc),
|
||||
/* 220 */ SyscallDesc("semtimedop", unimplementedFunc),
|
||||
/* 221 */ SyscallDesc("fadvise64", unimplementedFunc),
|
||||
|
@ -454,12 +454,12 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 231 */ SyscallDesc("exit_group", exitGroupFunc),
|
||||
/* 232 */ SyscallDesc("epoll_wait", unimplementedFunc),
|
||||
/* 233 */ SyscallDesc("epoll_ctl", unimplementedFunc),
|
||||
/* 234 */ SyscallDesc("tgkill", unimplementedFunc),
|
||||
/* 234 */ SyscallDesc("tgkill", tgkillFunc<X86Linux64>),
|
||||
/* 235 */ SyscallDesc("utimes", unimplementedFunc),
|
||||
/* 236 */ SyscallDesc("vserver", unimplementedFunc),
|
||||
/* 237 */ SyscallDesc("mbind", unimplementedFunc),
|
||||
/* 238 */ SyscallDesc("set_mempolicy", unimplementedFunc),
|
||||
/* 239 */ SyscallDesc("get_mempolicy", unimplementedFunc),
|
||||
/* 239 */ SyscallDesc("get_mempolicy", ignoreFunc),
|
||||
/* 240 */ SyscallDesc("mq_open", unimplementedFunc),
|
||||
/* 241 */ SyscallDesc("mq_unlink", unimplementedFunc),
|
||||
/* 242 */ SyscallDesc("mq_timedsend", unimplementedFunc),
|
||||
|
@ -477,7 +477,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 254 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
|
||||
/* 255 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
|
||||
/* 256 */ SyscallDesc("migrate_pages", unimplementedFunc),
|
||||
/* 257 */ SyscallDesc("openat", unimplementedFunc),
|
||||
/* 257 */ SyscallDesc("openat", openatFunc<X86Linux64>),
|
||||
/* 258 */ SyscallDesc("mkdirat", unimplementedFunc),
|
||||
/* 259 */ SyscallDesc("mknodat", unimplementedFunc),
|
||||
/* 260 */ SyscallDesc("fchownat", unimplementedFunc),
|
||||
|
@ -493,7 +493,7 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 270 */ SyscallDesc("pselect6", unimplementedFunc),
|
||||
/* 271 */ SyscallDesc("ppoll", unimplementedFunc),
|
||||
/* 272 */ SyscallDesc("unshare", unimplementedFunc),
|
||||
/* 273 */ SyscallDesc("set_robust_list", unimplementedFunc),
|
||||
/* 273 */ SyscallDesc("set_robust_list", ignoreFunc),
|
||||
/* 274 */ SyscallDesc("get_robust_list", unimplementedFunc),
|
||||
/* 275 */ SyscallDesc("splice", unimplementedFunc),
|
||||
/* 276 */ SyscallDesc("tee", unimplementedFunc),
|
||||
|
@ -536,12 +536,18 @@ static SyscallDesc syscallDescs64[] = {
|
|||
/* 313 */ SyscallDesc("finit_module", unimplementedFunc),
|
||||
};
|
||||
|
||||
X86_64LinuxProcess::X86_64LinuxProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: X86_64LiveProcess(params, objFile, syscallDescs64,
|
||||
sizeof(syscallDescs64) / sizeof(SyscallDesc))
|
||||
X86_64LinuxProcess::X86_64LinuxProcess(ProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: X86_64Process(params, objFile, syscallDescs64,
|
||||
sizeof(syscallDescs64) / sizeof(SyscallDesc))
|
||||
{}
|
||||
|
||||
void X86_64LinuxProcess::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *process, TheISA::IntReg flags)
|
||||
{
|
||||
X86_64Process::clone(old_tc, new_tc, (X86_64Process*)process, flags);
|
||||
}
|
||||
|
||||
static SyscallDesc syscallDescs32[] = {
|
||||
/* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
|
||||
/* 1 */ SyscallDesc("exit", exitFunc),
|
||||
|
@ -554,7 +560,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 8 */ SyscallDesc("creat", unimplementedFunc),
|
||||
/* 9 */ SyscallDesc("link", unimplementedFunc),
|
||||
/* 10 */ SyscallDesc("unlink", unimplementedFunc),
|
||||
/* 11 */ SyscallDesc("execve", unimplementedFunc),
|
||||
/* 11 */ SyscallDesc("execve", execveFunc<X86Linux32>),
|
||||
/* 12 */ SyscallDesc("chdir", unimplementedFunc),
|
||||
/* 13 */ SyscallDesc("time", timeFunc<X86Linux32>),
|
||||
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
|
||||
|
@ -563,7 +569,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 17 */ SyscallDesc("break", unimplementedFunc),
|
||||
/* 18 */ SyscallDesc("oldstat", unimplementedFunc),
|
||||
/* 19 */ SyscallDesc("lseek", unimplementedFunc),
|
||||
/* 20 */ SyscallDesc("getpid", unimplementedFunc),
|
||||
/* 20 */ SyscallDesc("getpid", getpidFunc),
|
||||
/* 21 */ SyscallDesc("mount", unimplementedFunc),
|
||||
/* 22 */ SyscallDesc("umount", unimplementedFunc),
|
||||
/* 23 */ SyscallDesc("setuid", unimplementedFunc),
|
||||
|
@ -585,7 +591,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 39 */ SyscallDesc("mkdir", unimplementedFunc),
|
||||
/* 40 */ SyscallDesc("rmdir", unimplementedFunc),
|
||||
/* 41 */ SyscallDesc("dup", dupFunc),
|
||||
/* 42 */ SyscallDesc("pipe", unimplementedFunc),
|
||||
/* 42 */ SyscallDesc("pipe", pipeFunc),
|
||||
/* 43 */ SyscallDesc("times", timesFunc<X86Linux32>),
|
||||
/* 44 */ SyscallDesc("prof", unimplementedFunc),
|
||||
/* 45 */ SyscallDesc("brk", brkFunc),
|
||||
|
@ -598,15 +604,15 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 52 */ SyscallDesc("umount2", unimplementedFunc),
|
||||
/* 53 */ SyscallDesc("lock", unimplementedFunc),
|
||||
/* 54 */ SyscallDesc("ioctl", ioctlFunc<X86Linux32>),
|
||||
/* 55 */ SyscallDesc("fcntl", unimplementedFunc),
|
||||
/* 55 */ SyscallDesc("fcntl", fcntlFunc),
|
||||
/* 56 */ SyscallDesc("mpx", unimplementedFunc),
|
||||
/* 57 */ SyscallDesc("setpgid", unimplementedFunc),
|
||||
/* 57 */ SyscallDesc("setpgid", setpgidFunc),
|
||||
/* 58 */ SyscallDesc("ulimit", unimplementedFunc),
|
||||
/* 59 */ SyscallDesc("oldolduname", unimplementedFunc),
|
||||
/* 60 */ SyscallDesc("umask", unimplementedFunc),
|
||||
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
|
||||
/* 62 */ SyscallDesc("ustat", unimplementedFunc),
|
||||
/* 63 */ SyscallDesc("dup2", unimplementedFunc),
|
||||
/* 63 */ SyscallDesc("dup2", dup2Func),
|
||||
/* 64 */ SyscallDesc("getppid", unimplementedFunc),
|
||||
/* 65 */ SyscallDesc("getpgrp", unimplementedFunc),
|
||||
/* 66 */ SyscallDesc("setsid", unimplementedFunc),
|
||||
|
@ -640,9 +646,9 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 94 */ SyscallDesc("fchmod", unimplementedFunc),
|
||||
/* 95 */ SyscallDesc("fchown", unimplementedFunc),
|
||||
/* 96 */ SyscallDesc("getpriority", unimplementedFunc),
|
||||
/* 97 */ SyscallDesc("setpriority", unimplementedFunc),
|
||||
/* 97 */ SyscallDesc("setpriority", ignoreFunc),
|
||||
/* 98 */ SyscallDesc("profil", unimplementedFunc),
|
||||
/* 99 */ SyscallDesc("statfs", unimplementedFunc),
|
||||
/* 99 */ SyscallDesc("statfs", ignoreFunc),
|
||||
/* 100 */ SyscallDesc("fstatfs", unimplementedFunc),
|
||||
/* 101 */ SyscallDesc("ioperm", unimplementedFunc),
|
||||
/* 102 */ SyscallDesc("socketcall", unimplementedFunc),
|
||||
|
@ -663,7 +669,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 117 */ SyscallDesc("ipc", unimplementedFunc),
|
||||
/* 118 */ SyscallDesc("fsync", unimplementedFunc),
|
||||
/* 119 */ SyscallDesc("sigreturn", unimplementedFunc),
|
||||
/* 120 */ SyscallDesc("clone", unimplementedFunc),
|
||||
/* 120 */ SyscallDesc("clone", cloneFunc<X86Linux32>),
|
||||
/* 121 */ SyscallDesc("setdomainname", unimplementedFunc),
|
||||
/* 122 */ SyscallDesc("uname", unameFunc),
|
||||
/* 123 */ SyscallDesc("modify_ldt", unimplementedFunc),
|
||||
|
@ -701,13 +707,13 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 155 */ SyscallDesc("sched_getparam", unimplementedFunc),
|
||||
/* 156 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
|
||||
/* 157 */ SyscallDesc("sched_getscheduler", unimplementedFunc),
|
||||
/* 158 */ SyscallDesc("sched_yield", unimplementedFunc),
|
||||
/* 158 */ SyscallDesc("sched_yield", ignoreFunc),
|
||||
/* 159 */ SyscallDesc("sched_get_priority_max", unimplementedFunc),
|
||||
/* 160 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
|
||||
/* 161 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
|
||||
/* 162 */ SyscallDesc("nanosleep", unimplementedFunc),
|
||||
/* 162 */ SyscallDesc("nanosleep", ignoreFunc),
|
||||
/* 163 */ SyscallDesc("mremap", unimplementedFunc),
|
||||
/* 164 */ SyscallDesc("setresuid", unimplementedFunc),
|
||||
/* 164 */ SyscallDesc("setresuid", ignoreFunc),
|
||||
/* 165 */ SyscallDesc("getresuid", unimplementedFunc),
|
||||
/* 166 */ SyscallDesc("vm86", unimplementedFunc),
|
||||
/* 167 */ SyscallDesc("query_module", unimplementedFunc),
|
||||
|
@ -762,12 +768,12 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 216 */ SyscallDesc("setfsgid32", unimplementedFunc),
|
||||
/* 217 */ SyscallDesc("pivot_root", unimplementedFunc),
|
||||
/* 218 */ SyscallDesc("mincore", unimplementedFunc),
|
||||
/* 219 */ SyscallDesc("madvise", unimplementedFunc),
|
||||
/* 219 */ SyscallDesc("madvise", ignoreFunc),
|
||||
/* 220 */ SyscallDesc("madvise1", unimplementedFunc),
|
||||
/* 221 */ SyscallDesc("getdents64", unimplementedFunc),
|
||||
/* 222 */ SyscallDesc("fcntl64", unimplementedFunc),
|
||||
/* 223 */ SyscallDesc("unused", unimplementedFunc),
|
||||
/* 224 */ SyscallDesc("gettid", unimplementedFunc),
|
||||
/* 224 */ SyscallDesc("gettid", gettidFunc),
|
||||
/* 225 */ SyscallDesc("readahead", unimplementedFunc),
|
||||
/* 226 */ SyscallDesc("setxattr", unimplementedFunc),
|
||||
/* 227 */ SyscallDesc("lsetxattr", unimplementedFunc),
|
||||
|
@ -785,7 +791,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 239 */ SyscallDesc("sendfile64", unimplementedFunc),
|
||||
/* 240 */ SyscallDesc("futex", unimplementedFunc),
|
||||
/* 241 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
|
||||
/* 242 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
|
||||
/* 242 */ SyscallDesc("sched_getaffinity", ignoreFunc),
|
||||
/* 243 */ SyscallDesc("set_thread_area", setThreadArea32Func),
|
||||
/* 244 */ SyscallDesc("get_thread_area", unimplementedFunc),
|
||||
/* 245 */ SyscallDesc("io_setup", unimplementedFunc),
|
||||
|
@ -801,7 +807,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 255 */ SyscallDesc("epoll_ctl", unimplementedFunc),
|
||||
/* 256 */ SyscallDesc("epoll_wait", unimplementedFunc),
|
||||
/* 257 */ SyscallDesc("remap_file_pages", unimplementedFunc),
|
||||
/* 258 */ SyscallDesc("set_tid_address", unimplementedFunc),
|
||||
/* 258 */ SyscallDesc("set_tid_address", setTidAddressFunc),
|
||||
/* 259 */ SyscallDesc("timer_create", unimplementedFunc),
|
||||
/* 260 */ SyscallDesc("timer_settime", unimplementedFunc),
|
||||
/* 261 */ SyscallDesc("timer_gettime", unimplementedFunc),
|
||||
|
@ -813,12 +819,12 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 267 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
|
||||
/* 268 */ SyscallDesc("statfs64", unimplementedFunc),
|
||||
/* 269 */ SyscallDesc("fstatfs64", unimplementedFunc),
|
||||
/* 270 */ SyscallDesc("tgkill", unimplementedFunc),
|
||||
/* 270 */ SyscallDesc("tgkill", tgkillFunc<X86Linux32>),
|
||||
/* 271 */ SyscallDesc("utimes", unimplementedFunc),
|
||||
/* 272 */ SyscallDesc("fadvise64_64", unimplementedFunc),
|
||||
/* 273 */ SyscallDesc("vserver", unimplementedFunc),
|
||||
/* 274 */ SyscallDesc("mbind", unimplementedFunc),
|
||||
/* 275 */ SyscallDesc("get_mempolicy", unimplementedFunc),
|
||||
/* 275 */ SyscallDesc("get_mempolicy", ignoreFunc),
|
||||
/* 276 */ SyscallDesc("set_mempolicy", unimplementedFunc),
|
||||
/* 277 */ SyscallDesc("mq_open", unimplementedFunc),
|
||||
/* 278 */ SyscallDesc("mq_unlink", unimplementedFunc),
|
||||
|
@ -838,7 +844,7 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 292 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
|
||||
/* 293 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
|
||||
/* 294 */ SyscallDesc("migrate_pages", unimplementedFunc),
|
||||
/* 295 */ SyscallDesc("openat", unimplementedFunc),
|
||||
/* 295 */ SyscallDesc("openat", openatFunc<X86Linux32>),
|
||||
/* 296 */ SyscallDesc("mkdirat", unimplementedFunc),
|
||||
/* 297 */ SyscallDesc("mknodat", unimplementedFunc),
|
||||
/* 298 */ SyscallDesc("fchownat", unimplementedFunc),
|
||||
|
@ -854,8 +860,8 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 308 */ SyscallDesc("pselect6", unimplementedFunc),
|
||||
/* 309 */ SyscallDesc("ppoll", unimplementedFunc),
|
||||
/* 310 */ SyscallDesc("unshare", unimplementedFunc),
|
||||
/* 311 */ SyscallDesc("set_robust_list", unimplementedFunc),
|
||||
/* 312 */ SyscallDesc("get_robust_list", unimplementedFunc),
|
||||
/* 311 */ SyscallDesc("set_robust_list", ignoreFunc),
|
||||
/* 312 */ SyscallDesc("get_robust_list", ignoreFunc),
|
||||
/* 313 */ SyscallDesc("splice", unimplementedFunc),
|
||||
/* 314 */ SyscallDesc("sync_file_range", unimplementedFunc),
|
||||
/* 315 */ SyscallDesc("tee", unimplementedFunc),
|
||||
|
@ -869,8 +875,13 @@ static SyscallDesc syscallDescs32[] = {
|
|||
/* 323 */ SyscallDesc("eventfd", unimplementedFunc)
|
||||
};
|
||||
|
||||
I386LinuxProcess::I386LinuxProcess(LiveProcessParams * params,
|
||||
ObjectFile *objFile)
|
||||
: I386LiveProcess(params, objFile, syscallDescs32,
|
||||
sizeof(syscallDescs32) / sizeof(SyscallDesc))
|
||||
I386LinuxProcess::I386LinuxProcess(ProcessParams * params, ObjectFile *objFile)
|
||||
: I386Process(params, objFile, syscallDescs32,
|
||||
sizeof(syscallDescs32) / sizeof(SyscallDesc))
|
||||
{}
|
||||
|
||||
void I386LinuxProcess::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *process, TheISA::IntReg flags)
|
||||
{
|
||||
I386Process::clone(old_tc, new_tc, (I386Process*)process, flags);
|
||||
}
|
||||
|
|
|
@ -44,20 +44,27 @@
|
|||
#include "arch/x86/process.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
struct ProcessParams;
|
||||
struct ThreadContext;
|
||||
|
||||
namespace X86ISA {
|
||||
|
||||
class X86_64LinuxProcess : public X86_64LiveProcess
|
||||
class X86_64LinuxProcess : public X86_64Process
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
X86_64LinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
void clone(ThreadContext *old_tc, ThreadContext *new_tc, Process *process,
|
||||
TheISA::IntReg flags);
|
||||
};
|
||||
|
||||
class I386LinuxProcess : public I386LiveProcess
|
||||
class I386LinuxProcess : public I386Process
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
I386LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
|
||||
I386LinuxProcess(ProcessParams * params, ObjectFile *objFile);
|
||||
void clone(ThreadContext *old_tc, ThreadContext *new_tc, Process *process,
|
||||
TheISA::IntReg flags);
|
||||
};
|
||||
|
||||
} // namespace X86ISA
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
|
||||
#include "arch/x86/process.hh"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/x86/isa_traits.hh"
|
||||
#include "arch/x86/regs/misc.hh"
|
||||
#include "arch/x86/regs/segment.hh"
|
||||
|
@ -57,6 +60,7 @@
|
|||
#include "debug/Stack.hh"
|
||||
#include "mem/multi_level_page_table.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process_impl.hh"
|
||||
#include "sim/syscall_desc.hh"
|
||||
#include "sim/syscall_return.hh"
|
||||
|
@ -69,9 +73,9 @@ static const int ArgumentReg[] = {
|
|||
INTREG_RDI,
|
||||
INTREG_RSI,
|
||||
INTREG_RDX,
|
||||
//This argument register is r10 for syscalls and rcx for C.
|
||||
// This argument register is r10 for syscalls and rcx for C.
|
||||
INTREG_R10W,
|
||||
//INTREG_RCX,
|
||||
// INTREG_RCX,
|
||||
INTREG_R8W,
|
||||
INTREG_R9W
|
||||
};
|
||||
|
@ -91,19 +95,24 @@ static const int ArgumentReg32[] = {
|
|||
static const int NumArgumentRegs32 M5_VAR_USED =
|
||||
sizeof(ArgumentReg) / sizeof(const int);
|
||||
|
||||
X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs) :
|
||||
LiveProcess(params, objFile), syscallDescs(_syscallDescs),
|
||||
numSyscallDescs(_numSyscallDescs)
|
||||
X86Process::X86Process(ProcessParams * params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs)
|
||||
: Process(params, objFile), syscallDescs(_syscallDescs),
|
||||
numSyscallDescs(_numSyscallDescs)
|
||||
{
|
||||
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
}
|
||||
|
||||
X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
|
||||
ObjectFile *objFile, SyscallDesc *_syscallDescs,
|
||||
int _numSyscallDescs) :
|
||||
X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
|
||||
void X86Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *p, TheISA::IntReg flags)
|
||||
{
|
||||
Process::clone(old_tc, new_tc, p, flags);
|
||||
X86Process *process = (X86Process*)p;
|
||||
*process = *this;
|
||||
}
|
||||
|
||||
X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs)
|
||||
: X86Process(params, objFile, _syscallDescs, _numSyscallDescs)
|
||||
{
|
||||
|
||||
vsyscallPage.base = 0xffffffffff600000ULL;
|
||||
|
@ -111,27 +120,19 @@ X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
|
|||
vsyscallPage.vtimeOffset = 0x400;
|
||||
vsyscallPage.vgettimeofdayOffset = 0x0;
|
||||
|
||||
// Set up stack. On X86_64 Linux, stack goes from the top of memory
|
||||
// downward, less the hole for the kernel address space plus one page
|
||||
// for undertermined purposes.
|
||||
stack_base = (Addr)0x7FFFFFFFF000ULL;
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr stack_base = 0x7FFFFFFFF000ULL;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
Addr mmap_end = 0x7FFFF7FFF000ULL;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// "mmap_base" is a function which defines where mmap region starts in
|
||||
// the process address space.
|
||||
// mmap_base: PAGE_ALIGN(TASK_SIZE-MIN_GAP-mmap_rnd())
|
||||
// TASK_SIZE: (1<<47)-PAGE_SIZE
|
||||
// MIN_GAP: 128*1024*1024+stack_maxrandom_size()
|
||||
// We do not use any address space layout randomization in gem5
|
||||
// therefore the random fields become zero; the smallest gap space was
|
||||
// chosen but gap could potentially be much larger.
|
||||
mmap_end = (Addr)0x7FFFF7FFF000ULL;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
void
|
||||
I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
|
||||
I386Process::syscall(int64_t callnum, ThreadContext *tc, Fault *fault)
|
||||
{
|
||||
TheISA::PCState pc = tc->pcState();
|
||||
Addr eip = pc.pc();
|
||||
|
@ -140,14 +141,13 @@ I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
|
|||
pc.npc(vsyscallPage.base + vsyscallPage.vsysexitOffset);
|
||||
tc->pcState(pc);
|
||||
}
|
||||
X86LiveProcess::syscall(callnum, tc);
|
||||
X86Process::syscall(callnum, tc, fault);
|
||||
}
|
||||
|
||||
|
||||
I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
|
||||
ObjectFile *objFile, SyscallDesc *_syscallDescs,
|
||||
int _numSyscallDescs) :
|
||||
X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
|
||||
I386Process::I386Process(ProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs)
|
||||
: X86Process(params, objFile, _syscallDescs, _numSyscallDescs)
|
||||
{
|
||||
_gdtStart = ULL(0xffffd000);
|
||||
_gdtSize = PageBytes;
|
||||
|
@ -157,24 +157,19 @@ I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
|
|||
vsyscallPage.vsyscallOffset = 0x400;
|
||||
vsyscallPage.vsysexitOffset = 0x410;
|
||||
|
||||
stack_base = _gdtStart;
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr stack_base = _gdtStart;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
Addr mmap_end = 0xB7FFF000ULL;
|
||||
|
||||
// Set pointer for next thread stack. Reserve 8M for main stack.
|
||||
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
|
||||
|
||||
// "mmap_base" is a function which defines where mmap region starts in
|
||||
// the process address space.
|
||||
// mmap_base: PAGE_ALIGN(TASK_SIZE-MIN_GAP-mmap_rnd())
|
||||
// TASK_SIZE: 0xC0000000
|
||||
// MIN_GAP: 128*1024*1024+stack_maxrandom_size()
|
||||
// We do not use any address space layout randomization in gem5
|
||||
// therefore the random fields become zero; the smallest gap space was
|
||||
// chosen but gap could potentially be much larger.
|
||||
mmap_end = (Addr)0xB7FFF000ULL;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
}
|
||||
|
||||
SyscallDesc*
|
||||
X86LiveProcess::getDesc(int callnum)
|
||||
X86Process::getDesc(int callnum)
|
||||
{
|
||||
if (callnum < 0 || callnum >= numSyscallDescs)
|
||||
return NULL;
|
||||
|
@ -182,13 +177,13 @@ X86LiveProcess::getDesc(int callnum)
|
|||
}
|
||||
|
||||
void
|
||||
X86_64LiveProcess::initState()
|
||||
X86_64Process::initState()
|
||||
{
|
||||
X86LiveProcess::initState();
|
||||
X86Process::initState();
|
||||
|
||||
argsInit(sizeof(uint64_t), PageBytes);
|
||||
argsInit(PageBytes);
|
||||
|
||||
// Set up the vsyscall page for this process.
|
||||
// Set up the vsyscall page for this process.
|
||||
allocateMem(vsyscallPage.base, vsyscallPage.size);
|
||||
uint8_t vtimeBlob[] = {
|
||||
0x48,0xc7,0xc0,0xc9,0x00,0x00,0x00, // mov $0xc9,%rax
|
||||
|
@ -571,7 +566,7 @@ X86_64LiveProcess::initState()
|
|||
dataAttr.expandDown = 0;
|
||||
dataAttr.system = 1;
|
||||
|
||||
//Initialize the segment registers.
|
||||
// Initialize the segment registers.
|
||||
for (int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
|
||||
tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
|
||||
tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
|
||||
|
@ -603,7 +598,7 @@ X86_64LiveProcess::initState()
|
|||
efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
|
||||
tc->setMiscReg(MISCREG_EFER, efer);
|
||||
|
||||
//Set up the registers that describe the operating mode.
|
||||
// Set up the registers that describe the operating mode.
|
||||
CR0 cr0 = 0;
|
||||
cr0.pg = 1; // Turn on paging.
|
||||
cr0.cd = 0; // Don't disable caching.
|
||||
|
@ -626,11 +621,11 @@ X86_64LiveProcess::initState()
|
|||
}
|
||||
|
||||
void
|
||||
I386LiveProcess::initState()
|
||||
I386Process::initState()
|
||||
{
|
||||
X86LiveProcess::initState();
|
||||
X86Process::initState();
|
||||
|
||||
argsInit(sizeof(uint32_t), PageBytes);
|
||||
argsInit(PageBytes);
|
||||
|
||||
/*
|
||||
* Set up a GDT for this process. The whole GDT wouldn't really be for
|
||||
|
@ -682,7 +677,7 @@ I386LiveProcess::initState()
|
|||
dataAttr.expandDown = 0;
|
||||
dataAttr.system = 1;
|
||||
|
||||
//Initialize the segment registers.
|
||||
// Initialize the segment registers.
|
||||
for (int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
|
||||
tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
|
||||
tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
|
||||
|
@ -723,7 +718,7 @@ I386LiveProcess::initState()
|
|||
efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
|
||||
tc->setMiscReg(MISCREG_EFER, efer);
|
||||
|
||||
//Set up the registers that describe the operating mode.
|
||||
// Set up the registers that describe the operating mode.
|
||||
CR0 cr0 = 0;
|
||||
cr0.pg = 1; // Turn on paging.
|
||||
cr0.cd = 0; // Don't disable caching.
|
||||
|
@ -746,8 +741,8 @@ I386LiveProcess::initState()
|
|||
|
||||
template<class IntType>
|
||||
void
|
||||
X86LiveProcess::argsInit(int pageSize,
|
||||
std::vector<AuxVector<IntType> > extraAuxvs)
|
||||
X86Process::argsInit(int pageSize,
|
||||
std::vector<AuxVector<IntType> > extraAuxvs)
|
||||
{
|
||||
int intSize = sizeof(IntType);
|
||||
|
||||
|
@ -760,7 +755,7 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
else
|
||||
filename = argv[0];
|
||||
|
||||
//We want 16 byte alignment
|
||||
// We want 16 byte alignment
|
||||
uint64_t align = 16;
|
||||
|
||||
// Patch the ld_bias for dynamic executables.
|
||||
|
@ -846,13 +841,13 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
// X86_IA64Processor |
|
||||
0;
|
||||
|
||||
//Bits which describe the system hardware capabilities
|
||||
//XXX Figure out what these should be
|
||||
// Bits which describe the system hardware capabilities
|
||||
// XXX Figure out what these should be
|
||||
auxv.push_back(auxv_t(M5_AT_HWCAP, features));
|
||||
//The system page size
|
||||
// The system page size
|
||||
auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::PageBytes));
|
||||
//Frequency at which times() increments
|
||||
//Defined to be 100 in the kernel source.
|
||||
// Frequency at which times() increments
|
||||
// Defined to be 100 in the kernel source.
|
||||
auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
|
||||
// This is the virtual address of the program header tables if they
|
||||
// appear in the executable image.
|
||||
|
@ -865,32 +860,32 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
// zero for static executables or contain the base address for
|
||||
// dynamic executables.
|
||||
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||
//XXX Figure out what this should be.
|
||||
// XXX Figure out what this should be.
|
||||
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
||||
//The entry point to the program
|
||||
// The entry point to the program
|
||||
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
|
||||
//Different user and group IDs
|
||||
// Different user and group IDs
|
||||
auxv.push_back(auxv_t(M5_AT_UID, uid()));
|
||||
auxv.push_back(auxv_t(M5_AT_EUID, euid()));
|
||||
auxv.push_back(auxv_t(M5_AT_GID, gid()));
|
||||
auxv.push_back(auxv_t(M5_AT_EGID, egid()));
|
||||
//Whether to enable "secure mode" in the executable
|
||||
// Whether to enable "secure mode" in the executable
|
||||
auxv.push_back(auxv_t(M5_AT_SECURE, 0));
|
||||
//The address of 16 "random" bytes.
|
||||
// The address of 16 "random" bytes.
|
||||
auxv.push_back(auxv_t(M5_AT_RANDOM, 0));
|
||||
//The name of the program
|
||||
// The name of the program
|
||||
auxv.push_back(auxv_t(M5_AT_EXECFN, 0));
|
||||
//The platform string
|
||||
// The platform string
|
||||
auxv.push_back(auxv_t(M5_AT_PLATFORM, 0));
|
||||
}
|
||||
|
||||
//Figure out how big the initial stack needs to be
|
||||
// Figure out how big the initial stack needs to be
|
||||
|
||||
// A sentry NULL void pointer at the top of the stack.
|
||||
int sentry_size = intSize;
|
||||
|
||||
//This is the name of the file which is present on the initial stack
|
||||
//It's purpose is to let the user space linker examine the original file.
|
||||
// This is the name of the file which is present on the initial stack
|
||||
// It's purpose is to let the user space linker examine the original file.
|
||||
int file_name_size = filename.size() + 1;
|
||||
|
||||
const int numRandomBytes = 16;
|
||||
|
@ -906,10 +901,10 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
for (int i = 0; i < argv.size(); ++i)
|
||||
arg_data_size += argv[i].size() + 1;
|
||||
|
||||
//The info_block needs to be padded so it's size is a multiple of the
|
||||
//alignment mask. Also, it appears that there needs to be at least some
|
||||
//padding, so if the size is already a multiple, we need to increase it
|
||||
//anyway.
|
||||
// The info_block needs to be padded so its size is a multiple of the
|
||||
// alignment mask. Also, it appears that there needs to be at least some
|
||||
// padding, so if the size is already a multiple, we need to increase it
|
||||
// anyway.
|
||||
int base_info_block_size =
|
||||
sentry_size + file_name_size + env_data_size + arg_data_size;
|
||||
|
||||
|
@ -917,7 +912,7 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
|
||||
int info_block_padding = info_block_size - base_info_block_size;
|
||||
|
||||
//Each auxilliary vector is two 8 byte words
|
||||
// Each auxiliary vector is two 8 byte words
|
||||
int aux_array_size = intSize * 2 * (auxv.size() + 1);
|
||||
|
||||
int envp_array_size = intSize * (envp.size() + 1);
|
||||
|
@ -925,15 +920,15 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
|
||||
int argc_size = intSize;
|
||||
|
||||
//Figure out the size of the contents of the actual initial frame
|
||||
// Figure out the size of the contents of the actual initial frame
|
||||
int frame_size =
|
||||
aux_array_size +
|
||||
envp_array_size +
|
||||
argv_array_size +
|
||||
argc_size;
|
||||
|
||||
//There needs to be padding after the auxiliary vector data so that the
|
||||
//very bottom of the stack is aligned properly.
|
||||
// There needs to be padding after the auxiliary vector data so that the
|
||||
// very bottom of the stack is aligned properly.
|
||||
int partial_size = frame_size + aux_data_size;
|
||||
int aligned_partial_size = roundUp(partial_size, align);
|
||||
int aux_padding = aligned_partial_size - partial_size;
|
||||
|
@ -944,9 +939,14 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
aux_padding +
|
||||
frame_size;
|
||||
|
||||
stack_min = stack_base - space_needed;
|
||||
Addr stack_base = memState->getStackBase();
|
||||
|
||||
Addr stack_min = stack_base - space_needed;
|
||||
stack_min = roundDown(stack_min, align);
|
||||
stack_size = roundUp(stack_base - stack_min, pageSize);
|
||||
|
||||
unsigned stack_size = stack_base - stack_min;
|
||||
stack_size = roundUp(stack_size, pageSize);
|
||||
memState->setStackSize(stack_size);
|
||||
|
||||
// map memory
|
||||
Addr stack_end = roundDown(stack_base - stack_size, pageSize);
|
||||
|
@ -982,15 +982,14 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
IntType argc = argv.size();
|
||||
IntType guestArgc = X86ISA::htog(argc);
|
||||
|
||||
//Write out the sentry void *
|
||||
// Write out the sentry void *
|
||||
IntType sentry_NULL = 0;
|
||||
initVirtMem.writeBlob(sentry_base,
|
||||
(uint8_t*)&sentry_NULL, sentry_size);
|
||||
initVirtMem.writeBlob(sentry_base, (uint8_t*)&sentry_NULL, sentry_size);
|
||||
|
||||
//Write the file name
|
||||
// Write the file name
|
||||
initVirtMem.writeString(file_name_base, filename.c_str());
|
||||
|
||||
//Fix up the aux vectors which point to data
|
||||
// Fix up the aux vectors which point to data
|
||||
assert(auxv[auxv.size() - 3].a_type == M5_AT_RANDOM);
|
||||
auxv[auxv.size() - 3].a_val = aux_data_base;
|
||||
assert(auxv[auxv.size() - 2].a_type == M5_AT_EXECFN);
|
||||
|
@ -998,14 +997,15 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
assert(auxv[auxv.size() - 1].a_type == M5_AT_PLATFORM);
|
||||
auxv[auxv.size() - 1].a_val = aux_data_base + numRandomBytes;
|
||||
|
||||
//Copy the aux stuff
|
||||
|
||||
// Copy the aux stuff
|
||||
for (int x = 0; x < auxv.size(); x++) {
|
||||
initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize,
|
||||
(uint8_t*)&(auxv[x].a_type), intSize);
|
||||
initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
|
||||
(uint8_t*)&(auxv[x].a_val), intSize);
|
||||
}
|
||||
//Write out the terminating zeroed auxilliary vector
|
||||
// Write out the terminating zeroed auxiliary vector
|
||||
const uint64_t zero = 0;
|
||||
initVirtMem.writeBlob(auxv_array_base + auxv.size() * 2 * intSize,
|
||||
(uint8_t*)&zero, intSize);
|
||||
|
@ -1020,30 +1020,28 @@ X86LiveProcess::argsInit(int pageSize,
|
|||
initVirtMem.writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
|
||||
|
||||
ThreadContext *tc = system->getThreadContext(contextIds[0]);
|
||||
//Set the stack pointer register
|
||||
// Set the stack pointer register
|
||||
tc->setIntReg(StackPointerReg, stack_min);
|
||||
|
||||
// There doesn't need to be any segment base added in since we're dealing
|
||||
// with the flat segmentation model.
|
||||
tc->pcState(getStartPC());
|
||||
|
||||
//Align the "stack_min" to a page boundary.
|
||||
stack_min = roundDown(stack_min, pageSize);
|
||||
|
||||
// num_processes++;
|
||||
// Align the "stack_min" to a page boundary.
|
||||
memState->setStackMin(roundDown(stack_min, pageSize));
|
||||
}
|
||||
|
||||
void
|
||||
X86_64LiveProcess::argsInit(int intSize, int pageSize)
|
||||
X86_64Process::argsInit(int pageSize)
|
||||
{
|
||||
std::vector<AuxVector<uint64_t> > extraAuxvs;
|
||||
extraAuxvs.push_back(AuxVector<uint64_t>(M5_AT_SYSINFO_EHDR,
|
||||
vsyscallPage.base));
|
||||
X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs);
|
||||
X86Process::argsInit<uint64_t>(pageSize, extraAuxvs);
|
||||
}
|
||||
|
||||
void
|
||||
I386LiveProcess::argsInit(int intSize, int pageSize)
|
||||
I386Process::argsInit(int pageSize)
|
||||
{
|
||||
std::vector<AuxVector<uint32_t> > extraAuxvs;
|
||||
//Tell the binary where the vsyscall part of the vsyscall page is.
|
||||
|
@ -1051,38 +1049,46 @@ I386LiveProcess::argsInit(int intSize, int pageSize)
|
|||
vsyscallPage.base + vsyscallPage.vsyscallOffset));
|
||||
extraAuxvs.push_back(AuxVector<uint32_t>(M5_AT_SYSINFO_EHDR,
|
||||
vsyscallPage.base));
|
||||
X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs);
|
||||
X86Process::argsInit<uint32_t>(pageSize, extraAuxvs);
|
||||
}
|
||||
|
||||
void
|
||||
X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn retval)
|
||||
X86Process::setSyscallReturn(ThreadContext *tc, SyscallReturn retval)
|
||||
{
|
||||
tc->setIntReg(INTREG_RAX, retval.encodedValue());
|
||||
}
|
||||
|
||||
X86ISA::IntReg
|
||||
X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
X86_64Process::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < NumArgumentRegs);
|
||||
return tc->readIntReg(ArgumentReg[i++]);
|
||||
}
|
||||
|
||||
void
|
||||
X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
|
||||
X86_64Process::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
|
||||
{
|
||||
assert(i < NumArgumentRegs);
|
||||
return tc->setIntReg(ArgumentReg[i], val);
|
||||
}
|
||||
|
||||
void
|
||||
X86_64Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *p, TheISA::IntReg flags)
|
||||
{
|
||||
X86Process::clone(old_tc, new_tc, p, flags);
|
||||
((X86_64Process*)p)->vsyscallPage = vsyscallPage;
|
||||
}
|
||||
|
||||
X86ISA::IntReg
|
||||
I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
|
||||
I386Process::getSyscallArg(ThreadContext *tc, int &i)
|
||||
{
|
||||
assert(i < NumArgumentRegs32);
|
||||
return tc->readIntReg(ArgumentReg32[i++]);
|
||||
}
|
||||
|
||||
X86ISA::IntReg
|
||||
I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
I386Process::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||
{
|
||||
assert(width == 32 || width == 64);
|
||||
assert(i < NumArgumentRegs);
|
||||
|
@ -1093,8 +1099,16 @@ I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
|
|||
}
|
||||
|
||||
void
|
||||
I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
|
||||
I386Process::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
|
||||
{
|
||||
assert(i < NumArgumentRegs);
|
||||
return tc->setIntReg(ArgumentReg[i], val);
|
||||
}
|
||||
|
||||
void
|
||||
I386Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *p, TheISA::IntReg flags)
|
||||
{
|
||||
X86Process::clone(old_tc, new_tc, p, flags);
|
||||
((I386Process*)p)->vsyscallPage = vsyscallPage;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "sim/aux_vector.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "mem/multi_level_page_table.hh"
|
||||
|
||||
|
@ -55,7 +56,7 @@ namespace X86ISA
|
|||
M5_AT_SYSINFO_EHDR = 33
|
||||
};
|
||||
|
||||
class X86LiveProcess : public LiveProcess
|
||||
class X86Process : public Process
|
||||
{
|
||||
protected:
|
||||
Addr _gdtStart;
|
||||
|
@ -64,12 +65,12 @@ namespace X86ISA
|
|||
SyscallDesc *syscallDescs;
|
||||
const int numSyscallDescs;
|
||||
|
||||
X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
X86Process(ProcessParams * params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
|
||||
template<class IntType>
|
||||
void argsInit(int pageSize,
|
||||
std::vector<AuxVector<IntType> > extraAuxvs);
|
||||
std::vector<AuxVector<IntType> > extraAuxvs);
|
||||
|
||||
public:
|
||||
Addr gdtStart()
|
||||
|
@ -81,13 +82,28 @@ namespace X86ISA
|
|||
SyscallDesc* getDesc(int callnum);
|
||||
|
||||
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
|
||||
void clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *process, TheISA::IntReg flags);
|
||||
|
||||
X86Process &
|
||||
operator=(const X86Process &in)
|
||||
{
|
||||
if (this == &in)
|
||||
return *this;
|
||||
|
||||
_gdtStart = in._gdtStart;
|
||||
_gdtSize = in._gdtSize;
|
||||
syscallDescs = in.syscallDescs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class X86_64LiveProcess : public X86LiveProcess
|
||||
class X86_64Process : public X86Process
|
||||
{
|
||||
protected:
|
||||
X86_64LiveProcess(LiveProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
X86_64Process(ProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
|
||||
class VSyscallPage
|
||||
{
|
||||
|
@ -96,24 +112,40 @@ namespace X86ISA
|
|||
Addr size;
|
||||
Addr vtimeOffset;
|
||||
Addr vgettimeofdayOffset;
|
||||
|
||||
VSyscallPage &
|
||||
operator=(const VSyscallPage &in)
|
||||
{
|
||||
if (this == &in)
|
||||
return *this;
|
||||
|
||||
base = in.base;
|
||||
size = in.size;
|
||||
vtimeOffset = in.vtimeOffset;
|
||||
vgettimeofdayOffset = in.vgettimeofdayOffset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
VSyscallPage vsyscallPage;
|
||||
|
||||
public:
|
||||
void argsInit(int intSize, int pageSize);
|
||||
void argsInit(int pageSize);
|
||||
void initState();
|
||||
|
||||
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
/// Explicitly import the otherwise hidden getSyscallArg
|
||||
using LiveProcess::getSyscallArg;
|
||||
using Process::getSyscallArg;
|
||||
void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
|
||||
void clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *process, TheISA::IntReg flags);
|
||||
};
|
||||
|
||||
class I386LiveProcess : public X86LiveProcess
|
||||
class I386Process : public X86Process
|
||||
{
|
||||
protected:
|
||||
I386LiveProcess(LiveProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
I386Process(ProcessParams *params, ObjectFile *objFile,
|
||||
SyscallDesc *_syscallDescs, int _numSyscallDescs);
|
||||
|
||||
class VSyscallPage
|
||||
{
|
||||
|
@ -122,17 +154,33 @@ namespace X86ISA
|
|||
Addr size;
|
||||
Addr vsyscallOffset;
|
||||
Addr vsysexitOffset;
|
||||
|
||||
VSyscallPage &
|
||||
operator=(const VSyscallPage &in)
|
||||
{
|
||||
if (this == &in)
|
||||
return *this;
|
||||
|
||||
base = in.base;
|
||||
size = in.size;
|
||||
vsyscallOffset = in.vsyscallOffset;
|
||||
vsysexitOffset = in.vsysexitOffset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
VSyscallPage vsyscallPage;
|
||||
|
||||
public:
|
||||
void argsInit(int intSize, int pageSize);
|
||||
void argsInit(int pageSize);
|
||||
void initState();
|
||||
|
||||
void syscall(int64_t callnum, ThreadContext *tc);
|
||||
void syscall(int64_t callnum, ThreadContext *tc, Fault *fault);
|
||||
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
|
||||
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i, int width);
|
||||
void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
|
||||
void clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
||||
Process *process, TheISA::IntReg flags);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,7 +49,9 @@ m5Syscall(ThreadContext *tc)
|
|||
{
|
||||
DPRINTF(PseudoInst, "PseudoInst::m5Syscall()\n");
|
||||
|
||||
tc->syscall(tc->readIntReg(INTREG_RAX));
|
||||
Fault fault;
|
||||
tc->syscall(tc->readIntReg(INTREG_RAX), &fault);
|
||||
|
||||
MiscReg rflags = tc->readMiscReg(MISCREG_RFLAGS);
|
||||
rflags &= ~(1 << 16);
|
||||
tc->setMiscReg(MISCREG_RFLAGS, rflags);
|
||||
|
|
|
@ -231,13 +231,10 @@ TLB::finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const
|
|||
AddrRange m5opRange(0xFFFF0000, 0xFFFFFFFF);
|
||||
|
||||
if (m5opRange.contains(paddr)) {
|
||||
if (m5opRange.contains(paddr)) {
|
||||
req->setFlags(Request::MMAPPED_IPR | Request::GENERIC_IPR |
|
||||
Request::STRICT_ORDER);
|
||||
req->setPaddr(GenericISA::iprAddressPseudoInst(
|
||||
(paddr >> 8) & 0xFF,
|
||||
paddr & 0xFF));
|
||||
}
|
||||
req->setFlags(Request::MMAPPED_IPR | Request::GENERIC_IPR |
|
||||
Request::STRICT_ORDER);
|
||||
req->setPaddr(GenericISA::iprAddressPseudoInst((paddr >> 8) & 0xFF,
|
||||
paddr & 0xFF));
|
||||
} else if (FullSystem) {
|
||||
// Check for an access to the local APIC
|
||||
LocalApicBase localApicBase =
|
||||
|
|
|
@ -305,6 +305,13 @@ namespace X86ISA
|
|||
PCState() {}
|
||||
PCState(Addr val) { set(val); }
|
||||
|
||||
void
|
||||
setNPC(Addr val)
|
||||
{
|
||||
Base::setNPC(val);
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
uint8_t size() const { return _size; }
|
||||
void size(uint8_t newSize) { _size = newSize; }
|
||||
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* Copyright (c) 2003-2005 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -211,4 +223,29 @@ popCount(uint64_t val) {
|
|||
return (val * sum) >> 56; // horizontal sum
|
||||
#endif // defined(__GNUC__) || (defined(__clang__) && __has_builtin(__builtin_popcountl))
|
||||
}
|
||||
|
||||
/**
|
||||
* Align to the next highest power of two.
|
||||
*
|
||||
* The number passed in is aligned to the next highest power of two,
|
||||
* if it is not already a power of two. Please note that if 0 is
|
||||
* passed in, 0 is returned.
|
||||
*
|
||||
* This code has been modified from the following:
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
*/
|
||||
inline uint64_t alignToPowerOfTwo(uint64_t val)
|
||||
{
|
||||
val--;
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
val |= val >> 8;
|
||||
val |= val >> 16;
|
||||
val |= val >> 32;
|
||||
val++;
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
#endif // __BASE_BITFIELD_HH__
|
||||
|
|
|
@ -545,6 +545,8 @@ ElfObject::getSections()
|
|||
sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
|
||||
section = elf_getscn(elf, ++sec_idx);
|
||||
} // while sections
|
||||
|
||||
elf_end(elf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue