diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1dbbc64861322d92433471171e73be421c7df7b9 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,82 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014-2021 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +name: CI + +on: + push: + workflow_dispatch: + inputs: + clear-cache: + description: Clear cache + required: false + default: false + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends \ + python3-mako gcc-arm-linux-gnueabihf libc6-dev-armhf-cross \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross + - name: Install Coverity + if: ${{ github.ref == 'refs/heads/coverity_scan' }} + run: | + wget https://scan.coverity.com/download/cxx/linux64 \ + --post-data "token=$COVERITY_TOKEN&project=siemens%2Fjailhouse" \ + -O coverity_tool.tar.gz + tar -xf coverity_tool.tar.gz + ln -s cov-analysis-linux64-* cov-analysis-linux64 + - name: Cache kernel build environment + uses: actions/cache@v2 + id: cache-kernel + with: + key: kernel-build + path: | + ci/linux + ci/linux-5.10 + - name: Install kernel build environment + if: ${{ github.event.inputs.clear-cache == 'true' || steps.cache-kernel.outputs.cache-hit != 'true' }} + run: | + cd ci + rm -rf linux linux-5.10 + wget http://www.kiszka.org/downloads/jailhouse-ci/kernel-build.tar.xz + tar xJf kernel-build.tar.xz + - name: Build + if: ${{ github.ref != 'refs/heads/coverity_scan' }} + run: | + ci/build-all-configs.sh + - name: Build for Coverity + if: ${{ github.ref == 'refs/heads/coverity_scan' }} + run: | + export PATH=$PWD/cov-analysis-linux64/bin:$PATH + cov-configure --comptype gcc --compiler arm-linux-gnueabihf-gcc --template + cov-configure --comptype gcc --compiler aarch64-linux-gnu-gcc --template + ci/build-all-configs.sh --cov cov-int + - name: Submit Coverity results + if: ${{ github.ref == 'refs/heads/coverity_scan' }} + run: | + tar caf jailhouse-scan.tar.bz2 cov-int + curl --form token=$COVERITY_TOKEN \ + --form email=$COVERITY_EMAIL \ + --form file=@jailhouse-scan.tar.bz2 \ + --form version="${{ github.sha }}" \ + --form description="Jailhouse Coverity Scan" \ + https://scan.coverity.com/builds?project=siemens%2Fjailhouse + env: + COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }} + COVERITY_EMAIL: ${{ secrets.COVERITY_EMAIL }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..245733cb70c49c21cd9507b8901a3aa26ba55b18 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Build outputs - only! +*.[oa] +*.mod +*.mod.[co] +*.cell +*.cmd +*.bin +*.gcno +*.gcda +.tmp_versions +*.dtb +*.dtb.S +*.dtb.*.tmp +*.8 +.cache.mk +Module.symvers +modules.order +driver/jailhouse.ko +include/jailhouse/config.h +hypervisor/hypervisor.lds +inmates/lib/arm/inmate.lds +inmates/lib/arm64/inmate.lds +pyjailhouse/pci_defs.py +tools/demos/cache-timings +tools/demos/ivshmem-demo +tools/jailhouse +tools/jailhouse-gcov-extract +tools/jailhouse-config-collect +Documentation/generated +hypervisor/include/generated +hypervisor/arch/*/include/generated +*.s +ci/out +ci/*.tar.xz +*.pyc diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..eb644c810f1ed5d8198c7f0d37b203bec4d6a13d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,147 @@ +Contributing to Jailhouse +========================= + +Contributions to Jailhouse are always welcome. This document explains the +general requirements on contributions and the recommended preparation steps. It +also sketches the typical integration process of patches. + + +Contribution Checklist +---------------------- + +- use git to manage your changes [*recommended*] + +- follow Documentation/coding-style.txt coding style [**required**] + - for python code run pep8 coding style checker [**required**] + +- add the required copyright header to each new file introduced, see + [licensing information](LICENSING.md) [**required**] + +- structure patches logically, in small steps [**required**] + - one separable functionality/fix/refactoring = one patch + - do not mix those three into a single patch (e.g. first refactor, then + add a new functionality that builds onto the refactoring) + - after each patch, the tree still has to build and work, i.e. do not add + even temporary breakages inside a patch series (helps when tracking down + bugs) + - use `git rebase -i` to restructure a patch series + +- base patches on top of latest master or - if there are dependencies - on next + (note: next is an integration branch that may change non-linearly) + +- test patches sufficiently (obvious, but...) [**required**] + - no regressions are caused in affected code + - seemingly unaffected architectures still build (use github actions e.g.) + - static code analyzer finds no new defects (register a github fork with + Coverity for free scanning) [*recommended*] + - python code shall be tested with python 3 [**required**] + - the world is still spinning + +- add signed-off to all patches [**required**] + - to certify the "Developer's Certificate of Origin", see below + - check with your employer when not working on your own! + +- add Fixes: to all bug-fix commits [*recommended*] + - the Fixes: tag format shall be: + Fixes: 12-byte-hash ("subject of bug-introducing commit") + - if you are unsure of the bug-introducing commit do *not* add a + Fixes: tag - no Fixes: tag is better than a wrong Fixes: tag. + +- post patches to mailing list [**required**] + - use `git format-patch/send-email` if possible + - send patches inline, do not append them + - no HTML emails! + - CC people who you think should look at the patches, e.g. + - affected maintainers (see areas of responsibility below) + - someone who wrote a change that is fixed or reverted by you now + - who commented on related changes in the recent past + - who otherwise has expertise and is interested in the topic + - pull requests on github are only optional + +- post follow-up version(s) if feedback requires this + +- send reminder if nothing happened after about a week + + +Developer's Certificate of Origin 1.1 +------------------------------------- + +When signing-off a patch for this project like this + + Signed-off-by: Random J Developer + +using your real name (no pseudonyms or anonymous contributions), you declare the +following: + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +See also https://www.kernel.org/doc/Documentation/process/submitting-patches.rst +(Section 11, "Sign your work") for further background on this process which was +adopted from the Linux kernel. + + +Contribution Integration Process +-------------------------------- + +1. patch reviews performed on mailing list + * at least by maintainers, but everyone is invited + * feedback has to consider design, functionality and style + * simpler and clearer code preferred, even if original code works fine + +2. accepted patches merged into next branch + +3. further testing done by community, including CI build tests and code + analyzer runs + +4. if no new problems or discussions showed up, acceptance into master + * grace period for master: about 3 days + * urgent fixes may be applied sooner + +github facilities are not used for the review process so that people can follow +all changes and related discussions at a single stop, the mailing list. This +may change in the future if github should improve their email integration. + + +Areas of responsibility +----------------------- + +Jailhouse is rather small. Nevertheless, there are different people involved in +different areas of its code. The following list shall give an overview on who +is working in which area and should be involved when discussing changes: + +Jan Kiszka : + - overall Jailhouse maintenance + - committer to official repository + +Valentine Sinitsyn : + - AMD64 support + +Henning Schild : + - inter-cell communication + - configuration file generator + +Ralf Ramsauer + - uart infrastructure + - inmate library diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..ffd9b72672061fb8f4ee2d9f39609156df8daed8 --- /dev/null +++ b/COPYING @@ -0,0 +1,346 @@ +This copyright does not cover applications or operating systems that +run inside hypervisor cells, also if they use hypervisor services by +normal hypercalls. This is considered normal use of the hypervisor +and is not a "derived work". + +--------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Documentation/Doxyfile b/Documentation/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..d7e76859e8e84107dcadc8f6a458240848d45f71 --- /dev/null +++ b/Documentation/Doxyfile @@ -0,0 +1,307 @@ +# Doxygen 1.8 or newer + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Jailhouse +PROJECT_NUMBER = +PROJECT_BRIEF = "Linux-based partitioning hypervisor" +PROJECT_LOGO = +OUTPUT_DIRECTORY = Documentation/generated +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = YES +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = YES +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = hypervisor +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js +RECURSIVE = YES +EXCLUDE = hypervisor/arch/arm +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = hypervisor/include +INCLUDE_FILE_PATTERNS = +PREDEFINED = \ + DOXYGEN_CPP \ + __attribute__(x)= \ + DEFINE_MMIO_READ(s)="static inline u##s mmio_read##s(void *address);" \ + DEFINE_MMIO_WRITE(s)="static inline void mmio_write##s(void *address, u##s value);" +EXPAND_AS_DEFINED = COMM_REGION_GENERIC_HEADER +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/Documentation/articles/LJ-article-04-2015.txt b/Documentation/articles/LJ-article-04-2015.txt new file mode 100644 index 0000000000000000000000000000000000000000..075fedc79143e2664099756b6cc1ae142122013f --- /dev/null +++ b/Documentation/articles/LJ-article-04-2015.txt @@ -0,0 +1,399 @@ +Get to know Jailhouse +===================== + +By Valentine Sinitsyn + +Originally appeared in Linux Journal issue 252 (April 2015). +Minor fixes and updates applied. + +As you read Linux Journal, you probably know Linux has rich +virtualization ecosystem. KVM is de-facto standard, VirtualBox is widely +used for desktop virtualization, veterans should remember Xen (it's +still in a good shape, by the way!) and there is also VMware (which +isn't free but runs on Linux as well). This is not to mention a +multitude of lesser-known hypervisors like educational lguest or hobbyst +Xvisor. In such crowded landscape, is there a place for a newcomer? + +There is likely not much sense in creating Yet Another Linux-based +"versatile" hypervisor (except doing it just for fun, you know). But +there are some specific use cases which general-purpose solutions don't +address quite well. One of such areas is real-time virtualization, that +is frequently met in industrial automation, medicine, +telecommunications, and high-performance computing. In these +applications, dedicating a whole CPU or its core to the software that +runs bare-metal (with no underlying OS) is a way to meet strict deadline +requirements. While it is possible to pin KVM instance to processor core +and pass-through PCI devices to guests, tests [1] show the worst-case +latency may be above some realistic requirements. As usual with Free +Software, the situation is getting better with time, but there one other +thing. + +And it's security. Sensitive software systems go through rigorous +certifications (like Common Criteria) or even formal verification +procedures. If you want them to run virtualized (say, for consolidation +purposes), the hypervisor must isolate them from non-certifiable +workloads. This implies the hypervisor itself must be small enough, +otherwise it may end up being larger (and more "suspicious") than the +software it segregates thus devastating the whole idea of isolation. + +So looks like there is some room for a lightweight (for real-time camp), +small and simple (for security folks) open-source Linux-friendly +hypervisor for real-time and certifiable workloads. And it's where +Jailhouse comes into a play (this being said, safety, not security +is the primary focus at this point). + +New guy in a block +------------------ + +Jailhouse was born in Siemens and is developed as Free Software project +(GPLv2) since November 2013. On May 2015, Jailhouse 0.5 was released to +general public. Jailhouse is rather young and more of research project +than ready-to-use tool, so it's a good time to get acquainted with it +now, and stay prepared to meet it in the production. + +From the technical point of view, Jailhouse is static partitioning +hypervisor that runs bare-metal but cooperates with Linux closely. It +means Jailhouse doesn't emulate resources you don't have - it just +splits your hardware into isolated compartments called "cells" that are +wholly dedicated to guest software programs called "inmates". One of +these cells runs Linux OS and is known as "root cell"; other cells +borrow CPUs and devices from the root cell as they are created. +Besides Linux, Jailhouse supports bare-metal applications but +it can't run general-purpose OS (like Windows or FreeBSD) unmodified: as +discussed, there are plenty of other options, if you need to. One day, +Jailhouse may also support running KVM in the root cell, thus delivering +the best of two worlds. + +As said above, Jailhouse cooperates with Linux closely and relies on it +for hardware bootstrapping, hypervisor launch and doing management tasks +(like creating new cells). Bootstrapping is really essential here, as it +is rather complex task for modern computers, and implementing it within +Jailhouse would make it a way more complex. This being said, Jailhouse +doesn't meld with the kernel as KVM (which is a kernel module on x86, or +even linked-in on ARM) does. It is loaded as firmware image (the same way +Wi-Fi adapters load their firmware blobs) and resides in dedicated memory +region which you should reserve at Linux boot time. Jailhouse's kernel +module (jailhouse.ko, also called "driver") loads the firmware and creates +/dev/jailhouse device which jailhouse userspace tool uses, but it doesn't +contain any hypervisor logic. + +Jailhouse is an example of Asynchronous Multiprocessing (AMP) +architecture. Compared to traditional Symmetric Multiprocessing (SMP) +systems, CPU cores in Jailhouse are not treated equal: say, cores 0 and +1 may run Linux and have access to SATA hard drive while core 2 runs a +bare-metal application which only has access to serial port. As most +computers Jailhouse can run on have shared L2/L3 caches, this means +there is a possibility for cache thrashing. To understand why it +happens, consider that Jailhouse maps the same guest physical memory +address (GPA) to different host (or real) physical address for different +inmates. If two inmates occasionally have the same GPA (naturally +containing diverse data) in the same L2/L3 cache line due to cache +associativity, they will interfere each other's work and degrade the +performance. This effect is yet to be measured, and Jailhouse currently +has no dedicated means to mitigate it. However there is a vision that +for many applications this performance loss won't be crucial. Future CPUs +may also introduce some QoS mechanisms to manage caches better. Moreover, +this issue is not specific in Jailhouse and also affects e.g. cloud platforms. + +Now you have enough background to understand what Jailhouse is (and what +isn't). I hope you are interested; if it's the case, let's see how to +install and run it on your system. + +Getting up-to-date +------------------ + +Sometimes you may need very latest KVM and QEMU to give Jailhouse a try. +KVM is part of the kernel, and updating the critical system component +just to try some new software would probably seem overkill. Luckily, +there is another way. + +kvm-kmod [2] is a tool to take KVM modules from one kernel and compile +them for another, and is usually used to build latest KVM for your +current kernel. The build process is detailed in the README, but in a +nutshell you clone the repository, initialize a submodule (it's the +source for KVM) and run configure script followed by make. When modules +are ready, just insmod them instead of what your distribution provides +(don't forget to unload those first). If you want the change permanent, +run 'make modules_install'. kvm-kmod can take KVM sources fromever you +point to, but the defaults are usually sufficient. + +Compiling QEMU is easier but more time-consuming. It follows the usual +'configure && make' procedure, and doesn't need to be installed +system-wide (which is package manager-friendly). Just put +'/path/to/qemu/x86_64-softmmu/qemu-system-x86_64' instead of plain +'qemu-system-x86_64' in the text's examples. + +Building Jailhouse +------------------ + +Despite having a 0.5 release now, Jailhouse is still a young project +that is developed in quick paces. You are unlikely to find it in your +distribution's repositories for the same reasons, so the preferred way +to get Jailhouse is to build it from Git. + +To run Jailhouse, you'll need a recent multicore VT-x-enabled Intel x86 +64-bit CPU, and a motherboard with VT-d support. Version 0.5 introduced +support for AMD64 (albeit AMD IOMMU support is still in the works) and +ARM (v7 or better). At least 1GB RAM is recommended, and even more for +nested setup we discuss below. On software side, you'll need the usual +developer tools (make, gcc, git) and headers for your Linux kernel. + +Running Jailhouse on real hardware isn't straightforward at this time, +and if you only want to play with it, there is a better alternative. +Given that you meet CPU requirements, the hypervisor should run well +under KVM/QEMU; this is known as nested setup. Jailhouse relies on some +bleeding-edge features, so you'll need at least Linux 3.17 and QEMU 2.1 +for everything to work smoothly. Unless you are on rolling release +distribution, this could be a problem, so you may want to compile these +tools by yourself. This is detailed in the sidebar, and I suggest you +have a look at it even if you are lucky enough to have the required +versions pre-packaged: Jailhouse evolves and may need yet unreleased +features and fixes by the time you read this. + +Make sure you have nested mode enabled in KVM. Both kvm-intel and +kvm-amd kernel modules accept 'nested=1' parameter which is responsible +just for that. You can set it manually, in modprobe command line (don't +forget to unload previous module's instance first). Alternatively, add +'options kvm-intel nested=1' (or similar kvm-amd line) to a new file +under /etc/modprobe.d. + +You should also reserve memory for Jailhouse and inmates. To do this, +simply add 'memmap=66M$0x3b000000' to QEMU guest kernel command line. +For one-time usage, do this from the GRUB menu (press 'e', edit the +command line, press 'F10'). To make the change persistent, edit +GRUB_CMDLINE_LINUX variable in /etc/default/grub at QEMU guest side +and regenerate the configuration with grub-mkconfig. If you are using +GRUB 2, make sure you escape the dollar sign in 'memmap=' with three +slashes (\\\). + +Now, take a JeOS edition of your favorite distribution. You can produce +one with SUSE Studio, ubuntu-vm-builder and similar, or just install a +minimal system the ordinary way yourself. It is recommended to have the +same kernel on the host and inside QEMU. Now, run the virtual machine as +(Intel CPU assumed): + +qemu-system-x86_64 -machine q35 -m 1G -enable-kvm -smp 4 \ + -cpu kvm64,-kvm_pv_eoi,-kvm_steal_time,-kvm_asyncpf,-kvmclock,+vmx,+x2apic \ + -drive file=LinuxInstallation.img,id=disk,if=none \ + -fsdev local,path=/path/to/jailhouse,security_model=passthrough,id=vfs \ + -device virtio-9p-pci,addr=1f.7,mount_tag=host,fsdev=vfs \ + -device ide-hd,drive=disk -serial stdio -serial file:com2.txt + +Note we enabled 9p (-virtfs) to access the host filesystem from QEMU +guest side; /path/to/jailhouse is where you are going to compile +Jailhouse now. Cd to this directory and run: + +git clone git@github.com:siemens/jailhouse.git jailhouse +cd jailhouse +make + +Now, switch to the guest and mount 9p filesystem (for example, with +'mount -t 9p host /mnt'). Cd to /mnt/jailhouse and execute: + +sudo make firmware_install +sudo insmod jailhouse.ko + +This copies Jailhouse binary image you've built to /lib/firmware and +inserts Jailhouse driver module. You can now enable Jailhouse with: + +sudo tools/jailhouse enable configs/qemu-vm.cell + +As the command returns, type 'dmesg | tail'. If you see "The Jailhouse +is opening." message, you've successfully launched the hypervisor, and +your Linux guest now runs under Jailhouse (which itself runs under +KVM/QEMU). If you get an error, it is an indication that your CPU misses +some required feature. If the guest hangs, this is most likely due to +your host kernel or QEMU are not up-to-date enough for Jailhouse, or +something is wrong with qemu-vm cell config. Jailhouse sends all its +messages to serial port, and QEMU simply prints them to the terminal +where it was started. Look at the messages to see what resource +(I/O port, memory and so on) caused the problem, and read on for the +details of Jailhouse configuration. + +Configs and inmates +------------------- + +Creating Jailhouse configuration files isn't straightforward. As the +codebase must be kept small, most of the logic that takes place +automatically in other hypervisors must be done manually here (albeit +with some help from the tools that come with Jailhouse). Compared to +libvirt or VirtualBox XML, Jailhouse configuration files are very +detailed and rather low-level. The configuration is currently expressed +in form of plain C files (found under configs/ in the sources) compiled +into raw binaries, however another format (like DeviceTree) could be +used in future versions. + +Most of the time, you wouldn't need to create a cell config from +scratch, unless you authored a whole new inmate, or want the hypervisor +to run on your specific hardware (that's addressed in the sidebar). + +Cell configuration files contain information like hypervisor base +address (it should be within area you reserved with 'memmap=' earlier), +a mask of CPUs assigned to the cell (for root cells, it's 0xff, or all +CPUs in the system), the list of memory regions and the permissions this +cell has to them, I/O ports bitmap (0 marks a port as cell-accessible), +and the list of PCI devices. + +Each Jailhouse cell has its own config file, so you'll have one config +for the root cell describing the platform Jailhouse executes on (like +qemu-vm.c we saw above) and several others for each running cell. It's +possible for inmates to share one config file (and thus one cell), but +then only one of these inmates will be active at given time. + +In order to launch an inmate, you need to create its cell first: + +sudo tools/jailhouse cell create configs/apic-demo.cell + +apic-demo.cell is cell configuration file that comes with Jailhouse (I +also assume you still use QEMU setup described earlier). This cell +doesn't use any PCI devices, but in more complex cases it is recommended +to unload Linux drivers before moving devices to the cell with this +command. + +Now, the inmate image can be loaded into memory: + +sudo tools/jailhouse cell load apic-demo \ + inmates/demos/x86/apic-demo.bin -a 0xf0000 + +Jailhouse treats all inmates as opaque binaries, and although it +provides a small framework to develop them faster, the only thing it +needs to know about the inmate image is its base address. Jailhouse +expects an inmate entry point at 0xffff0 (which is different from x86 +reset vector). apic-demo.bin is a standard demo inmate that comes with +Jailhouse, and inmates framework linker script ensures that if the +binary is mapped at 0xf0000, the entry point will be at the right +address. 'apic-demo' is just a name, and it can be almost anything you +want. + +Finally, start the cell with: + +sudo tools/jailhouse cell start apic-demo + +Now, switch back to the terminal you run QEMU from. You'll see lines +like this one are being sent to the serial port: + +Calibrated APIC frequency: 1000008 kHz Timer fired, jitter: 38400 ns, +min: 38400 ns, max: 38400 ns ... + +apic-demo is a purely demonstrational inmate. It programs APIC timer +(found on each contemporary CPU's core) to fire at 10 Hz, and measures +actual time between the events happening. Jitter is the difference +between the expected and actual time (the latency), and the smaller it +is, the less visible (in terms of performance) the hypervisor is. +Although this test isn't quite comprehensive, it is important as +Jailhouse targets realtime inmates and needs to be as lightweight as +possible. + +Jailhouse also provides some means for getting cell statistics. At the +most basic level, there is sysfs interface under /sys/devices/jailhouse. +Several tools exist that pretty-print this data. For instance, you can +list cells currently on the system with: + +sudo tools/jailhouse cell list + +For more detailed statistics, run: + +sudo tools/jailhouse cell stats apic-demo + +The data you see is updated periodically (as in top utility) and contains +various low-level counters like the number of hypercalls issued, or the +number of I/O port accesses. The lifetime total and per-second values are +given for each entry. It's mainly for developers, but higher numbers mean +the inmate causes hypervisor involvement more often, thus degrading the +performance. Ideally, these should be close to zero, as jitter in apic-demo. +To exit the tool, press Q. + +Tearing down +------------ + +Jailhouse comes with several demo inmates, not only apic-demo. Let's try +something different. Stop the inmate with: + +sudo tools/jailhouse cell destroy apic-demo +JAILHOUSE_CELL_DESTROY: Operation not permitted + +What's the reason? Remember apic-demo cell had 'running/locked' state in +the cell list. Jailhouse introduces locked state to prevent changes to +the configuration; a cell that locks the hypervisor is essentially more +important than the root one (think it does some critical job at the +power plant while Linux is mostly for management purposes on that +system). Luckily, apic-demo is a toy inmate and it unlocks Jailhouse +after the first shutdown attempt, so the second one should succeed. +Execute the command above one more time, and apic-demo should disappear +from the cell listing. + +Now, create tiny-demo cell (which is originally for tiny-demo.bin, also +from the Jailhouse demo inmates set) and load 32-bit-demo.bin into it +the usual way: + +sudo tools/jailhouse cell create configs/tiny-demo.cell +sudo tools/jailhouse cell load tiny-demo \ + inmates/demos/x86/32-bit-demo.bin -a 0xf0000 +sudo tools/jailhouse cell start tiny-demo + +Look into com2.txt in the host (the same directory you started QEMU +from). Not only this shows that cells can be reused by the inmates +provided they have compatible resource requirements, it is also a proof +that Jailhouse can run 32-bit inmates (the hypervisor itself and the +root cell always run in 64-bit mode). + +When you are done with Jailhouse, you can disable it with: + +sudo tools/jailhouse disable + +For this to succeed, the must be no cells in "running/locked" state. + +This is the end of our short trip to Jailhouse: I hope you enjoyed your +stay. For now, Jailhouse is not a ready-to-consume product, so you may +not see an immediate use of it. However, it's actively developed and +somewhat unique to Linux ecosystem, and if you have a need for real-time +application virtualization, it makes sense to keep a close eye on its +progress. + +Jailhouse for real +------------------ + +QEMU is great for giving Jailhouse a try, but it's also possible to test +it on real hardware. However, you should never do this on your PC: with +low-level tool Jailhouse is, you can easily hang your root cell where +Linux runs, which may result in filesystem and data corruption. + +Jailhouse comes with helper tool to generate cell configs, but usually +you still need to tweak the resultant file. The tool depends on Python; +if you don't have it on your testing board, Jailhouse lets you to +collect required data and generate the configuration on your main Linux +PC (it's safe): + +sudo tools/jailhouse config collect data.tar + +Copy data.tar to your PC or notebook and untar + +tools/jailhouse config create -r path/to/untarred/data configs/myboard.c + +Configuration tool reads many files under /proc and /sys (either +collected or directly), analyzes them and generates memory regions, PCI +devices list and other things required for Jailhouse to run. + +Post-processing the generated config is mostly trial and error process. +You enable Jailhouse and try to do something. If the system locks up, +you analyze serial output and decide if you need to grant access. If you +are trying to run Jailhouse on a memory-constrained system (less than 1 +GB RAM), be careful with hypervisor memory area, as the configuration +tool can currently get it wrong. Don't forget to reserve memory for +Jailhouse through kernel command line the same way you did it with QEMU. +On some AMD-based systems, you may need to adjust Memory Mapped I/O +(MMIO) regions, because Jailhouse doesn't support AMD IOMMU technology +yet while the configuration tool implies it. + +To capture Jailhouse serial output, you'll likely need serial-to-USB +adapter and null modem cable. Many modern motherboards come with no COM +ports, but they have headers you can connect a socket to. Once you connect +your board to main Linux PC, run minicom or alike to see the output (remember +to set port's baud rate to 115200 in program's settings). + +References +---------- + +1. Static System Partitioning and KVM (KVM Forum 2013 slides): + https://docs.google.com/file/d/0B6HTUUWSPdd-Zl93MVhlMnRJRjg +2. kvm-kmod homepage: http://git.kiszka.org/?p=kvm-kmod.git diff --git a/Documentation/articles/LWN.net-article-01-2014.txt b/Documentation/articles/LWN.net-article-01-2014.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb95848366099cfa8c878ed5b16f7be52d9a4d17 --- /dev/null +++ b/Documentation/articles/LWN.net-article-01-2014.txt @@ -0,0 +1,172 @@ +------------------------------------------------------------------------------- + This Article by Valentine Sinitsyn was published in two parts on LWN.net in + January 2014. It is licensed under Creative Commons Attribution-ShareAlike + (CC-BY-SA). + + Please note that its content my be partially outdated due to code changes + applied after the article was released. However, this article is not meant to + remain unchanged; feel free to post corrections and additions as patches to + the Jailhouse project. +------------------------------------------------------------------------------- + +Understanding the Jailhouse Hypervisor + +Jailhouse [1] is a new partitioning hypervisor that runs bare-metal applications or modified guest OS images. Currently it is for x86_64 only, and this will be the architecture we implicitly refer to in the text. However, ARM is on the roadmap, and since the code is portable, support for other architectures can be added as well. Compared to other virtualization solutions like KVM or Xen, Jailhouse is lightweight and doesn't support over-commitment of the resources. Guests can't share CPU because there is no scheduler, and Jailhouse can't emulate devices you don't have. Hardware virtualization support (VT-x and VT-d for x86) is required. All of these makes the hypervisor design clean, and its code small and relatively simple. Yet Jailhouse is not a toy and is targeted at production use. For example, it can be employed for Services OS partitions creation [2]. Jailhouse uses Linux to bootstrap itself and to issue commands to the hypervisor, however it doesn't depend on Linux and is completely self-contained. The code is available freely under GPLv2 license. + +This article provides an overview of how Jailhouse works internally, and aims those who intend to hack on it or want to know what Jailhouse is (currently) capable of. It doesn't explain how to use the hypervisor - please consult README or the mailing list [3] instead. + +This text is an extended version of the two-part article series originally published by the LWN. + +Concepts +======== + +Jailhouse splits your system into isolated partitions called "cells". Each cell runs one guest and has a set of assigned resources (CPUs, memory regions, PCI devices) that it fully controls. Hypervisor's job is to manage cells and maintain their isolation from each other. + +A running Jailhouse system has at least one cell known as the "Linux cell". It contains Linux operating system used to initially launch the hypervisor and to control it afterwards. This cell's role is somewhat similar to dom0 in Xen. However, the Linux cell doesn't assert full control on hardware resources, as dom0 does. Instead, when a new cell is created, its CPUs and memory are taken from a Linux cell. This process is called 'shrinking'. + +Data structures +=============== + +Jailhouse uses struct jailhouse_system (defined in cell-config.h) as a descriptor for the system it runs on. This structure contains three fields: + +* hypervisor_memory, which defines Jailhouse's location in memory; + +* config_memory, which points to the region where hardware configuration is stored (in x86, it's the ACPI tables); and + +* system, a cell descriptor which sets the initial configuration for a Linux cell. + +Cell descriptor starts with struct jailhouse_cell_desc, defined in cell-config.h as well. This structure contains basic information like cell's name, size of CPU set, number of memory regions, IRQ lines and PCI devices. After struct jailhouse_cell_desc, several variable-sized arrays follow: + +* cpu_set: a bitmap which lists cell's CPUs (1 at Nth position means Nth CPU is assigned to the cell); + +* mem_regions: an array which stores physical address, guest physical address (virt_start), size and access flags for this cell's memory regions. There can be many of them: RAM (currently it must be the first region), PCI, ACPI or I/O APIC. See config/qemu-vm.c for an example; + +* irq_lines: an array which describes IRQ lines. It's unused now and may disappear or change in future; + +* I/O bitmap (usually referred to as pio_bitmap), which controls I/O ports accessible from the cell (1 means the port is inaccessible). This is x86-only, since no other conceivable architecture has separate I/O space; + +* pci_devices: an array, which maps PCI devices to VT-d domains. + +jailhouse_system_config_size() returns system descriptor size, jailhouse_cell_config_size() calculates cell descriptor size. + +Currently, Jailhouse has no human-readable configuration files. C structures mentioned earlier (see config/*.c) are compiled with '-O binary' objcopy(1) flag to produce raw binaries rather than ELF objects, and jailhouse userspace tool (see tools/jailhouse.h) loads them into memory as is. Creating such descriptors is tedious work that require good knowledge of hardware architecture. There are no sanity checks for descriptors except basic validation, so you can easily create something unusable. Nothing prevents Jailhouse from using a higher-level XML or similar text-based configuration files in the future - they are just not implemented yet. + +Another common data structure is struct per_cpu, which is architecture-specific and defined in x86/include/asm/percpu.h. It describes a CPU that is assigned to a cell. Throughout this text, we will refer to it as cpu_data. There is one cpu_data for each processor Jailhouse manages, and it is stored in per_cpu memory region (see 'Memory management'). cpu_data contains information like logical CPU identifier (cpu_id field), APIC identifier (apic_id), hypervisor stack (stack[PAGE_SIZE]), back reference to the cell this CPU belongs to (cell), a set of Linux registers (i. e. register values used when Linux moved to this CPU's cell), CPU mode (stopped, wait-for-SIPI, etc). It also holds VMXON and VMCS regions required for VT-x. + +Finally, there is struct jailhouse_header defined in header.h, which describes the hypervisor as a whole. It is located at the very beginning of the hypervisor binary image and contains various information like hypervisor entry point address, its memory size, per_cpu area size, page offset (see below) and number of possible/online CPUs. Some fields in this structure have static values, while the loader initializes the others at Jailhouse startup. + +Memory management +================= + +Jailhouse operates in physically continuous memory region. Currently, it needs to be reserved at boot using "memmap=" kernel command-line parameter. Future versions may use Contiguous Memory Allocator (CMA) [4] instead. When you enable Jailhouse, the loader linearly maps this memory somewhere in kernel virtual address space. Its offset from the memory region's base address is stored in page_offset field of the header. This makes converting from host virtual to physical address (and the reverse) trivial: page_map_hvirt2phys() and page_map_phys2hvirt() functions only need to subtract or add page_offset. + +An overall (physical) layout of Jailhouse memory region is shown at Fig. 1: + + +-----------+-------------------+-----------------+------------+--------------+------+ + | Guest RAM | hypervisor_header | Hypervisor Code | cpu_data[] | system_confg | Heap | + +-----------+-------------------+-----------------+------------+--------------+------+ + |__start |__page_pool |hypervisor_header.size + +Fig. 1 Jailhouse physical memory layout scheme. Lowercase labels are global symbols or common function argument names. + +To manage this memory, Jailhouse utilizes a simple bitmap-based page allocator available through page_alloc() function. The function that initializes memory management is paging_init(). It creates two page pools (struct page_pool defined in paging.h): mem_pool to manage free physical pages, and remap_pool for [host] virtual address space regions. mem_pool begins at __page_pool, so paging_init() marks per_cpu area (cpu_data[]) and system_config as already allocated. remap_pool appears in VT-d and xAPIC code, and maps config_memory pages. It also includes the foreign mapping region (see below), however it is not allocated dynamically but reserved in page_init() during the hypervisor startup. As the last step, paging_init() copies the Linux mappings for the hypervisor memory (addresses between __start and hypervisor_header.size) into hv_page_table global variable. This page directory is used later in host (VMX root) mode. + +page_map_create() function creates page mappings. It is mainly useful when initializing Extended Page Tables (EPT) for the cell. When a mapping is no longer needed, one calls page_map_destroy() to release it. By default, Jailhouse has no access to guest ("foreign") pages. They are mapped on request either manually or by page_map_get_foreign_page() function that accepts guest virtual address and creates a mapping at FOREIGN_MAPPING_BASE (currently, 1M) in host virtual address space. This is similar to fixmaps in Linux kernel in that it allows to create short-living non-linear mappings. Each CPU has its own foreign mapping region, and fixed number of foreign pages (NUM_FOREIGN_PAGES, currently 16) can be mapped to it. + +Jailhouse itself is not mapped into cells. This way, it is protected from unwanted guest access. + +Enabling Jailhouse +================== + +To enable the hypervisor, Jailhouse needs to initialize its subsystems, create a Linux cell according to system_config, enable VT-x on each CPU and finally migrate Linux to its cell to continue running in guest mode. From this point, the hypervisor asserts full control over the system's resources. + +As stated earlier, Jailhouse doesn't depend on Linux. However, Linux is used to initialize the hypervisor and to control it later. For these tasks, jailhouse userspace tool issues ioctls to /dev/jailhouse. jailhouse.ko module (the loader), compiled from main.c, registers this device node on load. + +To enable Jailhouse, the jailhouse tool issues JAILHOUSE_ENABLE ioctl which causes a call to jailhouse_enable(). It loads the hypervisor code to memory via request_firmware() call. This is the same mechanism device drivers use. Then jailhouse_enable() maps Jailhouse's reserved memory region (as described in "Memory management") using ioremap() and marks its pages as executable. The hypervisor loaded and a system configuration (struct jailhouse_system) copied from userspace are laid out as shown at Fig. 1. Finally, jailhouse_enable() calls enter_hypervisor() on each CPU, passing it the header, and waits till all these calls return. After that Jailhouse is considered enabled, and the firmware is released. + +hypervisor_enter() is really a thin wrapper that jumps to the entry point set in the header, passing it what smp_processor_id() returns as an argument. The entry point is defined in hypervisor/setup.c as arch_entry, which is coded in assembler and resides in x86/entry.S. This code locates per_cpu region for a given cpu_id using RIP-relative addressing, stores Linux stack pointer and cpu_id in it, sets Jailhouse stack, and calls generic entry() function, passing it a pointer to cpu_data. When it returns, Linux stack pointer is restored. + +entry() function is what actually enables Jailhouse. It behaves slightly differently for the first CPU it initializes and the rest of them. The first CPU is called "master" and it is responsible for system-wide initializations and checks. It sets up paging (see "Memory management"), maps config_memory if it is present in the system configuration, checks memory regions defined in the Linux cell descriptor for alignment and access flags, initializes the APIC (see "Interrupts handling"), creates Jailhouse's Interrupt Descriptor Table (IDT), configures x2APIC guest (VMX non-root) access (if available), and initializes the Linux cell (see "Cell initialization"). After that, VT-d is enabled and configured for the Linux cell (we won't go into details here, see [2] for an overview of VT-d operation). Non-master CPUs only initialize themselves. + +CPU Initialization +------------------ + +CPU initialization is a lengthy process that begins in cpu_init() function. For the starters, CPU is registered as "Linux CPU": its ID is validated, and if it is on system CPU set, it is added to the Linux cell. The rest of the procedure is architecture-specific and continues in arch_cpu_init(). For x86, it saves current register values including RIP, segment selectors, CR3, TR, GDTR and the descriptors in linux_* fields of the cpu_data structure. These values will be restored on first VM entry. IA32_SYSENTER Model Specific Registers (MSR) used for Linux system calls, and IA32_EFER MSR (used for 64-bit mode switch) are also stored. Then Jailhouse swaps the IDT (interrupt handlers), Global Descriptor Table (GDT) that contains segment descriptors, and CR3 (page directory pointer) register with its own values. Jailhouse's IDT is discussed in "Handling interrupts", and hv_page_table is used for CR3. + +Compared to IA-32 mode, segmentation's role in IA-32e (64-bit mode) is greatly reduced. Segment base addresses and limits are ignored, so access is permitted to the whole address range. Given that, Jailhouse uses only bare minimum of segments: one for code with 'L' bit enabled in the descriptor, and the obligatory TSS segment. Code segment selector is loaded to CS to indicate Jailhouse code is 64-bit. DS, ES and SS are not used in 64-bit mode, however, they are set to null selectors that cause #GP if accidentally accessed. + +Finally, arch_cpu_init() fills cpu_data->apic_id (see apic_cpu_init()) and configures VMX for the CPU. This is done in vmx_cpu_init() which first checks that CPU provides all the required features. Then it prepares Virtual Machine Control Structure (VMCS) which is located in cpu_data, and enables Virtual Machine eXtensions (VMX) on the CPU. VMCS region is configured in vmcs_setup() so that on every VM entry or exit: + +* The host (Jailhouse) gets the control and segmentation registers values described earlier in this section. The corresponding VMCS fields are simply copied from hardware registers arch_cpu_init() set. LMA and LME bits are raised in the host IA32_EFER MSR, indicating that the processor is in 64-bit mode, and the stack pointer is set to the end of cpu_data->stack (remember stack grows down). Host RIP (instruction pointer) is set to vm_exit defined in x86/entry.S. It calls vmx_handle_exit() function and resumes VM execution with VMRESUME instruction when it returns. This way, on each VM exit the control is transferred to the dispatch function that analyzes the exit reason and acts appropriately. SYSENTER MSRa are cleared because Jailhouse has no userspace applications or system calls, and its guests use a different means to switch to the hypervisor (see "Creating a cell"). + +* The guest gets its control and segmentation registers from cpu_data->linux_*. RSP and RIP are taken from the kernel stack frame created for arch_entry() call. This way, on VM entry Linux code will continue execution as if entry(smp_processor_id()) call in hypervisor_enter() has already completed - the kernel is transparently migrated to the cell. The guest's IA32_EFER MSR is also set to its Linux value so 64-bit mode is enabled on VM entry. Cells besides Linux cell will reset their CPUs just after initialization, overwriting values defined here. + +vmcs_setup() enables the following VMX features: MSR and I/O bitmaps (access to specific I/O ports or MSRs results in VM exit, which Jailhouse either handles or panics); Unrestricted guest mode (allows guests to run in unprotected unpaged mode; this is needed to emulate hardware reset as described in 'Creating a cell' and for CPU hot-plugging to "recycle" CPUs from destroyed); Extended Page Tables (required for Unrestricted guest mode and used for guest physical address space mappings); Preemption timer (used to schedule VM exit as described later). + +When all CPUs are initialized, entry() function calls arch_cpu_activate_vmm(). This is point of no return: it sets RAX to zero, loads all general-purposes registers left and issues VMLAUNCH instruction to enter the VM. Due to guest register setup described earlier and because RAX (which, by convention, stores function return value) is 0, Linux will consider entry(smp_processor_id()) call successful and move on as a guest. + +Handling interrupts +------------------- + +Modern x86 processors cores have Local Advanced Programmable Interrupt Controller (LAPIC) that delivers Inter-Processor Interrupts (IPIs) as well as external interrupts that I/O APIC, which is part of system's chipset, generates. Currently, Jailhouse virtualizes LAPIC only; I/O APIC is simply mapped to Linux cell, which is not quite safe because malicious guest (or Linux kernel module) can reprogram it to tamper with other guests work. + +LAPIC work in xAPIC or x2APIC mode. xAPIC is programmed via Memory Mapped I/O (MMIO), while x2AIPC uses MSRs. x2APIC is backward compatible with xAPIC, and its MSR addresses directly map to offsets in MMIO page. When apic_init() initializes APIC, it checks if x2APIC is enabled and sets up apic_ops access methods appropriately. Internally, Jailhouse refers to all APIC registers by their MSR addresses. For xAPIC, these values are transparently converted to the corresponding MMIO offsets (see read_xapic() and write_xapic() functions as examples). + +Jailhouse virtualizes APIC in both modes, however the mechanism is slightly different. For xAPIC, a special APIC access page (apic_access_page[PAGE_SIZE] defined in vmx.c) is mapped at XAPIC_BASE (0xfee00000) guest physical address via EPT. This happens in vmx_cell_init() (see "Cell initialization"). Later in vmcs_setup(), APIC virtualization is enabled and apic_access_page physical address is stored as APIC access address. This way, every time a guest tries to access virtual APIC MMIO region, VM exit occurs. No data is really read from apic_access_page or written to it, so CPUs can share this page. For x2APIC, normal MSR bitmaps are used. By default, Jailhouse traps access to all APIC registers. However, if apic_init() detects that host APIC is in x2APIC mode, the bitmap is changed so that only ICR (Interrupt Control Register) access is trapped. This happens when master CPU executes vmx_init() (see "Enabling Jailhouser"). + +There is a special case when a guest tries to access virtual x2APIC on a system where x2APIC is not really enabled. Here, MSR bitmap remains unmodified. Jailhouse intercepts access to all APIC registers and passes incoming requests to xAPIC using apic_ops access methods, effectively emulating x2APIC on top of xAPIC. Since APIC registers are referred in apic.c by their MSR addresses regardless the mode, this emulation has very little overhead. + +The main reason behind Jailhouse trapping ICR (and few other registers) access is isolation: a cell shouldn't be able to send an IPI to the CPU not in its own CPU set, and ICR is what defines the interrupt destination. To achieve isolation, apic_cpu_init() function that master CPU calls during initialization, stores apic_id to cpu_id mapping in the array of the same name. When CPU is assigned a Logical APIC ID, Jailhouse enforces it to be equal to cpu_id (see apic_mmio_access()). This way, when IPI is sent to physical or logical destination, the hypervisor is able to map it to cpu_id and check if the CPU is on the cell's set. See apic_deliver_ipi() for details. + +Now let's turn to interrupt handling. In vmcs_setup(), Jailhouse skips enabling external-interrupt exiting and sets exception bitmaps to all-zeroes. This means the the only interrupt that results in VM exit is Non-Maskable Interrupt (NMI). Everything else is dispatched through guest IDT and handled in guest mode. Since cells asserts full control on their own resources, this makes sense. + +Currently, NMIs can only come from the hypervisor itself (see TODO in apic_deliver_ipi() function) which uses them to control CPUs (suspend_cpu() is an example). When NMI occurs in VM, it exits and Jailhouse re-throws NMI in host mode. The CPU dispatches it through the host IDT and jumps to apic_nmi_handler(). It schedules another VM exit using VMX feature known as preemption timer. vmcs_setup() sets this timer to zero, so if it is enabled, VM exit occurs immediately after VM entry. The reason behind this indirection is serialization: this way, NMIs (which are asynchronous by nature) are always delivered after guest entries. + +At this next exit, vmx_handle_exit() calls apic_handle_events() which spins in a loop waiting for cpu_data->wait_for_sipi or cpu->stop_cpu to become false. suspend_cpu() sets cpu->stop_cpu flag and resume_cpu() clears it, and apic_deliver_ipi() function resets cpu_data->wait_for_sipi for a target CPU when delivering Startup IPI (SIPI). It also stores the vector SIPI contains in cpu_data->sipi_vector for later use (see "Creating a cell"). For Jailhouse-initiated CPU resets, arch_reset_cpu() sets sipi_vector to APIC_BSP_PSEUDO_SIPI (0x100, real SIPI vectors are always less than 0xff). + +Any other interrupt or exception in host mode is considered serious fault and results in panic. + +Creating a cell +================= + +To create a new cell, Jailhouse needs to shrink the Linux cell. It also obviously needs to load guest image and perform CPU reset to jump at the guest's entry point. + +This process starts in a Linux cell with the ioctl (JAILHOUSE_CELL_CREATE) that cause jailhouse_cell_create() function call in the Linux kernel. It copies cell configuration and guest image from userspace (jailhouse userspace tool reads these from files and stores in memory). Then, the cell's memory region is mapped as in jailhouse_enable() and guest image is moved to the target (physical) address specified by the user. After that, jailhouse_cell_create() calls standard Linux cpu_down() function to offline each CPU assigned to the new cell. This is required so Linux won't try to schedule processes on them anymore. Finally, the loader issues a hypercall (JAILHOUSE_HC_CELL_CREATE) using VMCALL instruction and passes a pointer to struct jailhouse_cell_desc that describe the new cell as its argument. This causes VM exit from the Linux cell to the hypervisor, and vmx_handle_exit() dispatches the call to the cell_create() function. + +cell_create() suspends all CPUs assigned to the cell except the one executing the function (if it is in cell's CPU set) to prevent races. This is done in cell_suspend() that indirectly signals an NMI (see "Handling interrupts") to each CPU and waits for cpu_stopped flag on target cpu_data. Then, the cell configuration is mapped from the Linux cell to per-CPU region above FOREIGN_MAPPING_BASE in host virtual address space (the loader copies this structure to Linux kernel memory). However, a caution should be taken not to step out of the region, which puts maximum size requirement on cell descriptor. Memory regions are checked as for Linux cell, and the new cell is allocated and initialized (see "Cell initialization"). After that, Linux cell is shrunk: all the new cell's CPUs are removed from its CPU set, page maps for guest physical addresses are destroyed, and the new cell's I/O resources have their bits set in parent cell's io_bitmap, so accessing them will result in VM exit (and panic). This is done in cell_create() and vmx_cell_shrink(). Finally, the new cell is added to the cells list (which is singly linked list having linux_cell as its head) and each CPU in the cell is reset using arch_cpu_reset(). It sends pseudo SIPI as described in "Handling interrupts". In a response, the hypervisor executes vmx_cpu_reset(). + +For pseudo SIPI, this function sets CS:RIP to 000f:fff0. Then it disables paging, protection, and 64-bit mode, and clears all segment selectors. On the next VM entry, the CPU will start executing code located at 0x000ffff0 in real mode. If you followed README instructions, it is just were apic-demo.bin 16-bit entry point is. The address 0x000ffff0 is different from real reset vector for x86 (0xfffffff0), and there is the reason. Jailhouse is not designed to run unmodified guests and has no BIOS emulation, so it can simplify boot process and skip A20 gate emulation required for real reset vector to work. When a guest modifies CR0 to enable protection and (later) paging, VM exit occurs and vmx_handle_cr() handles it. This function determines that the guest changes CR0 and calls update_efer() to check if the guest has requested 64-bit mode (LME bit in IA32_EFER is set, LMA bit is not set). If it is the case, Jailhouse sets LMA bit in guest IA32_EFER to reflect that IA-32e mode is on, and modifies VMCS to enable 64-bit mode on VM entry. You can follow these steps in inmate/header.S, which bootstraps apic-demo.bin guest. + +Cell initialization +------------------- + +Cells are represented by struct cell, defined in x86/include/asm/cell.h. This structure contains page table directories for VMX and VT-d, io_bitmap for VMX, cpu_set and other fields. It is initialized as follows. First, cell_init() copies a name for the cell from a descriptor and allocates cpu_data->cpu_set if needed (sets less than 64 CPUs in size are stored within struct cell in small_cpu_set field). Then, arch_cell_create(), the same function that shrinks Linux cell, calls vmx_cell_init() for the new one. The latter allocates VMX and VT-d resources (page directories and I/O bitmap), creates EPT mappings for guest physical address ranges (as per struct jailhouse_cell_desc), maps APIC access page (see "Handling interrupts") and copies I/O bitmap to struct cell from the cell descriptor (struct jailhouse_cell_desc). For linux_cell, master CPU calls this function during system-wide initializations. All of these are later applied to the VM in vmx_set_cell_config(). It is called either indirectly from vmx_cpu_init() during CPU initialization for Linux cell, or from vmx_cpu_reset() for the rest. + +When linux_cell is shrunk, jailhouse_cell_create() has already put detached CPUs offline (see "Creating a cell"). Linux never uses guest memory pages since they are taken from the region reserved at boot (see "Memory management"). However, Jailhouse currently takes no action to detach I/O resources and devices in general. If they were attached to Linux cell, they will remain attached, and it may cause panic if Linux driver tries to use an I/O port that moved to other cell. To prevent this, you should not assign these resources to Linux cell, or manually unload Linux driver for the device, or even blacklist it in Linux. + +Deleting a cell +=============== + +At the time of writing, Jailhouse had no support for cell destruction. However this feature has recently appeared in the development branch and will likely be available soon. When a cell is destroyed, its CPUs and memory pages are reassigned back to Linux cell, and other resources are also returned where they originate from. The CPUs are also moved to wait-for-SIPI mode ("parked"). + +Disabling Jailhouse +=================== + +To disable Jailhouse, the userspace tool issues JAILHOUSE_DISABLE ioctl which causes a call to jailhouse_disable(). This function calls leave_hypervisor() on each CPU in the Linux cell and waits for these calls to complete. Then hypervisor_mem mapping created in jailhouse_enable() is destroyed, the function brings up all offlined CPUs (which were presumably moved to other cells) and exits. From this point, Linux kernel runs bare-metal again. + +leave_hypervisor() simply issues JALIHOUSE_HC_DISABLE hypercall. It causes VM exit at the given CPU, and vmx_handle_exit() calls shutdown(). For the first Linux CPU that called it, this function iterates over CPUs in all cells other than Linux cell and calls arch_shutdown_cpu() for each of these CPUs; for the rest, it does nothing. arch_shutdown_cpu() is equivalent to suspending the CPU, setting cpu_data->shutdown_cpu to true and resuming it back. As described in "Handling interrupts", this transfers the control to apic_handle_events(), but this time this function detects that CPU is shutting down. It disables APIC and effectively executes VMXOFF; HLT to disable VMX on the CPU and halt it. This way, the hypervisor is disabled on all CPUs outside Linux cell. + +When shutdown() returns, VT-d is disabled and the hypervisor restores Linux environment for the CPU. First, cpu_data->linux_* fields are copied from VMCS guest area. Then, arch_cpu_restore() is called to disable VMX (without halting the CPU this time) and restore register values along with Linux GDT and IDT from cpu_data->linux_*. Afterwards, general purpose registers are popped from the hypervisor stack, Linux stack is restored, RAX is zeroed and RET instruction is issued. For Linux kernel, everything will look like leave_hypervisor() has returned successfully. This happens to each CPU in the Linux cell. After that, offlined CPUs (likely halted by arch_shutdown_cpu()) are brought back to the active state, as described earlier. + +Conclusion +========== + +Jailhouse is a young project that is developed in quick paces. It is lightweight VMM and does not intend to replace full-featured hypervisors like Xen or KVM, but this doesn't mean that Jailhouse itself is feature-limited. It is rare project that has a potential both in a classroom and in production, and we hope this article helped you to understand it better. + +Resources +========= + +1. +2. +3. +4. diff --git a/Documentation/bootstrap-interface.txt b/Documentation/bootstrap-interface.txt new file mode 100644 index 0000000000000000000000000000000000000000..425dcf3503a109dc4177447eddbc13d510b1608a --- /dev/null +++ b/Documentation/bootstrap-interface.txt @@ -0,0 +1,109 @@ +Bootstrap Interface +=================== + +The Jailhouse hypervisor is started by performing the following steps: + + - map physical memory region reserved for Jailhouse at fixed virtual address + JAILHOUSE_BASE (definition available via jailhouse/hypercall.h) + + - load its binary image at beginning of hypervisor memory region + + - load system configuration [1] at its target address in hypervisor memory + region [2] + + - set "Number of Possible CPUs" and "Number of Online CPUs" in hypervisor + header according to system state + + - initialize remaining hypervisor memory to zero + + - on each online CPU, call function at address stored in "Initialization + Function" hypervisor header field + + +Hypervisor Header +----------------- + +The hypervisor binary image starts with a header structure as defined in the +following. Its first part is preset during the build process of the hypervisor +core. The second part needs to be filled by the Linux driver that loads +Jailhouse. + + +Header Layout +- - - - - - - + + +------------------------------+ - begin of hypervisor header + | Signature "JAILHOUS" | (lower address) + | (8 bytes) | + +------------------------------+ + | Hypervisor Core Size | + | (unsigned long) | + +------------------------------+ + | Per-CPU Data Structure Size | + | (unsigned long) | + +------------------------------+ + | Address of Initialization | + | Function (pointer) | preset in binary image + +------------------------------+ - - - - - - - - - - - - - - - - - + | Number of Possible CPUs | set by driver while loading + | (unsigned int) | + +------------------------------+ + | Number of Online CPUs | + | (unsigned int) | + +------------------------------+ - higher address + +All fields use the native endianness of the system. + + +Field Descriptions +- - - - - - - - - - + +Hypervisor Core Size - size of hypervisor core, starting with its + header, ending after its bss section [2] +Per-CPU Data Structure Size - size of data structure used for a single + CPU +Address of Initialization Function - virtual address of initialization + function, see below +Number of Possible CPUs - 0 to possible CPUs - 1 defines the range + of CPU ID that can be passed as argument + to the initialization function +Number of Online CPUs - defines the number of CPUs the + initialization function will expect + + +Hypervisor Initialization Function +---------------------------------- + +The initialization function has to be called on each online CPU in order to +hand over control of the system to Jailhouse. Jailhouse will wait for as many +CPUs as specified in the "Number of Online CPUs" header field and will not +return from the function until all started the initialization. CPUs not +initialized during hypervisor activation cannot be used by any cell until +Jailhouse is deactivated again. + +Prototype: int entry(unsigned int cpu_id) + +Calling convention: as used by Linux kernel on target architecture + +Arguments: cpu_id - unique logical ID of caller's CPU + +Return code: 0 on success, negative error code otherwise + + Possible errors are: + -EIO (-5) - lacking hardware capabilities or unsupported hardware + state (as configured by Linux) + -ENOMEM (-12) - insufficient hypervisor-internal memory + -EBUSY (-16) - a required hardware resource is already in use + -ENODEV (-19) - CPU or I/O virtualization unit missing + -EINVAL (-22) - invalid system configuration + -ERANGE (-34) - a resource ID is out of supported range + +The initialization function will always return the same code on all CPUs for a +single initialization attempt. + + +References +---------- + +[1] Documentation/configuration-format.txt +[2] Documentation/memory-layout.txt diff --git a/Documentation/coding-style.txt b/Documentation/coding-style.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fcbfeb82c9f81b55e96b2e08cd406de977c1440 --- /dev/null +++ b/Documentation/coding-style.txt @@ -0,0 +1,42 @@ +Coding style +============ + +This document sets the coding style for Jailhouse code contributions. +In general, Jailhouse coding style for C is the same as for Linux kernel +(checkable with scripts/checkpatch.pl and detailed in +Documentation/CodingStyle), but with some notable variations and clarifications +described here (in random order): + +* Align function arguments vertically when wrapping over line breaks: + + void rather_long_function_name(struct another_rather_long_name *argument1, + struct yet_another_long_name *argument2); + +* Avoid conditional compilation (#ifdefs) where possible (and it's almost + always possible). Variations should be resolved during link time, or + (if absolutely necessary) in the runtime (but think about performance). + +* Do not explicitly initialize static variables you want zeroed. C standard + ensures this by default. + +* Do not insert blank lines in #include list, except to separate include blocks + where the second depends on the first one, e.g. + + #include + + #include + +* Always include generic headers ("jailhouse/*.h") before architecture + headers ("asm/*.h"). + +* Header files must be self-standing, i.e. must not rely on other headers being + included prior to them. Use scripts/header_check to validate. + +* Spaces in brackets are permitted for designated initializers in order to + improve readability via vertical alignment: + + [ 0/8 ... 0x1f/8] = 0, /* floppy DMA controller */ + [ 0x20/8 ... 0x3f/8] = -1, + [ 0x40/8 ... 0x47/8] = 0xf0, /* PIT */ + +For Python code, stick to PEP-8. diff --git a/Documentation/configuration-format.md b/Documentation/configuration-format.md new file mode 100644 index 0000000000000000000000000000000000000000..9588ef4d684cf69e82f04ec5b1bb5710ae57e93c --- /dev/null +++ b/Documentation/configuration-format.md @@ -0,0 +1 @@ +To be written... diff --git a/Documentation/debug-output.md b/Documentation/debug-output.md new file mode 100644 index 0000000000000000000000000000000000000000..b364bf0866f8300db594aa04f95df60036f24fa6 --- /dev/null +++ b/Documentation/debug-output.md @@ -0,0 +1,188 @@ +Jailhouse Debug Output +====================== + +System Configuration +-------------------- + +Jailhouse supports various debug output drivers. The debug output of the +hypervisor is selected in the system configuration inside the debug_console +structure. The 'type' member selects the output driver and the 'flags' member +specifies additional options. + +### .type and .flags +All architectures support the empty debug output driver, which is selected by +default if nothing else is chosen: + + - JAILHOUSE_CON_TYPE_NONE + +Possible debug outputs for x86: + + - JAILHOUSE_CON_TYPE_8250 /* 8250-compatible UART (PIO or MMIO) */ + - JAILHOUSE_CON_TYPE_EFIFB /* EFI framebuffer console */ + +Possible debug outputs for arm and arm64: + + - JAILHOUSE_CON_TYPE_8250 /* 8250 compatible UART*/ + - JAILHOUSE_CON_TYPE_PL011 /* AMBA PL011 UART */ + - JAILHOUSE_CON_TYPE_XUARTPS /* Xilinx UART */ + - JAILHOUSE_CON_TYPE_MVEBU /* Marvell UART */ + - JAILHOUSE_CON_TYPE_HSCIF /* Renesas HSCIF UART */ + - JAILHOUSE_CON_TYPE_SCIFA /* Renesas SCIFA UART */ + - JAILHOUSE_CON_TYPE_SCIF /* Renesas SCIF UART */ + - JAILHOUSE_CON_TYPE_IMX /* NXP i.MX UART */ + - JAILHOUSE_CON_TYPE_IMX_LPUART/* NXP i.MX LPUART */ + +Possible access modes, to be or'ed: + + - JAILHOUSE_CON_ACCESS_PIO /* PIO, x86 only */ + - JAILHOUSE_CON_ACCESS_MMIO /* MMIO, x86 and ARM */ + +Possible register distances (MMIO only, PIO is implicitly 1-byte), to be or'ed: + + - JAILHOUSE_CON_REGDIST_1 /* 1-byte distance */ + - JAILHOUSE_CON_REGDIST_4 /* 4-bytes distance */ + +Possible framebuffer formats (EFIFB only); + + - JAILHOUSE_CON_FB_1024x768 /* 1024x768 pixel, 32 bit each */ + - JAILHOUSE_CON_FB_1920x1080 /* 1920x1080 pixel, 32 bit each */ + +### .address and .size +The address member denotes the base address of the Debug console (PIO or MMIO +base address). The .size parameter is only required for MMIO. + +### .divider +An optional UART divider parameter that can be passed to the driver. This is +supported by the 8250 driver. + +A zero value means that the hypervisor or the inmate will skip the +initialisation of the UART console. This is the case in most scenarios, as the +hypervisor's UART console was initialised by Linux before. + +Defaults to 0. + +### .clock_reg and .gate_nr +If Linux does not initialise the UARTs, Jailhouse has to initialise them on +its own. Some UARTs require to gate a clock before the UART can be used. + +Ignored if "clock_reg" is 0, both default to 0. + +Clock gating is currently only supported on 32-bit ARM. + +### Examples +Example configuration for PIO based debug output on x86: + + .debug_console = { + .address = 0x3f8, /* PIO address */ + .divider = 0x1, /* 115200 Baud */ + .type = JAILHOUSE_CON_TYPE_8250, /* choose the 8250 driver */ + .flags = JAILHOUSE_CON_PIO, /* chose PIO register access */ + }, + +Example configuration for MMIO based debug output on ARM (8250 UART): + + .debug_console = { + .address = 0x70006300, /* MMIO base address */ + .size = 0x40, /* size */ + .clock_reg = 0x60006000 + 0x330, /* Optional: Debug Clock Register */ + .gate_nr = (65 % 32), /* Optional: Debug Clock Gate Nr */ + .divider = 0xdd, /* 115200 */ + .type = JAILHOUSE_CON_TYPE_8250, /* choose the 8250 driver */ + .flags = JAILHOUSE_CON_MMIO_32, /* choose 32-bit MMIO access */ + }, + +Example configuration for EFI framebuffer debug out on x86: + + .debug_console = { + .address = 0x80000000, /* framebuffer base address */ + .size = 0x300000, /* 1024x768x4 */ + .type = JAILHOUSE_CON_TYPE_EFIFB, /* choose the EFIFB driver */ + .flags = JAILHOUSE_CON_MMIO | \ /* access is MMIO */ + JAILHOUSE_CON_FB_1024x768 /* format */ + }, + +Example configuration for disabled debug output (architecture independent): + + .debug_console = { + .flags = JAILHOUSE_CON_TYPE_NONE, + } + + +Jailhouse Virtual Console +------------------------- + +If the system configuration has the flag JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE +set, the hypervisor console is available through +/sys/devices/jailhouse/console. Continuous reading of the hypervisor console +is available through /dev/jailhouse. + +Example + + cat /dev/jailhouse + or + jailhouse console -f + +If a cell configuration of a non-root cells has the flag +JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED set, the inmate is allowed to use the +dbg_putc hypercall to write to the hypervisor console. This is useful for +debugging, as the root cell is able to read the output of the inmate. + +The flag JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE implies +JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED and shall cause the inmate to +automatically use the virtual console as an output path. + + +Jailhouse Inmates +----------------- + +As well as the hypervisor, inmates choose their output driver during runtime. +By default, the particular driver is chosen by the "console" field in the +non-root cell configuration. This field is passed to the inmate via the +communication region. If a non-root cell has the flag +JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE set, Jailhouse inmates will additionally +write to the Jailhouse virtual console. + +The default remains off, and the administrator is expected to grant this +permission only temporarily while debugging a specific cell. Note that output +might be duplicated, if the hypervisor shares the console with the inmate. + +The "console" parameters of the cell's configration may always be overrided by +inmate command line parameters. + +### Parameter list +| Parameter | Description | x86 | ARM and ARM64 | +|:--------------|:------------------------------|:-------------------|:--------------------------------| +| con-type | Primary Debug Output Driver | see below | see below | +| con-base | PIO/MMIO Base Address | e.g. 0x3f8 | e.g. 0x70006000 | +| con-divider | UART divider | 0x1 | 0x0d | +| con-clock-reg | Clock Register | not supported | | +| con-gate-nr | Clock Gate Nr | not supported | | +| con-regdist-1 | MMIO: 8 bit register distance | true / false | true / false | +| con-is-mmio | MMIO'ed access mode | true / false | not supported, ARM is MMIO only | +| con-virtual | Use secondary virtual console | true / false | true / false | + +Available debug output drivers (con-type=): +x86: none, 8250 +arm: none, 8250, hscif, imx, mvebu, pl011, scifa, xuartps + +Similar to the hypervisor configuration, a zero value for con-divider will skip +initialisation of the UART interface. + +On x86, EFI framebuffer output is not available for inmates. + +### Examples +Example command line parameters for PIO based debug output on x86, where the +inmate will initialise UART: + + jailhouse cell load foocell inmate.bin \ + -s "con-base=0x3f8 con-is-mmio=false con-divider=1" -a 0x1000 + +Example configuration for MMIO based debug output on ARM using the 8250 driver: + + jailhouse cell load foocell inmate.bin \ + -s "con-type=8250 con-is-mmio=true con-base=0x70006000 con-divider=0xdd" -a 0x1000 + +Example configuration for MMIO based debug output on ARM64 using the PL011 driver: + + jailhouse cell load foocell inmate.bin \ + -s "con-type=PL011 con-is-mmio=true con-base=0xf7113000" -a 0x1000 diff --git a/Documentation/gcov.txt b/Documentation/gcov.txt new file mode 100644 index 0000000000000000000000000000000000000000..27a25862e50fa69b9a414916aaa844787616a6da --- /dev/null +++ b/Documentation/gcov.txt @@ -0,0 +1,50 @@ +Extracting code coverage information from the hypervisor +======================================================== + +Jailhouse supports collecting code coverage information while it is running. +In order to use that feature you have to set CONFIG_JAILHOUSE_GCOV in the +configuration system. (see Documentation/hypervisor-configuration.md) + +Now rebuild jailhouse and run your favorite example cell. Follow the usual +workflow until `jailhouse disable`, but do not unload the jailhouse kernel +module. + +While the module is loaded but the hypervisor is not running anymore, you can +get a copy of the hypervisor-image containing runtime data. And that data +includes code coverage information. The jailhouse tools allow you to extract +gcov data from that image (*.gcda-files). And these files can be processed by +a number of higher level tools. + +Example workflow +---------------- +# enter jailhouse source directory +cd /path/to/jailhouse +# remove *.gcda files from previous run +find -iname *.gcda -exec rm -f {} + +# now run jailhouse until you eventually "disable" it again +..... +jailhouse disable +# extract the *.gcda files, which will be placed in the src directory +./tools/jailhouse-gcov-extract +# at that point you can use higher level tools to process the data +# here an example for generating an html-report with +# lcov (http://ltp.sourceforge.net/coverage/lcov.php) +lcov -o /tmp/coverage.info --capture -d . +genhtml /tmp/coverage.info --output-directory /tmp/coverage/ +firefox /tmp/coverage/index.html + +Cross Compiled +-------------- +If you have cross compiled jailhouse you will need to copy the +jailhouse-gcov-extract tool over to your target and execute it when you want +to collect the statistics. The sources and *.gcno-files are not required on +the target, just on the machine where you process the data further. + +Using the tool, the *.gcda-files will be generated in the directory jailhouse +was built in on your build machine. If the tool fails to create the *.gcda- +files, make sure the base directory exists and is writeable for your user. + +From there copy the files back to your build host and process them further +with higher level tools like lcov. Make sure to use gcov and other tools from +your cross toolchain. For the above example and an ARM32 toolchain you would +have to add "--gcov-tool arm-linux-gnueabihf-gcov" to the lcov invocation. diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt new file mode 100644 index 0000000000000000000000000000000000000000..80e462ccc635d4e7994a58bc40be8df9ff6584d4 --- /dev/null +++ b/Documentation/glossary.txt @@ -0,0 +1,40 @@ +Glossary +======== + +Hypervisor +---------- +System management software that runs at a higher privileged level than any +operating system or application software. It furthermore defines if software +at lower privilege levels has direct access to resources, if access should be +denied or trapped and the hypervisor code invoked on such events. + +Hypervisor Mode +--------------- +Execution mode of a CPU while executing hypervisor code. + +Guest Mode +---------- +Execution mode of a CPU while executing an operating system or application +software in an isolated environment under the control of the hypervisor. + +Cell +---- +Protection domain for an operating systems with its application software in +the context of Jailhouse. A cell is granted exclusive or intercepted and +moderated access to system resources like CPUs, RAM or I/O devices. + +Root Cell +--------- +The cell that contains the Linux system which originally started Jailhouse. +The root cell cannot be destroyed, thus exists as long as Jailhouse is active. + +Non-Root Cell +------------- +Any cell started after the root cell under the control of Jailhouse. There can +be as many non-root cells as required resources are available, Non-root cells +can be destroyed under certain conditions while Jailhouse is running. + +Sysfs +----- +Linux filesystem that provides a means to export kernel data structures, their +attributes, and the linkages between them to userspace. diff --git a/Documentation/hypervisor-configuration.md b/Documentation/hypervisor-configuration.md new file mode 100644 index 0000000000000000000000000000000000000000..7d6120915c87e12be5430abec00aa75a3703b41a --- /dev/null +++ b/Documentation/hypervisor-configuration.md @@ -0,0 +1,39 @@ +Hypervisor Configuration +======================== + +Jailhouse supports various static compile-time configuration +parameters, such as platform specific settings and debugging options. +Those settings can optionally be defined in +'include/jailhouse/config.h'. +Every configuration option should be defined to "1" or not be in the file at +all. Defining any other value can cause unexpected behaviour. + +Available configuration options +------------------------------- + +General configuration parameters + + /* Print error sources with filename and line number to debug console */ + #define CONFIG_TRACE_ERROR 1 + + /* + * Set instruction pointer to 0 if cell CPU has caused an access violation. + * Linux inmates will dump a stack trace in this case. + */ + #define CONFIG_CRASH_CELL_ON_PANIC 1 + + /* Enable code coverage data collection (see Documentation/gcov.txt) */ + #define CONFIG_JAILHOUSE_GCOV 1 + + /* + * Link inmates against a custom base address. Only supported on ARM + * architectures. If this parameter is defined, inmates must be loaded to + * the appropriate location. + */ + #define CONFIG_INMATE_BASE 0x90000000 + + /* + * Only available on x86. This debugging option that needs to be activated + * when running mmio-access tests. + */ + #define CONFIG_TEST_DEVICE 1 diff --git a/Documentation/hypervisor-interfaces.txt b/Documentation/hypervisor-interfaces.txt new file mode 100644 index 0000000000000000000000000000000000000000..d888dab7f79dded9ce1f53ee6410a94d8d1a4742 --- /dev/null +++ b/Documentation/hypervisor-interfaces.txt @@ -0,0 +1,509 @@ +Hypervisor Interface for Cells +============================== + +The Jailhouse hypervisor provides three kinds of interfaces to interact with +its cells during runtime. The first is a read-only detection interface. The +second is a set of hypercalls which cells can invoke synchronously by executing +architecture specific instructions that switch to hypervisor mode. The third +interface consists of variables located in a per-cell memory region that is +shared between hypervisor and that particular cell. + + +Detection +--------- + +This interface is useful for cell code that should work not only inside a +Jailhouse cell. The ABI is architecture specific. So far, it is only available +for x86. + + +x86 ABI +- - - - + +On x86, Jailhouse modifies the register values returned when executing the +cpuid instruction as follows: + + +Function (EAX): 0x01 +Result in EAX: passed unmodified + EBX: passed unmodified + ECX: bit 31 ("hypervisor") set, all other bits passed unmodified + EDX: passed unmodified + +Note: A cell should first check if bit 31 is set in ECX before querying the +signature function 0x40000000. + + +Function (EAX): 0x40000000 (signature) +Result in EAX: highest supported hypervisor function, currently 0x40000001 + EBX: 0x6c69614a ("Jail") + ECX: 0x73756f68 ("hous") + EDX: 0x00000065 ("e") + +Note: A cell should first validate the presence of Jailhouse via both checking +the hypervisor feature bit (function 31) and then the signature (function +0x40000000) before evaluating the returned values of the feature function +0x40000001. + + +Function (EAX): 0x40000001 (features) +Result in EAX: 0 + EBX: 0 + ECX: 0 + EDX: 0 + + +Hypercalls +---------- + +A hypercall is typically issued via a designated instruction that causes a +context switch from guest to hypervisor mode. Before causing the mode switch, a +cell has to prepare potential arguments of the call in predefined registers or +a known memory location. A return code of the completed hypercall is passed via +a similar channel. Details of the hypercall ABI are architecture specific and +will be defined in the following. + + +x86 ABI +- - - - + +Instruction: vmcall (IA-32/32e) / vmmcall (AMD64) +Hypercall code: EAX +1. argument: RDI (64-bit mode) / EDI (32-bit mode) +2. argument: RSI (64-bit mode) / ESI (32-bit mode) +Return code: EAX + + +ARMv7 ABI +- - - - - + +Instruction: hvc #0x4a48 +Hypercall code: r0 +1. argument: r1 +2. argument: r2 +Return code: r0 + + +ARMv8 ABI +- - - - - + +Instruction: hvc #0x4a48 +Hypercall code: x0 +1. argument: x1 +2. argument: x2 +Return code: x0 + + +Hypercall "Disable" (code 0) +- - - - - - - - - - - - - - - + +Tries to shuts down the hypervisor, returning full control over the hardware +back to Linux. All non-root cells must have been destroyed prior to issuing +this hypercall. The hypercall has to be invoked on all CPUs of the root cell to +achieve a consistent shutdown. + +This hypercall can only be issued on CPUs belonging to the Linux cell. + +Arguments: None + +Return code: 0 on success, negative error code otherwise + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-Linux cell or an active + cell rejected the shutdown request + -EBUSY (-16) - one or more non-root cells still exist + + +Hypercall "Cell Create" (code 1) +- - - - - - - - - - - - - - - - - + +Creates a new cell according to the provided configuration. The cell's memory +content will not be initialized, and the cell will be put in suspended state, +i.e. no code is executed on its CPUs after this hypercall completed. + +This hypercall can only be issued on CPUs belonging to the Linux cell. + +Arguments: 1. Guest-physical address of cell configuration (see [2] for + details) + +Return code: 0 on success or negative error code + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell or an active + cell locked the cell configurations + -E2BIG (-7) - configuration data too large to process + -ENOMEM (-12) - insufficient hypervisor-internal memory + -EBUSY (-16) - a resource of the new cell is already in use by another + non-root cell, or the caller's CPU is supposed to be + given to the new cell + -EEXIST (-17) - a cell with the given name or id already exists + -EINVAL (-22) - incorrect or inconsistent configuration data + + +Hypercall "Cell Start" (code 2) +- - - - - - - - - - - - - - - - + +Sets all cell CPUs to an architecture-specific start state and resumes +execution of the cell if it was previously suspended. At least one CPU will +then execute the bootstrap code that must have been loaded into the cell's +memory at the reset address before invoking this hypercall. See [1] for details +on the start state of cell CPUs. In addition, access from the root cell to +memory regions of this cell that are marked "loadable" [2] is revoked. + +This hypercall can only be issued on CPUs belonging to the Linux cell. + +Arguments: 1. ID of target cell + +Return code: 0 on success or negative error code + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell or the target + cell rejected the reset request + -ENOENT (-2) - cell with provided ID does not exist + -EINVAL (-22) - root cell specified, which cannot be started + + +Hypercall "Cell Set Loadable" (code 3) +- - - - - - - - - - - - - - - - - - - - + +Shuts down a running cell and enables (re-)loading of their memory regions that +are marked "loadable" in the cell's configuration. This is achieved by mapping +the marked regions into the root cell. + +Arguments: 1. ID of target cell + +Return code: 0 on success or negative error code + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell or the target + cell rejected the shutdown request + -ENOENT (-2) - cell with provided ID does not exist + -EINVAL (-22) - root cell specified, which cannot be set loadable + + +Hypercall "Cell Destroy" (code 4) +- - - - - - - - - - - - - - - - - + +Destroys the cell of the provided name, returning its resources to the root +cell if they are part of the system configuration, i.e. belonged to the root +cell directly after hypervisor start. + +This hypercall can only be issued on CPUs belonging to the root cell. + +Arguments: 1. ID of cell to be destroyed + +Return code: 0 on success, negative error code otherwise + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell, the target + cell rejected the destruction request or another active + cell locked the cell configurations + -ENOENT (-2) - cell with provided ID does not exist + -ENOMEM (-12) - insufficient hypervisor-internal memory for + reconfiguration + -EINVAL (-22) - root cell specified, which cannot be destroyed + +Note: The root cell uses ID 0. Passing this ID to "Cell Destroy" is illegal. + + +Hypercall "Hypervisor Get Info" (code 5) +- - - - - - - - - - - - - - - - - - - - - + +Obtain information about specific hypervisor states. + +Arguments: 1. Information type: + 0 - number of pages in hypervisor memory pool + 1 - used pages of hypervisor memory pool + 2 - number of pages in hypervisor remapping pool + 3 - used pages of hypervisor remapping pool + 4 - number of registered cells + +Return code: Requested value (>=0) or negative error code + + Possible errors are: + -EINVAL (-22) - invalid information type + + +Hypercall "Cell Get State" (code 6) +- - - - - - - - - - - - - - - - - - + +Obtain information about the state of a specific cell. + +Arguments: 1. ID of cell to be queried + +This hypercall can only be issued on CPUs belonging to the root cell. + +Return code: Cell state (>=0) or negative error code + + Valid cell states are: + 0 - Running + 1 - Shut down + 2 - Failed + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell + -EINVAL (-22) - cell state is invalid + + +Hypercall "CPU Get Info" (code 7) +- - - - - - - - - - - - - - - - - + +Obtain information about a specific CPU. + +Arguments: 1. Logical ID of CPU to be queried + 2. Generic information type: + 0 - CPU state + 1000 - Total number of VM exits + 1001 - VM exits due to MMIO accesses + 1002 - VM exits due to management events + 1003 - VM exits due to hypercalls + + x86-specific type: + + 1004 - VM exits due to PIO accesses + 1005 - VM exits due to xAPIC accesses + 1006 - VM exits due to CR accesses + 1007 - VM exits due to CPUID instructions + 1008 - VM exits due to XSETBV instructions + 1009 - VM exits due to exceptions + 1010 - VM exits due to unspecified MSR accesses + 1011 - VM exits due to x2APIC ICR MSR accesses + + ARMv7/ARMv8-specific type: + + 1004 - VM exits due to maintenance IRQs + 1005 - VM exits due to IRQ injections + 1006 - VM exits due to SGI injections + 1007 - VM exits due to PSCI calls + 1008 - VM exits due to SMCCC calls + 1009 - VM exits due to CP15 accesses (only ARMv7) + +Statistic counters are reset when a CPU is assigned to a different cell. The +total number of VM exits may be different from the sum of all specific VM exit +counters. + +Return code: Requested value (>=0) or negative error code + + Possible CPU states are: + 0 - Running + 2 - Failed + + Possible errors are: + -EPERM (-1) - hypercall was issued over a non-root cell and the CPU + does not belong to the issuing cell + -EINVAL (-22) - invalid CPU ID + + +Hypercall "Debug Console putc" (code 8) +- - - - - - - - - - - - - - - - - - - - + +Write a single character to the hypervisor's debug console. + +Arguments: 1. character to write + +Return code: 0 on success, negative error code otherwise + + Possible errors are: + -EPERM (-1) - cell lacks JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED + flag in its configuration + + +Communication Region +-------------------- + +The communication region is a per-cell shared memory area that both the +hypervisor and the particular cell can read from and write to by default. It is +an optional communication mechanism. If the region shall be used by a cell, it +has to be mapped into the cell's address space via its configuration (see [2] +for details). If the cell is configured to be passive with respect to the +communication region (cell flag JAILHOUSE_CELL_PASSIVE_COMMREG) and the region +is mapped, it has to be declared read-only in the cell configuration. + + +Communication region layout +- - - - - - - - - - - - - - + + +------------------------------+ - begin of communication region + | Signature "JHCOMM" (6 byte) | (lower address) + +------------------------------+ + | ABI Revision (16 bit) | + +------------------------------+ + | Cell State (32 bit) | + +------------------------------+ + | Message to Cell (32 bit) | + +------------------------------+ + | Message from Cell (32 bit) | + +------------------------------+ + : Generic Platform Information : + +------------------------------+ + : Architecture-specific : + : Platform Information : + +------------------------------+ - higher address + +All fields use the native endianness of the system. The format is of the +Platform Information part is architecture-specific. Its content is filled by +the hypervisor during cell creation and shall be considered read-only until +cell destruction. + +The ABI revision described here is 2. Future versions may not use a compatible +layout or field semantic, except for the fields "Signature", "ABI Revision" and +"Cell State". + + +Logical Channel "Message" +- - - - - - - - - - - - - + +The first logical channel of the region is formed by the fields "Message to +Cell" and "Message from Cell". The hypervisor uses this channel to inform the +cell about specific state changes in the system or request permission to +perform state changes that the cell can affect. + +Before the hypervisor sends a new message, it first sets the "Message from +Cell" field to 0. It then writes a non-zero message code in the "Message to +Cell" field. Finally the hypervisor reads from the "Message from Cell" field +in order to receive the cell's answer. + +For answering a message, the cell first has to clear the "Message to Cell" +field. It then has to write a non-zero reply code into the "Message from Cell" +field. If a cell receives an unknown message code, it has to send the reply +"Message unknown" (code 1). + +Write ordering of all updates has to be ensured by both the hypervisor +and the cell according to the requirements of the hardware architecture. + +The hypervisor may wait for a message reply by spinning until the "Message from +Cell" field becomes non-zero. Therefore, a cell should check for pending +messages periodically and answer them as soon as possible. The hypervisor will +not use a CPU assigned to non-root cell to wait for message replies, but long +message responds times may still affect the root cell negatively. + +The following messages and corresponding replies are defined: + + - Shutdown Request (code 1): + The cell is supposed to be shut down, either to destroy only the cell + itself or to disable the hypervisor completely. + + Possible replies: + 2 - Request denied + 3 - Request approved + + Note: The hypervisor does not request shutdown permission from a cell if + that cell has the "Passive Communication Region" flag set in its + configuration (see also [2]) or if the cell state is set to "Shut + Down" or "Failed" (see below). + + - Reconfiguration Completed (code 2): + A cell configuration was changed. This message is for information only + but has to be confirmed on reception nevertheless. + + Possible replies: + 4 - Message received + + Note: The hypervisor does not expect reception confirmation from a cell if + that cell has the "Passive Communication Region" flag set in its + configuration (see also [2]) or if the cell state is set to "Shut + Down" or "Failed" (see below). + + +Logical Channel "Cell State" +- - - - - - - - - - - - - - - + +The cell state field provides the second logical channel. On cell startup, it +is initialized by the hypervisor to the state "Running". From then on, the +field becomes conceptually read-only for the hypervisor and will only be +updated by the cell until a terminal state is reached. The following states are +defined: + + - Running (code 0) + - Running, cell configurations locked (code 1) + - Shut down (code 2), terminal state + - Failed (code 3), terminal state + - Communication region ABI mismatch (code 4), terminal state + +Once a cell declared to have reached a terminal state, the hypervisor is free +to destroy or restart that cell. On restart, it will also reset the state field +to "Running". + + +Generic Platform Information +- - - - - - - - - - - - - - - + + +--------------------------------------+ - begin of communication region + : header, see above : (lower address) + +--------------------------------------+ + | Information Flags (32 bit) | + +--------------------------------------+ + | Console Address (64 bit) | + +--------------------------------------+ + | Console Size (32 bit) | + +--------------------------------------+ + | Console Type (16 bit) | + +--------------------------------------+ + | Console Flags (16 bit) | + +--------------------------------------+ + | Console UART Divider (32 bit) | + +--------------------------------------+ + | Console UART Gate No. (32 bit) | + +--------------------------------------+ + | Console UART Clock Register (64 bit) | + +--------------------------------------+ + | PCI MMCONFIG Address (64 bit) | + +--------------------------------------+ + : Architecture-specific : + : Platform Information : + +--------------------------------------+ - higher address + +The Information Flags field defines two bits so far: Bit 0 is set when the cell +may use the Debug Console putc hypercall. Bit 1 is set when the cell shall use +the Debug Console putc hypercall as output console. Other bits in this field +are reserved. + +See [3] for a description of the console fields. + + +Platform Information for x86 +- - - - - - - - - - - - - - - + + +--------------------------------------+ - begin of communication region + : header, see above : (lower address) + +--------------------------------------+ + : generic information, see above : + +--------------------------------------+ + | PM Timer Address (16 bit) | + +--------------------------------------+ + | Number of CPUs (16 bit) | + +--------------------------------------+ + | TSC Frequency in kHz (32 bit) | + +--------------------------------------+ + | APIC Timer Frequency in kHz (32 bit) | + +--------------------------------------+ - higher address + + +Platform Information for ARMv7 and ARMv8 +- - - - - - - - - - - - - - - - - - - - - + + +--------------------------------------+ - begin of communication region + : header, see above : (lower address) + +--------------------------------------+ + : generic information, see above : + +--------------------------------------+ + | GIC Version (8 bit) | + +--------------------------------------+ + | Reserved (56 bit) | + +--------------------------------------+ + | GIC Distributor Address (64 bit) | + +--------------------------------------+ + | GIC CPU Interface Address (64 bit) | + +--------------------------------------+ + | GIC Redistributor Address (64 bit) | + +--------------------------------------+ + | Virtual PCI Host IRQ Base (32 bit) | + +--------------------------------------+ - higher address + + +References +---------- + +[1] Documentation/cell-environments.txt +[2] Documentation/configuration-format.txt +[3] Documentation/debug-output.md diff --git a/Documentation/inter-cell-communication.md b/Documentation/inter-cell-communication.md new file mode 100644 index 0000000000000000000000000000000000000000..eeed987631bb4af01009999432b1a4fa5741d71a --- /dev/null +++ b/Documentation/inter-cell-communication.md @@ -0,0 +1,131 @@ +Inter-Cell communication of the Jailhouse Hypervisor +==================================================== + +The hypervisor isolates cells but sometimes there is a need to exchange data +between cells. For that purpose Jailhouse provides shared memory and signaling +between cells via virtual ivshmem PCI devices. This device type is specified +in [1]. + + +Adding Inter-cell communication +------------------------------- + +In order to set up a communication channel between two or more cells you first +have to add memory regions to both cells. Each cell needs the follow regions: + + - read-only region to hold state table, generally one page large + - one region that is read/writable for all peers + - one output region per peer that is only read-writeable for one of them + +With 2 peers connected, this means a consecutive series of 4 regions needs to +be created. When connecting 3 peers, 5 regions are needed, and so on. All +regions must also be consecutive in guest-physical memory because only the +address for the first region is communicated to the guest. + +The second, common read-write region is optional and can be zero-sized. Also +the output regions are optional. All output regions must have the same size. +Write permission to the first output region must only be granted to the cell +that has the ivshmem device ID 0, write permission to the second region must be +granted to ID 1, and so forth. + +Non-root cells sharing memory with the root cell need the memory flag +`JAILHOUSE_MEM_ROOTSHARED` on the region. + +To define the memory regions of an ivshmem-net device, the macro +`JAILHOUSE_SHMEM_NET_REGIONS(base_address, id)` is provided. It uses 1 MB of +memory at the specified base address and assigns access according to the +specified ID. Shared memory based network devices only connect 2 peers, thus +4 memory regions will be added. + +After creating the memory regions, also a PCI device needs to be added to each +connected cell. Set the device type to `JAILHOUSE_PCI_TYPE_IVSHMEM`. The `bdf` +field must specify an unused bus-device-function slot on a physical or virtual +PCI controller. All connected peers must use the same `bdf` value in order to +establish the link. They may use different `domain` values, though. + +Set the bar_mask to either `JAILHOUSE_IVSHMEM_BAR_MASK_MSIX` or +`JAILHOUSE_IVSHMEM_BAR_MASK_INTX`, depending on whether MSI-X is available or +not. When MSI-X is used, num_msix_vectors must be set according to the needs of +the shared memory protocol used on the link. For ivshmem networking, grant 2 +vectors. + +Further fields needed: + - `shmem_regions_start` - index of first shared memory region used by device + - `shmem_dev_id` - ID of the peer (0..`shmem_peers`-1) + - `shmem_peers` - maximum number of connected peers + - `shmem_protocol` - shared memory protocol used over the link + +Set `shmem_protocol` to JAILHOUSE_SHMEM_PROTO_VETH for ivshmem networking, use +`JAILHOUSE_SHMEM_PROTO_UNDEFINED` for custom protocols, or pick an ID from the +custom range defined in [1]. + +You may also need to set the `iommu` field to match the IOMMU unit that the +guest expects based on the `bdf` value. Try 1 if MSI-X interrupts do not make +it when using 0. + +For an example have a look at the cell configuration files `qemu-x86.c`, +`ivshmem-demo.c`, and `linux-x86-demo.c` in `configs/x86`. + + +Demo code +--------- + +The first demo case is the peer-to-peer networking device ivshmem-net. Virtual +networking is pre-configured in most ARM and ARM64 targets as well as in the +qemu-x86 virtual one. Also all targets supported by the demo image generator +[3] have this feature enabled. It depends on the ivshmem-net driver that is +available through the Linux kernel for Jailhouse, see [3] and jailhouse-enabling +branches in [4]. + +Some targets, e.g. qemu-x86, qemu-arm64 and orangepi0, have a raw ivshmem +multi-peer demo preconfigured. It can be used by running the ivshmem-demo +application under Linux and loading ivshmem-demo.bin into bare-metal cell. The +Linux application is also a demonstrator for the uio_ivshmem driver, providing +unprivileged access to a ivshmem device it regular processes. See the code in +`tools/ivshmem-demo.c` for details on the usage. The bare-metal ivshmem-demo is +loaded under x86 into the ivshmem-demo.cell while ARM and ARM64 use a +*-inmate.demo.cell corresponding to the target. + +There is also work-in-progress support for transporting virtio over ivshmem. +Note that this is still experimental and can change until it may become part of +the official virtio specification. + +Two virtio-ivshmem demo cases are prepared so far for qemu-x86, one providing a +virtio console from the root cell to the Linux non-root cell, the other a +virtio block device. Starting the demo requires a number of manual steps at +this point. Under the root cell, execute + + echo "110a 4106 110a 4106 ffc003 ffffff" > \ + /sys/bus/pci/drivers/uio_ivshmem/new_id + +to bind the UIO driver to the ivshmem device acting as virtio console backend. +Then run + + virtio-ivshmem-console /dev/uio1 + +This tool can be built in the `tools/virtio` directory of [3]. Now you can +start a non-root Linux cell with `console=hvc0`, interacting with it in the +shell that runs the backend application. Make sure that the non-root Linux +kernel has the driver `virtio_ivshmem` (`CONFIG_VIRTIO_IVSHMEM`) from [3] +enabled. + +Analogously, you can create a virtio block backend by running + + echo "110a 4106 110a 4106 ffc002 ffffff" > \ + /sys/bus/pci/drivers/uio_ivshmem/new_id + +in the root cell. Then start the backend service like this: + + virtio-ivshmem-block /dev/uio2 /path/to/disk.image + +The disk will show up as /dev/vda in the non-root Linux and can be accessed +normally. + + +References +---------- + +[1] Documentation/ivshmem-v2-specification.md +[2] https://github.com/siemens/jailhouse-images +[3] http://git.kiszka.org/?p=linux.git;a=shortlog;h=refs/heads/queues/jailhouse +[4] https://github.com/siemens/linux diff --git a/Documentation/ivshmem-v2-specification.md b/Documentation/ivshmem-v2-specification.md new file mode 100644 index 0000000000000000000000000000000000000000..81ba300be6d80acfa74cfbe22a0cc56984b3738d --- /dev/null +++ b/Documentation/ivshmem-v2-specification.md @@ -0,0 +1,380 @@ +IVSHMEM Device Specification +============================ + +** NOTE: THIS IS WORK-IN-PROGRESS, NOT YET A STABLE INTERFACE SPECIFICATION! ** + +The goal of the Inter-VM Shared Memory (IVSHMEM) device model is to +define the minimally needed building blocks a hypervisor has to +provide for enabling guest-to-guest communication. The details of +communication protocols shall remain opaque to the hypervisor so that +guests are free to define them as simple or sophisticated as they +need. + +For that purpose, the IVSHMEM provides the following features to its +users: + +- Interconnection between up to 65536 peers + +- Multi-purpose shared memory region + + - common read/writable section + + - output sections that are read/writable for one peer and only + readable for the others + + - section with peer states + +- Event signaling via interrupt to remote sides + +- Support for life-cycle management via state value exchange and + interrupt notification on changes, backed by a shared memory + section + +- Free choice of protocol to be used on top + +- Protocol type declaration + +- Register can be implemented either memory-mapped or via I/O, + depending on platform support and lower VM-exit costs + +- Unprivileged access to memory-mapped or I/O registers feasible + +- Single discovery and configuration via standard PCI, no complexity + by additionally defining a platform device model + + +Hypervisor Model +---------------- + +In order to provide a consistent link between peers, all connected +instances of IVSHMEM devices need to be configured, created and run +by the hypervisor according to the following requirements: + +- The instances of the device shall appear as a PCI device to their + users. + +- The read/write shared memory section has to be of the same size for + all peers. The size can be zero. + +- If shared memory output sections are present (non-zero section + size), there must be one reserved for each peer with exclusive + write access. All output sections must have the same size and must + be readable for all peers. + +- The State Table must have the same size for all peers, must be + large enough to hold the state values of all peers, and must be + read-only for the user. + +- State register changes (explicit writes, peer resets) have to be + propagated to the other peers by updating the corresponding State + Table entry and issuing an interrupt to all other peers if they + enabled reception. + +- Interrupts events triggered by a peer have to be delivered to the + target peer, provided the receiving side is valid and has enabled + the reception. + +- All peers must have the same interrupt delivery features available, + i.e. MSI-X with the same maximum number of vectors on platforms + supporting this mechanism, otherwise INTx with one vector. + + +Guest-side Programming Model +---------------------------- + +An IVSHMEM device appears as a PCI device to its users. Unless +otherwise noted, it conforms to the PCI Local Bus Specification, +Revision 3.0. As such, it is discoverable via the PCI configuration +space and provides a number of standard and custom PCI configuration +registers. + +### Shared Memory Region Layout + +The shared memory region is divided into several sections. + + +-----------------------------+ - + | | : + | Output Section for peer n-1 | : Output Section Size + | (n = Maximum Peers) | : + +-----------------------------+ - + : : + : : + : : + +-----------------------------+ - + | | : + | Output Section for peer 1 | : Output Section Size + | | : + +-----------------------------+ - + | | : + | Output Section for peer 0 | : Output Section Size + | | : + +-----------------------------+ - + | | : + | Read/Write Section | : R/W Section Size + | | : + +-----------------------------+ - + | | : + | State Table | : State Table Size + | | : + +-----------------------------+ <-- Shared memory base address + +The first section consists of the mandatory State Table. Its size is +defined by the State Table Size register and cannot be zero. This +section is read-only for all peers. + +The second section consists of shared memory that is read/writable +for all peers. Its size is defined by the R/W Section Size register. +A size of zero is permitted. + +The third and following sections are output sections, one for each +peer. Their sizes are all identical. The size of a single output +section is defined by the Output Section Size register. An output +section is read/writable for the corresponding peer and read-only for +all other peers. E.g., only the peer with ID 3 can write to the +fourths output section, but all peers can read from this section. + +All sizes have to be rounded up to multiples of a mappable page in +order to allow access control according to the section restrictions. + +### Configuration Space Registers + +#### Header Registers + +| Offset | Register | Content | +|-------:|:-----------------------|:-----------------------------------------------------| +| 00h | Vendor ID | 110Ah | +| 02h | Device ID | 4106h | +| 04h | Command Register | 0000h on reset, writable bits are: | +| | | Bit 0: I/O Space (if Register Region uses I/O) | +| | | Bit 1: Memory Space (if Register Region uses Memory) | +| | | Bit 3: Bus Master | +| | | Bit 10: INTx interrupt disable | +| | | Writes to other bits are ignored | +| 06h | Status Register | 0010h, static value | +| | | In deviation to the PCI specification, the Interrupt | +| | | Status (bit 3) is never set | +| 08h | Revision ID | 00h | +| 09h | Class Code, Interface | Protocol Type bits 0-7, see [Protocols](#Protocols) | +| 0Ah | Class Code, Sub-Class | Protocol Type bits 8-15, see [Protocols](#Protocols) | +| 0Bh | Class Code, Base Class | FFh | +| 0Eh | Header Type | 00h | +| 10h | BAR 0 | MMIO or I/O register region | +| 14h | BAR 1 | MSI-X region | +| 18h | BAR 2 (with BAR 3) | optional: 64-bit shared memory region | +| 2Ch | Subsystem Vendor ID | same as Vendor ID, or provider-specific value | +| 2Eh | Subsystem ID | same as Device ID, or provider-specific value | +| 34h | Capability Pointer | First capability | +| 3Eh | Interrupt Pin | 01h-04h, must be 00h if MSI-X is available | + +The INTx status bit is never set by an implementation. Users of the +IVSHMEM device are instead expected to derive the event state from +protocol-specific information kept in the shared memory. This +approach is significantly faster, and the complexity of +register-based status tracking can be avoided. + +If BAR 2 is not present, the shared memory region is not relocatable +by the user. In that case, the hypervisor has to implement the Base +Address register in the vendor-specific capability. + +Subsystem IDs shall encode the provider (hypervisor) in order to +allow identifying potential deviating implementations in case this +should ever be required. + +If its platform supports MSI-X, an implementation of the IVSHMEM +device must provide this interrupt model and must not expose INTx +support. + +Other header registers may not be implemented. If not implemented, +they return 0 on read and ignore write accesses. + +#### Vendor Specific Capability (ID 09h) + +This capability must always be present. + +| Offset | Register | Content | +|-------:|:--------------------|:-----------------------------------------------| +| 00h | ID | 09h | +| 01h | Next Capability | Pointer to next capability or 00h | +| 02h | Length | 20h if Base Address is present, 18h otherwise | +| 03h | Privileged Control | Bit 0 (read/write): one-shot interrupt mode | +| | | Bits 1-7: Reserved (0 on read, writes ignored) | +| 04h | State Table Size | 32-bit size of read-only State Table | +| 08h | R/W Section Size | 64-bit size of common read/write section | +| 10h | Output Section Size | 64-bit size of output sections | +| 18h | Base Address | optional: 64-bit base address of shared memory | + +All registers are read-only. Writes are ignored, except to bit 0 of +the Privileged Control register. + +When bit 0 in the Privileged Control register is set to 1, the device +clears bit 0 in the Interrupt Control register on each interrupt +delivery. This enables automatic interrupt throttling when +re-enabling shall be performed by a scheduled unprivileged instance +on the user side. + +An IVSHMEM device may not support a relocatable shared memory region. +This support the hypervisor in locking down the guest-to-host address +mapping and simplifies the runtime logic. In such a case, BAR 2 must +not be implemented by the hypervisor. Instead, the Base Address +register has to be implemented to report the location of the shared +memory region in the user's address space. + +A non-existing shared memory section has to report zero in its +Section Size register. + +#### MSI-X Capability (ID 11h) + +On platforms supporting MSI-X, IVSHMEM has to provide interrupt +delivery via this mechanism. In that case, the MSI-X capability is +present while the legacy INTx delivery mechanism is not available, +and the Interrupt Pin configuration register returns 0. + +The IVSHMEM device has no notion of pending interrupts. Therefore, +reading from the MSI-X Pending Bit Array will always return 0. Users +of the IVSHMEM device are instead expected to derive the event state +from protocol-specific information kept in the shared memory. This +approach is significantly faster, and the complexity of +register-based status tracking can be avoided. + +The corresponding MSI-X MMIO region is configured via BAR 1. + +The MSI-X table size reported by the MSI-X capability structure is +identical for all peers. + +### Register Region + +The register region may be implemented as MMIO or I/O. + +When implementing it as MMIO, the hypervisor has to ensure that the +register region can be mapped as a single page into the address space +of the user, without causing potential overlaps with other resources. +Write accesses to MMIO region offsets that are not backed by +registers have to be ignored, read accesses have to return 0. This +enables the user to hand out the complete region, along with the +shared memory, to an unprivileged instance. + +The region location in the user's physical address space is +configured via BAR 0. The following table visualizes the region +layout: + +| Offset | Register | +|-------:|:--------------------------------------------------------------------| +| 00h | ID | +| 04h | Maximum Peers | +| 08h | Interrupt Control | +| 0Ch | Doorbell | +| 10h | State | + +All registers support only aligned 32-bit accesses. + +#### ID Register (Offset 00h) + +Read-only register that reports the ID of the local device. It is +unique for all of the connected devices and remains unchanged over +their lifetime. + +#### Maximum Peers Register (Offset 04h) + +Read-only register that reports the maximum number of possible peers +(including the local one). The permitted range is between 2 and 65536 +and remains constant over the lifetime of all peers. + +#### Interrupt Control Register (Offset 08h) + +This read/write register controls the generation of interrupts +whenever a peer writes to the Doorbell register or changes its state. + +| Bits | Content | +|-----:|:----------------------------------------------------------------------| +| 0 | 1: Enable interrupt generation | +| 1-31 | Reserved (0 on read, writes ignored) | + +Note that bit 0 is reset to 0 on interrupt delivery if one-shot +interrupt mode is enabled in the Enhanced Features register. + +The value of this register after device reset is 0. + +#### Doorbell Register (Offset 0Ch) + +Write-only register that triggers an interrupt vector in the target +device if it is enabled there. + +| Bits | Content | +|------:|:---------------------------------------------------------------------| +| 0-15 | Vector number | +| 16-31 | Target ID | + +Writing a vector number that is not enabled by the target has no +effect. The peers can derive the number of available vectors from +their own device capabilities because the provider is required to +expose an identical number of vectors to all connected peers. The +peers are expected to define or negotiate the used ones via the +selected protocol. + +Addressing a non-existing or inactive target has no effect. Peers can +identify active targets via the State Table. + +Implementations of the Doorbell register must ensure that data written by the +CPU prior to issuing the register write is visible to the receiving peer before +the interrupt arrives. + +The behavior on reading from this register is undefined. + +#### State Register (Offset 10h) + +Read/write register that defines the state of the local device. +Writing to this register sets the state and triggers MSI-X vector 0 +or the INTx interrupt, respectively, on the remote device if the +written state value differs from the previous one. Users of peer +devices can read the value written to this register from the State +Table. They are expected differentiate state change interrupts from +doorbell events by comparing the new state value with a locally +stored copy. + +The value of this register after device reset is 0. The semantic of +all other values can be defined freely by the chosen protocol. + +### State Table + +The State Table is a read-only section at the beginning of the shared +memory region. It contains a 32-bit state value for each of the +peers. Locating the table in shared memory allows fast checking of +remote states without register accesses. + +The table is updated on each state change of a peers. Whenever a user +of an IVSHMEM device writes a value to the Local State register, this +value is copied into the corresponding entry of the State Table. When +a IVSHMEM device is reset or disconnected from the other peers, zero +is written into the corresponding table entry. The initial content of +the table is all zeros. + + +--------------------------------+ + | 32-bit state value of peer n-1 | + +--------------------------------+ + : : + +--------------------------------+ + | 32-bit state value of peer 1 | + +--------------------------------+ + | 32-bit state value of peer 0 | + +--------------------------------+ <-- Shared memory base address + + +Protocols +--------- + +The IVSHMEM device shall support the peers of a connection in +agreeing on the protocol used over the shared memory devices. For +that purpose, the interface byte (offset 09h) and the sub-class byte +(offset 0Ah) of the Class Code register encodes a 16-bit protocol +type for the users. The following type values are defined: + +| Protocol Type | Description | +|--------------:|:-------------------------------------------------------------| +| 0000h | Undefined type | +| 0001h | Virtual peer-to-peer Ethernet | +| 0002h-3FFFh | Reserved | +| 4000h-7FFFh | User-defined protocols | +| 8000h-BFFFh | Virtio over Shared Memory, front-end peer | +| C000h-FFFFh | Virtio over Shared Memory, back-end peer | + +Details of the protocols are not in the scope of this specification. diff --git a/Documentation/memory-layout.txt b/Documentation/memory-layout.txt new file mode 100644 index 0000000000000000000000000000000000000000..82029f17ed6e20ae3ab18af9bd7fdbcdf71494d2 --- /dev/null +++ b/Documentation/memory-layout.txt @@ -0,0 +1,162 @@ +Memory Layout of the Jailhouse Hypervisor +========================================= + +The hypervisor memory space consists of three types of memory regions: commonly +visible hypervisor memory, globally visible I/O memory remappings and CPU- +specific remappings of hypervisor memory as well as cell memory pages. + +Cells are not mapped as a whole into the hypervisor address space. Only +explicitely shared pages and pages that are temporarily mapped, e.g. during +MMIO instruction parsing, are visible by the hypervisor during runtime. +Furthermore, the visibility is limited to the CPU that create it because they +are only added to the CPU-specifc mapping. + + +Common memory region +-------------------- + +This region contains both code and data of the hypervisor. It consists of +contiguous physical RAM, mapped at a fixed virtual address into the hypervisor +address space. + +Prior to enabling the hypervisor and after disabling it, this region is also +mapped into the address space of Linux that acts as root cell. The virtual +address of this mapping is identical to the one used by the hypervisor when the +architecture set JAILHOUSE_BORROW_ROOT_PT (currently x86 and ARM), on other, +this addressed can differ. + +The commom memory region contains an array of per-CPU data structures, one for +each configured CPU. Each per-CPU data structure consists of a private part and +a public part. The public part will remain visible for all CPUs throughout the +hypervisor operation. The private part, however, is only visible during setup +and prior to shutdown. When the hypervisor is in operational mode, the private +sections of all CPUs are hidden. Rather, CPUs are supposed to access this data +via their CPU-specific mapping. + +Virtual address: JAILHOUSE_BASE +Size: as defined in the system configuration (see hypervisor_memory.size) [1] + + +--------------------------------------+ - lower address + | Header [2] | + +--------------------------------------+ + | Text Segment | + | | + | | + +--------------------------------------+ + | Read-only Data Segment | + | | + +--------------------------------------+ + | Data Segment | + | | + +--------------------------------------+ + | Init Array | + | | + +--------------------------------------+ + | Bootstrap Page Tables (only ARM64) | + | | + +--------------------------------------+ + | Trampoline Code (only ARM and ARM64) | + | | + +--------------------------------------+ + | Console Page | + | | + +--------------------------------------+ + | BSS Segment | + | | + +--------------------------------------+ + | Page +-----------------------------+ | + | Pool | Private Data CPU 0 | | + | | (unmapped during operation) | | + | +-----------------------------+ | + | | Public Data CPU 0 | | + | +-----------------------------+ | + | | Private Data CPU 1 | | + | | (unmapped during operation) | | + | +-----------------------------+ | + | | Public Data CPU 1 | | + | +-----------------------------+ | + : : : : + : : : : + | +-----------------------------+ | + | | Private Data CPU n-1 | | + | | (unmapped during operation) | | + | +-----------------------------+ | + | | Public Data CPU n-1 | | + | +-----------------------------+ | + | | System Config | | + | | | | + | +-----------------------------+ | + | | Page Pool Allocation Bitmap | | + | +-----------------------------+ | + | | Dynamic Page Pool | | + : : : : + : : : : + | | | | + | +-----------------------------+ | + +--------------------------------------+ - higher address + + +I/O memory remapping region +--------------------------- + +This region is a range of reserved virtual memory in the hypervisor address +space. It is used to map MMIO pages for hypervisor access. + +Virtual address: REMAP_BASE +Size: PAGE_SIZE * NUM_REMAP_BITMAP_PAGES * PAGE_SIZE * 8 + + +--------------------------------------+ - lower address + | Dynamic Remapping Page pool | + : : + : : + | | + +--------------------------------------+ - higher address + + +CPU-specific remapping region +----------------------------- + +This region is differently mapped for each CPU. It consistes of a virtual +address range that is used for temporarily mapping individual pages of the cell +that runs on the same CPU. + +Futhermore, the private per-CPU data which is hidden from the common memory +region is made available at fixed virtual address here. This allows to +dereference CPU local data quickly and generically. Moreover, it hides cell- +private data that the hypervisor may collect on VM exit, e.g. register content, +from other CPUs. + +Consequently, malicious cells are unable to trick the hypervisor to leak cell +data and other sensitive state information from cells that are always running +on different CPUs. Specifically, all known Spectre-class attacks are unable to +reveal relevant data, provided cells are partitioned along physical cores +(hyperthread siblings belong to the same cell). + +Virtual address: TEMPORARY_MAPPING_BASE +Size: NUM_TEMPORARY_PAGES * PAGE_SIZE + + PAGE_ALIGN(sizeof(struct public_per_cpu)) + + +--------------------------------------+ - lower address + | Temporary cell page remapping range | + | | + +--------------------------------------+ + | Private per-CPU data | + | (at LOCAL_CPU_BASE) | + +--------------------------------------+ - higher address + + +Debug console MMIO region (JAILHOUSE_BORROW_ROOT_PT only) +--------------------------------------------------------- + +This mapping of the debug console device MMIO region is set up by the driver +prior to handing the control over to Jailhouse. The address is defined during +runtime by Linux and generally does not conflict with the other, statically +allocated regions. The hypervisor performs basic consistency checks on it. Its +size is defined by the system configuration (system_config->debug_console.size). + + +References +---------- + +[1] Documentation/configuration-format.md +[2] Documentation/bootstrap-interface.txt diff --git a/Documentation/non-root-linux.txt b/Documentation/non-root-linux.txt new file mode 100644 index 0000000000000000000000000000000000000000..61623f9cfbf6d3bd29750a1e145c85065af370e1 --- /dev/null +++ b/Documentation/non-root-linux.txt @@ -0,0 +1,80 @@ +Booting Linux in non-root cells +=============================== + +Jailhouse exposes only a minimal environment to inmates of non-root cells. +Specifically on x86, the available resources are insufficient to boot standard +operating systems without modifications. This document describes the necessary +steps to configure Linux for booting in a non-root cell. + + +Kernel patches +-------------- + +We currently maintain a queue of patches to enable booting of Linux in an x86 +non-root cell: + + git://git.kiszka.org/linux.git queues/jailhouse + +Note that this branch may be rebased from time to time to move it to a more +recent kernel version or to cleanup and adjust the patches. The plan is to +push those patches upstream once their usefulness and correctness have been +confirmed. + +Booting a Linux kernel on an ARM/ARM64 target is significantly simpler than on +x86, so in this case we do not need a specially modified Linux kernel for the +non-root cell. + + +x86 Kernel configuration +------------------------ + +After checking out the above kernel branch, create a configuration that +contains at least the following adjustments: + +- enable CONFIG_JAILHOUSE_GUEST +- disable CONFIG_SERIO +- disable CONFIG_PM_TRACE_RTC + +Note that only 64-bit kernels are supported. + +The proper UART configuration depends on the desired console setup. There is +currently no console available via the inter-cell communication channel, thus +it may be useful for testing purposes to configure the first physical UART for +the non-root cell. CONFIG_SERIAL_8250_RUNTIME_UARTS should therefore be set to +1, and the root cell should avoid using the first UART for its own purposes +(the linux-x86-demo will revoke the access for the root cell). As the non-root +Linux cells have no IOAPIC support, there is also no IRQ support for the UART. +The patch queue currently contains a hack to disable the interrupt for that +UART and switch Linux to timer-based polling mode. If you don't use a UART, +CONFIG_SERIAL_8250_RUNTIME_UARTS should be set to 0. + +In general, the non-root Linux kernel configuration should be tuned to disable +all unneeded drivers and features so that no undesired probing will take place +and the image size as well as the memory footprint is minimized. + + +Non-root Linux start +-------------------- + +The easiest way to start a non-root Linux inmate is via the jailhouse tool: + + jailhouse cell linux CELLCONFIG KERNEL [-d | --dtb DTB] [-i | --initrd FILE] + [-c | --cmdline "STRING"] [-w | --write-params FILE] + +A device tree (DTB) is only required on ARM and ARM64 systems. You can find +templates for the supported targets under +configs/{arm, arm64}/dts/inmate-.dts. Those device tree source files +are compiled to their binary representations (*.dtb) during the build. + +To create, load and start a Linux cell and use the first UART as console, issue + + jailhouse cell linux /path/to/linux.cell /path/to/bzImage \ + -i /path/to/initrd -c "console=ttyS0,115200" + +Alternatively, you can prepare the required configuration image in advance via + + jailhouse cell linux /path/to/linux.cell /path/to/bzImage \ + -i /path/to/initrd -c "console=ttyS0,115200" -w /path/to/linux-params + +and then issue the basic tool commands on the target as printed by the command +above. diff --git a/Documentation/pyjailhouse.md b/Documentation/pyjailhouse.md new file mode 100644 index 0000000000000000000000000000000000000000..7864694d74033e64f0d4b10364c18fd624e53daf --- /dev/null +++ b/Documentation/pyjailhouse.md @@ -0,0 +1,59 @@ +# pyjailhouse + +## Using source-tree version of pyjailhouse + +Python scripts in the **source tree** (i.e. as opposed to python scripts in an +installation directory) that import pyjailhouse automatically import +pyjailhouse from the jailhouse root directory. This is achieved by setting +`sys.path [0]` to be the absolute path of the root directory, just before +we import pyjailhouse (or something from it): + +`sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "[rel. path]"` +`from pyjailhouse.cell import JailhouseCell` + +Where, `[rel.path]` is the relative path from the directory containing the +running script to the root directory. When we install any python script that +uses pyjailhouse, we remove `sys.path[0] = os.path.dirname(...` from the +installed scripts, leaving python to import pyjailhouse from where pip +installed it. + +As a usage example, consider the following directory structure for jailhouse: + +`|jailhouse/` +`|_____> foo/` +`|___________> bar/` +`|_______________> __init__.py` +`|_______________> baz.py` +`|___________> boz.py` +`|_____> moo.py` +`|_____> pyjailhouse/` + +baz.py would have: +`sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/../.."` +`import pyjailhouse` + +boz.py would have: +`sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.."` +`import pyjailhouse.something` + +moo.py would have: +`sys.path[0] = os.path.dirname(os.path.abspath(__file__))` +`from pyjailhouse import other` + +Note that any attempt to import a module after writing to sys.path[0], such +that the module is located in the directory containing the script that +initially invoked the python interpreter (with a shebang), will fail. Read +about sys.path[0] in any python language reference to understand why this is so. +For the example, the following wouldn't work inside of boz.py: + +`sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.."` +`import pyjailhouse.something` +`import bar # Will fail` + +**Boilerplate code, with sys.path[0] warning** + +` +# Imports from directory containing this must be done before the following +sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "" +from pyjailhouse import * +` diff --git a/Documentation/setup-on-banana-pi-arm-board.md b/Documentation/setup-on-banana-pi-arm-board.md new file mode 100644 index 0000000000000000000000000000000000000000..32f6c9497814e676bb5236b5d6751678552f0bc0 --- /dev/null +++ b/Documentation/setup-on-banana-pi-arm-board.md @@ -0,0 +1,306 @@ +Setup on Banana Pi ARM board +============================ + +The Banana Pi is a cheap Raspberry-Pi-like ARM board with an Allwinner A20 SoC +(dual-core Cortex-A7). It runs mainline Linux kernels and U-Boot and is +comparably well hackable. Further information can be found on +http://linux-sunxi.org. + +In order to run Jailhouse, the Linux kernel version should be at least 3.19. The +configuration used for continuous integration builds can serve as reference, see +`ci/kernel-config-banana-pi`. The kernel requires a small patch in order to +build the Jailhouse driver module: + +```diff +diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c +index 7e45f69..dc0336e 100644 +--- a/arch/arm/kernel/armksyms.c ++++ b/arch/arm/kernel/armksyms.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + /* + * libgcc functions - functions that are used internally by the +@@ -181,3 +182,7 @@ EXPORT_SYMBOL(__pv_offset); + EXPORT_SYMBOL(arm_smccc_smc); + EXPORT_SYMBOL(arm_smccc_hvc); + #endif ++ ++#ifdef CONFIG_ARM_VIRT_EXT ++EXPORT_SYMBOL_GPL(__boot_cpu_mode); ++#endif +``` + +Meanwhile, an U-Boot release more recent than v2015.04 is required. Tested and +known to work is release v2016.03. Note that, **since v2015.10, you need to +disable CONFIG_VIDEO in the U-Boot config**, or U-Boot will configure the +framebuffer at the end of the physical RAM where Jailhouse is located. + +Below is a tutorial about setting up Jailhouse on a **BananaPi M1** board, and +running [FreeRTOS-cell](https://github.com/siemens/freertos-cell) on the top of +it. The tutorial is based on: + - Ubuntu-14.04 on a x86-64 machine + - BananaPi M1 board, running bananian-16.04 + + +Installation +------------ +Follow the instructions on [BananaPi official site](https://www.bananian.org/download) +to build your sd-card. + +Basically here are the steps, +```bash +#On Ubuntu-14.04 (or any other machine), +#HERE WE USE **BANANIAN** AS OUR BANANAPI'S OS +$ wget https://dl.bananian.org/releases/bananian-latest.zip +$ sudo apt-get update && sudo apt-get install unzip screen +$ unzip ./bananian-latest.zip +$ lsblk | grep mmcblk + +# Write the image to sdcard, replace `mmcblk0` below with the device name +# returned from `lsblk` +$ sudo dd bs=1M if=~/bananian-*.img of=/dev/mmcblk0 + +#Insert the sd-card to BananaPi, connect it to our machine using ttl cable. +#On Ubuntu, +$ screen /dev/ttyUSB0 115200 + +#On BananaPi, login with root/pi, then expand the filesystem +$ bananian-config + +#Choose `y` for `Do you want to expand the root file system`. +#Feel free to configure other stuff as well. +``` + + +Adjusting U-boot for kernel booting arguments. +--------------------------------------------- +Jailhouse needs to boot with certain Kernel arguments to reserve memory for +other cells (using `mem=...`). We must adjust U-boot config file to boot with +these arguments. The u-boot partition is not mounted by default. Thus, we need +to mount it first. On bananian, +```bash +$ mkdir /p1 +$ mount /dev/mmcblk0p1 /p1 +$ vi /p1/boot.cmd +``` +Append `mem=932M vmalloc=512M` on the end of line that starts with +`setenv bootargs`. After editing, the file should look like: +```bash +#------------------------------------------------------------------------------- +# Boot loader script to boot with different boot methods for old and new kernel +# Credits: https://github.com/igorpecovnik - Thank you for this great script! +#------------------------------------------------------------------------------- +if load mmc 0:1 0x00000000 uImage-next +then +# mainline kernel >= 4.x +#------------------------------------------------------------------------------- +setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait mem=932M vmalloc=512M +load mmc 0:1 0x49000000 dtb/${fdtfile} +load mmc 0:1 0x46000000 uImage-next +bootm 0x46000000 - 0x49000000 +#------------------------------------------------------------------------------- +else +# sunxi 3.4.x +#------------------------------------------------------------------------------- +setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 sunxi_g2d_mem_reserve=0 sunxi_ve_mem_reserve=0 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1680x1050p60 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait +setenv bootm_boot_mode sec +load mmc 0:1 0x43000000 script.bin +load mmc 0:1 0x48000000 uImage +bootm 0x48000000 +#------------------------------------------------------------------------------- +fi +``` +After saving the file, create u-boot recognizable image `*.src` from `*.cmd` +using mkimage +```bash +$ apt-get update && apt-get install -y u-boot-tools +$ cd /p1 +$ mkimage -C none -A arm -T script -d boot.cmd boot.scr +``` +See more on [disccusion](https://groups.google.com/forum/#!topic/jailhouse-dev/LzyOqEHvEk0) +about why it's `mem=932M` instead of `mem=958M`. + + +Cross Compiling Kernel for ARM on x86 +------------------------------------- +Jailhouse need to be compiled with kernel objects. Thus we first need a copy of +kernel source code and compile it. + +Jailhouse requires Kernel Version >= 3.19. Here, we'll use Kernel version 4.3.3 +with patch provided by Bananian team. + +We'll cross compile on a x86 machine for faster compilation. On the compiling +machine, +* Obtaining Kernel source code & patches for bananapi, and jailhouse +```bash +$ sudo apt-get update && sudo apt-get install -y git +$ cd ~ +$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git +$ git clone https://github.com/Bananian/bananian.git +$ git clone https://github.com/siemens/jailhouse.git +``` + +* Obtaining cross compiling tool-chain from [Linaro Official site](http://www.linaro.org/downloads/) +```bash +#Download the recommended cross-toolchain from Linaro + +$ cd ~ +$ wget https://releases.linaro.org/components/toolchain/binaries/latest-5/arm-linux-gnueabihf/gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf.tar.xz +$ tar -xf gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf.tar.xz + +#Update environment path +$ export PATH=$PATH:$(pwd)/gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf/bin +``` + +* Apply patches and Setup config +```bash +$ cd ~/linux-stable +$ git checkout v4.3.3 +$ for i in ../bananian/kernel/4.3.3/patches/*; do patch -p1 < $i; done + +#Copy config from jailhouse/ci directory +$ cp -av ../jailhouse/ci/kernel-config-banana-pi .config + +$ sudo apt-get update && sudo apt-get install -y build-essential libncurses5 libncurses5-dev +$ make ARCH=arm menuconfig +#Enable FUSE under "File systems", needed for file transfer via sshfs +``` + +* Compile Kernel +```bash +$ sudo apt-get update && sudo apt-get install -y u-boot-tools +$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8 uImage modules dtbs LOADADDR=40008000 +``` + + +Installing Kernel +----------------- +Here we choose to mount compiled kernel-source directory on BananaPi. Instead +one can choose to transfer the directory that contains kernel source to +BananaPi. +```bash +#On Compiling machine, +$ sudo apt-get update && sudo apt-get install -y sshfs + +#On BananaPi, +$ apt-get update && apt-get install -y sshfs make gcc +$ mkdir ~/linux-src +$ sshfs @: ~/linux-src +$ cd ~/linux-src +$ make modules_install + +#Update U-boot partition +$ mount /dev/mmcblk0p1 /boot +$ mkdir /boot/dtb/ +$ cp -v arch/arm/boot/uImage /boot/uImage-next +$ cp -v arch/arm/boot/dts/*.dtb /boot/dtb/ + +#now reboot +$ reboot +``` + +Verify installation using `$ uname -r`, if the kernel is installed successfully, +the bash command above should return `4.3.3-dirty`. + + +Cross Compiling Jailhouse(w/ FreeRTOS-cell) for ARM on x86 +----------------------------------------------------- +* Check the need of upgrading `make`. +Jailhouse require make>=3.82 to build it, we might need to upgrade `make`. +```bash +#On Compiling machine, +$ make --version + +#If make>=3.82, skip this part and continue with "Building Jailhouse" +$ sudo apt-get update && sudo apt-get install -y checkinstall +$ wget http://ftp.gnu.org/gnu/make/make-3.82.tar.bz2 -O ~/Downloads/make-3.82.tar.bz2 +$ cd ~ && tar -xf ~/Downloads/make-3.82.tar.bz2 +$ cd make-3.82 +$ ./configure --prefix=/usr +$ make +$ sudo checkinstall make install +``` + +* Building Jailhouse (mainly for FreeRTOR as a cell) +```bash +#On Compiling Machine, +$ sudo apt-get update && sudo apt-get install -y python3-mako device-tree-compiler +$ cd ~ +$ git clone https://github.com/siemens/freertos-cell +$ cp -av ~/freertos-cell/jailhouse-configs/bananapi.c ~/jailhouse/configs/arm/bananapi.c +$ cp -av freertos-cell/jailhouse-configs/bananapi-freertos-demo.c ~/jailhouse/configs/arm/ + +#Copy the configuration header file before building +$ cp -av ~/jailhouse/ci/jailhouse-config-banana-pi.h ~/jailhouse/include/jailhouse/config.h +$ cd ~/jailhouse +$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KDIR=../linux-stable +``` + +* Build FreeRTOS-cell +```bash +$ cd ~/freertos-cell +$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KDIR=../linux-stable +``` + + +Installing Jailhouse +-------------------- +Here we mount `/` of BananaPi on `~/bpi_root` on our compiling Machine, +```bash +#On Compiling Machine, +$ mkdir ~/bpi_root +$ sshfs root@:/ ~/bpi_root +$ cd ~/jailhouse +$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \ + KDIR=../linux-stable DESTDIR=~/bpi_root install +``` + + +Testing Jailhouse On BananaPi +----------------------------- +To test jailhouse on BananaPi, we would need the `*.cell` file where could be +located in the cross-compiled `jailhouse` & `freertos-cell` directory. + +Here we transfer these two directory from the compiling machine to BananaPi +using sftp. +```bash +#On Compiling Machine, +$ cd ~ && tar -zcf jailhouse-compiled.tar.gz jailhouse freertos-cell +$ sftp root@ +sftp > put jailhouse-compiled.tar.gz +sftp > quit + +#On BananaPi, +$ cd ~ && tar -xf jailhouse-compiled.tar.gz +$ modprobe jailhouse + +#If nothing goes wrong, you should see jailhouse using a `$ lsmod` +$ jailhouse enable ~/jailhouse/configs/arm/bananapi.cell +$ jailhouse cell create ~/jailhouse/configs/arm/bannapi-freertos-demo.cell +$ jailhouse cell load FreeRTOS ~/freertos-cell/freertos-demo.bin +$ jailhouse cell start FreeRTOS + +#Jailhouse and FreeRTOS cell has been started, you should able to get some +#output from the FreeRTOS demo application on the second serial interface of +#BananaPi. + +#After making sure all things works well, turn off jailhouse using command below +$ jailhouse cell shutdown FreeRTOS +$ jailhouse cell destroy FreeRTOS +$ jailhouse disable +$ rmmod jailhouse +``` + + +References +---------- +1. https://github.com/cyng93/jailhouse/blob/master/README.md +2. https://github.com/siemens/freertos-cell/blob/master/README.md +3. https://groups.google.com/forum/#!topic/jailhouse-dev/LzyOqEHvEk0 +4. https://fossapc.hackpad.com/Jailhouse-on-Banana-Pi-with-FreeRTOS-as-Cell-EZaCw8OEynM +5. https://embedded2015.hackpad.com/ep/pad/static/P8aM30iQ3hm +6. https://paper.dropbox.com/doc/Banana-Pi-and-jailhouse-6CoZ4Cgyom22Gy3uH9g7e diff --git a/Documentation/setup-on-emtrion-emcon-rz-boards.md b/Documentation/setup-on-emtrion-emcon-rz-boards.md new file mode 100644 index 0000000000000000000000000000000000000000..c80735028436fbfc1de8d38912a15fd46f91ddea --- /dev/null +++ b/Documentation/setup-on-emtrion-emcon-rz-boards.md @@ -0,0 +1,102 @@ +Setup on emtrion's emCON-RZ/G1x series board +============================================ + +The emCON-RZ/G1x boards from emtrion are boards with SoCs from the Renesas RZ/G series: + +- emCON-RZ/G1E has a RZ/G1E processor (dual-core Cortex-A7) +- emCON-RZ/G1M has a RZ/G1M processor (dual-core Cortex-A15) +- emCON-RZ/G1H has a RZ/G1H processor (quad-core Cortex-A15/Cortex-A7) + +These boards run mainline Linux kernels and U-Boot with patches from Renesas and emtrion. +Further information can be found on https://www.emtrion.de and https://support.emtrion.de. + +In order to run Jailhouse, the Linux kernel version should be at least 4.4.49 and U-Boot +should be at least 2016.07. + +Adjusting kernel boot parameters via U-Boot +------------------------------------------- +Jailhouse needs the Linux kernel boot parameters mem= and vmalloc= to be set in order to reserve memory for other cells. +In our case we chose mem=750M and vmalloc=384M. + +To set these values, you have to change the Linux kernel boot parameters via U-Boot accordingly. + +Install and start Jailhouse on emCON-RZ/G1x +------------------------------------------- +First we need access to the RootFS of the Linux running on the emCON-RZ/G1x. We assume that you +have mounted this on your development workstation through sshfs or nfs. + +Now in your Jailhouse source directory, create a file include/jailhouse/config.h. + +If you own an emCON-RZ/G1E or emCON-RZ/G1M put the following line to this file: + +#define CONFIG_MACH_EMCON_RZG 1 + +If you own an emCON-RZ/G1H put the following line to this file: + +#define CONFIG_MACH_EMCON_RZG1H 1 + +Then you can compile and install Jailhouse using this command on the development workstation: + +make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNELRELEASE=-emconrzg1x KDIR= DESTDIR= install + +**In the following replace the x with the last letter of the specific board name.** + +Jailhouse is now installed on the emCON-RZ/G1x board. But we also need the configuration +of the root cell. We have to copy this configuration manually using these commands on the +command line on the development workstation: + +mkdir -p /jailhouse/configs +cp configs/arm/emtrion-rzg1**x**.cell /jailhouse/configs + +Now we can unmount the RootFS of the emCON-RZ/G1x board because the other steps are executed +on the emCON-RZ/G1x board. On the console of the started Linux on emCON-RZ/G1x execute the +following commands to enable Jailhouse: + +modprobe jailhouse +jailhouse enable /jailhouse/configs/arm/emtrion-rzg1**x**.cell + +Running the Jailhouse UART demo as an inmate on emcon-RZ/G1x +------------------------------------------------------------ +The Jailhouse project contains a bare-metal inmate sample called uart-demo. This demo outputs +a string on the serial device in a loop. + +First you have to copy the following files from the Jailhouse development tree into the RootFS +of the root cell: + +cp configs/arm/emtrion-rzg1**x**-uart-demo.cell /jailhouse/configs +mkdir -p /jailhouse/inmates/uart-demo +cp inmates/demos/arm/uart-demo.bin /jailhouse/inmates + +We assume that the config file is available in the path /jailhouse/configs and the binary file +is available in the path /jailhouse/inmates/uart-demo. Then you can start the sample using +the following commands: + +jailhouse cell create /jailhouse/configs/emtrion-rzg1**x**-uart-demo.cell +jailhouse cell load emtrion-emconrzg1**x**-uart-demo /jailhouse/inmates/uart-demo/uart-demo.bin +jailhouse cell start emtrion-emconrzg1**x**-uart-demo + +The uart-demo will be started as an inmate and outputs strings through the serial port SCIF4. + +Running Linux as an inmate on emCON-RZ/G1x +------------------------------------------ +The sample Linux inmate is setup to use the following devices: + +- SCIF4 as serial console +- SDC0 where the RootFS should be stored +- I2C2 + +To setup the Linux inmate you have to first copy the following files from the Jailhouse tree into the RootFS +of the root cell: + +cp configs/arm/emtrion-rzg1**x**-linux-demo.cell /jailhouse/configs +cp configs/arm/dts/inmate-emtrion-emconrzg1**x**.dtb /jailhouse/configs + +We assume that these files are available in the path /jailhouse/configs on the RootFS of the +root cell. Make sure you have installed Python on the emCON-RZ/G1x board. + +Then we can start the linux inmate executing the following command line in the root cell: + +jailhouse cell linux /jailhouse/configs/emtrion-rzg1**x**-linux-demo.cell /boot/zImage -d /jailhouse/configs/inmate-emtrion-emconrzg1**x**.dtb -c "console=ttySC4,115200 cma=16M vmalloc=80M rootwait root=/dev/mmcblk0p2 vt.global_cursor_default=0 consoleblank=0" + +The Linux kernel in the inmate will be started. This Linux kernel uses the devices mentioned above and +searches on the second partition of the SD card for its RootFS. diff --git a/Documentation/setup-on-zynqmp-zcu102.md b/Documentation/setup-on-zynqmp-zcu102.md new file mode 100644 index 0000000000000000000000000000000000000000..613d7bcdacf8441a7668c5415e220f83ceef6bfe --- /dev/null +++ b/Documentation/setup-on-zynqmp-zcu102.md @@ -0,0 +1,203 @@ +Setup on ZCU102 ZynqMP Ultrascale+ +================================== +The ZCU102 target is a Xilinx target based on ZynqMP Ultrascale+. The SoC is a +quad-core Cortex-A53 and a dual-core R5 real-time processor. Further +information can be found on +https://www.xilinx.com/products/boards-and-kits/ek-u1-zcu102-g.html. + +The Linux Image which runs Jailhouse has been built with Petalinux 2017.4. +Petalinux uses linux-xlnx repository, and in this case it uses the +xilinx-v2017.4 one, which is based on 4.9 kernel. + + +Image build +----------- +In order to build the Linux image with Petalinux it is necessary to set all the +environmental variables. + + $ source /opt/pkg/settings.sh + +Once petalinux environments are set, the Petalinux project is created with the +name lnx_jailhouse. The bsp has to be downloaded. + + $ petalinux-create -t project --template zynqMP -s ../xilinx-zcu102-v2017.4-final.bsp -n lnx_jailhouse + +The Linux project is configured by: + + $ petalinux-config + +A menuconfig window is opened and just enable `Root filesystem type (SD card)`: + + Image Packaging Configuration--->Root filesystem type-->SD card + +Save project and exit. It will take some to time to configure the project. Once +it has finished configuring, the Linux kenel needs to be configured enabling +`CONFIG_OF_OVERLAY` and `CONFIG_KALLSYMS_ALL` + + $ petalinux-config -c kernel + +Once modified, save the changes and build the project. + + $ petalinux-build + $ petalinux-package --boot --u-boot + + +Jailhouse build +--------------- +In the Jailhouse source directory, create a file include/jailhouse/config.h +with the following lines: + +#define CONFIG_MACH_ZYNQMP_ZCU102 1 + +For debugging and for obtaining more information it is also possible to add: +#define CONFIG_TRACE_ERROR 1 + + +After that, it is possible to build the project. It is necessary to set the +variables `ARCH=` with arm64, `KDIR=` with the kernel directory inside the +Petalinux project, `CROSS_COMPILE=` with the compiler and `DESTDIR=` with the +rootfs directory. + + $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KDIR=../lnx_jailhouse/build/tmp/work/plnx_aarch64-xilinx-linux/linux-xlnx/4.9-xilinx-v2017.4+gitAUTOINC+b450e900fd-r0/linux-plnx_aarch64-standard-build/ DESTDIR=/media/user/rootfs install + +This command will add the jailhouse module and its binary. + + +U-Boot +------ +Jailhouse needs the Linux kernel boot parameters `mem=` to be set in order to +reserve memory for other cells. In this case we chose `mem=1536M`. This can be +done through U-Boot: + + ZynqMP> setenv bootargs "earlycon clk_ignore_unused earlyprintk mem=1536M root=/dev/mmcblk0p2 rw rootwait" + ZynqMP> setenv uenvcmd "fatload mmc 0 0x3000000 Image && fatload mmc 0 0x2A00000 system.dtb && booti 0x3000000 - 0x2A00000" + ZynqMP> setenv bootcmd "run uenvcmd" + ZynqMP> saveenv + ZynqMP> boot + + +Testing Jailhouse GIC Demo +-------------------------- +Copy the `configs/arm64/zynqmp-zcu102*.cell` to the rootfs. To test Jailhouse +it is also interesting to copy `inmates/demos/arm64/gic-demo.bin`. This demo +creates a periodic timer interrupt and calculates its jitter. Once Linux is +running: + + # modprobe jailhouse + [ 24.309597] jailhouse: loading out-of-tree module taints kernel. + + # jailhouse enable zynqmp-zcu102.cell + Initializing Jailhouse hypervisor v0.8 on CPU 2 + Code location: 0x0000ffffc0200060 + Page pool usage after early setup: mem 33/993, remap 64/131072 + Initializing processors: + CPU 2... OK + CPU 0... OK + CPU 3... OK + CPU 1... OK + Initializing unit: irqchip + Initializing unit: PCI + Adding virtual PCI device 00:00.0 to cell "ZynqMP-ZCU102" + Adding virtual PCI device 00:01.0 to cell "ZynqMP-ZCU102" + Page pool usage after late setup: mem 42/993, remap 69/131072 + Activating hypervisor + [ 39.844953] The Jailhouse is opening. + + # jailhouse cell create zynqmp-zcu102-inmate-demo.cell + [ 55.351670] CPU3: shutdown + [ 55.354303] psci: CPU3 killed. + Created cell "inmate-demo" + Page pool usage after cell creation: mem 56/993, remap 69/131072 + [ 55.388029] Created Jailhouse cell "inmate-demo" + + # jailhouse cell load 1 gic-demo.bin + Cell "inmate-demo" can be loaded + # jailhouse cell start 1 + +Second UART starts showing jitter data: + + Timer fired, jitter: 2212 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2171 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2454 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2444 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2181 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2181 ns, min: 2101 ns, max: 2585 ns + Timer fired, jitter: 2212 ns, min: 2101 ns, max: 2585 ns + +If second UART does not show anything, the problem can be between the DTB and +Jailhouse. Jailhouse is not still compatible with the last Xilinx DTBs. +Therefore, it is recommendable to use a 2016 repository DTB, such as, +https://github.com/Xilinx/linux-xlnx/blob/xilinx-v2016.4/arch/arm64/boot/dts/xilinx/zynqmp-zcu102.dts. + + +Testing Jailhouse Linux +----------------------- +It is possible to load a Linux image in a guest cell. In order to do that, it +is essential to do a new Linux image but with +`Image Packaging Configuration--->Root filesystem type-->INITRAMFS`. + +The files `image/linux/Image` and `image/linux/rootfs.cpio` have to be copied +from the Petalinux project to the rootfs. Besides, +`configs/arm64/dts/inmate-zynqmp.dtb` file has to be copied from Jailhouse +project. + +To load Linux in the guest cell: + + # modprobe jailhouse + [ 24.309597] jailhouse: loading out-of-tree module taints kernel. + + # jailhouse enable zynqmp-zcu102.cell + Initializing Jailhouse hypervisor v0.8 on CPU 2 + Code location: 0x0000ffffc0200060 + Page pool usage after early setup: mem 33/993, remap 64/131072 + Initializing processors: + CPU 2... OK + CPU 0... OK + CPU 3... OK + CPU 1... OK + Initializing unit: irqchip + Initializing unit: PCI + Adding virtual PCI device 00:00.0 to cell "ZynqMP-ZCU102" + Adding virtual PCI device 00:01.0 to cell "ZynqMP-ZCU102" + Page pool usage after late setup: mem 42/993, remap 69/131072 + Activating hypervisor + [ 39.844953] The Jailhouse is opening. + + # jailhouse cell linux zynqmp-zcu102-linux-demo.cell Image -d inmate-zynqmp.dtb -i rootfs.cpio -c "console=ttyPS0,115200" + [ 81.967652] CPU2: shutdown + [ 81.970285] psci: CPU2 killed. + [ 82.015619] CPU3: shutdown + [ 82.018242] psci: CPU3 killed. + Adding virtual PCI device 00:00.0 to cell "ZynqMP-linux-demo" + Shared memory connection established: "ZynqMP-linux-demo" <--> "ZynqMP-ZCU102" + Adding virtual PCI device 00:02.0 to cell "ZynqMP-linux-demo" + Created cell "ZynqMP-linux-demo" + Page pool usage after cell creation: mem 61/993, remap 69/131072 + [ 82.062667] Created Jailhouse cell "ZynqMP-linux-demo" + Cell "ZynqMP-linux-demo" can be loaded + Started cell "ZynqMP-linux-demo" + +Guest Linux booting will appear in the second UART. It possible to see the +state of each cell: + + root@xilinx-zcu102-2017_4:/# jailhouse cell list + ID Name State Assigned CPUs Failed CPUs + 0 ZynqMP-ZCU102 running 0-1 + 1 ZynqMP-linux-demo running 2-3 + + +Debug in ZCU102 +--------------- +The debug console is supposed to help with early cell boot issues and/or when a +UART is not available or not working. Add `JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED` +to the cell config (see e.g. configs/arm64/qemu-arm64-linux-demo.c). + +As an example, the gic-demo can be debugged. Just add the following info in the +cell load. It will print all the data through the principal UART instead of from +the second one. + + # jailhouse cell load 1 gic-demo.bin -s "con-type=JAILHOUSE" -a 0x1000 + +The output can be seen in: + + # jailhouse console -f diff --git a/Documentation/sysfs-entries.txt b/Documentation/sysfs-entries.txt new file mode 100644 index 0000000000000000000000000000000000000000..45db280af36651ea43da2f7694e1d68770f142f3 --- /dev/null +++ b/Documentation/sysfs-entries.txt @@ -0,0 +1,38 @@ +Sysfs Entries +============= + +The following sysfs entries are provided by the Jailhouse Linux driver. These +can be used for monitoring the state of the hypervisor and its cells. + +/sys/devices/jailhouse +|- console - hypervisor console (see [1]) +|- enabled - 1 if Jailhouse is enabled, 0 otherwise +|- mem_pool_size - number of pages in hypervisor memory pool +|- mem_pool_used - used pages of hypervisor memory pool +|- remap_pool_size - number of pages in hypervisor remapping pool +|- remap_pool_used - used pages of hypervisor remapping pool +`- cells + |- - unique numerical ID + | |- name - cell name + | |- state - "running", "running/locked", "shut down", or + | | "failed" + | |- cpus_assigned - bitmask of assigned logical CPUs + | |- cpus_assigned_list - human readable list of assigned logical CPUs + | |- cpus_failed - bitmask of logical CPUs that caused a failure + | |- cpus_failed_list - human readable list of logical CPUs that + | | caused a failure + | `- statistics + | |- cpu + | | |- vmexits_total - Total number of VM exits on CPU + | | `- vmexits_ - VM exits due to on CPU + | |- vmexits_total - Total number of VM exits on all cell CPUs + | `- vmexits_ - VM exits due to on all cell CPUs + `- ... + +Note that accumulated statistics over all CPUs of a cell are not collected +atomically and may not reflect a fully consistent state. The existence and +semantics of VM exit reason values are architecture-dependent and may change in +future versions. In general statistics shall only be considered as a first hint +when analyzing cell behavior. + +[1] Documentation/debug-output.md diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000000000000000000000000000000000000..1743bb1d684a393a00f827ed1bd73cf37f6e0024 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,94 @@ +FREQUENTLY ASKED QUESTIONS +========================== + +General +------- + +**Q: Linux already has KVM. Why do I need another hypervisor?** + +A: Short answer: in most cases, you don't. There are many hypervisors available +in Linux: KVM, Xen, Oracle VM VirtualBox, to name a few. Most of them are +full-featured versatile solutions you can use in almost any case, including +real-time virtualization. However, specialized solution can optimize its size +and complexity more aggressively, thus can do better when it comes to real-time +and validation of its correct isolation. + +Jailhouse is such a specialized hypervisor. It is all about static partitioning, +and it doesn't provide many features you'd expect from a virtual machine. There +is no overcommitting of resources, VM scheduling, or device emulation. + +Instead, Jailhouse focuses on two main things: being small and simple, and +allowing guests (called "inmates") to execute with nearly-zero latencies. It is +not to substitute KVM on your desktop or server, it is to run real-time code, +including bare-metal applications and RTOSes. Jailhouse also aims to provide a +platform for mixing critical applications in functional safety scenarios. +It can also fulfill secure isolation requirements, although this was not the +focus so far. + +**Q: Jailhouse is Asymmetric Multiprocessing (AMP). This means it will be slow due +to CPU cache thrashing.** + +A: These concerns do have grounds. However, what is "slow" is determined by +Service Level Agreement (SLA), and we hope the effect will be negligible in the +majority of cases. Jailhouse faces the same problem here as cloud services do, +and they are expected to be quite successful despite it. Future processors may +introduce QoS mechanisms for cache control, which will be helpful as well. One +example for such a feature is Intel's Cache Allocation Technology (CAT) which is +announced for new Xeon processors. Of course, running code under Jailhouse is +slightly slower than on a dedicated uniprocessor machine, but virtualization +always comes at price. + +**Q: Fault tolerance: how can I prevent a buggy/misbehaving inmate from hanging +the root cell by never replying to a request?** + +A: If the cell does not need or should not be able to vote over system +reconfigurations, you can simply set ```.flags = JAILHOUSE_CELL_PASSIVE_COMMREG``` +in the cell config. +Otherwise, use the ```msg_reply_timeout``` field in the cell config to specify +the number of idle loops the root cell must wait for a reply before considering +the cell as failing. + +**Q: Which open-source OSs can be currently run in non-root cells?** + +A: The following open-source OSs have been currently ported to Jailhouse: +* [Linux](Documentation/non-root-linux.txt) +* [FreeRTOS](https://github.com/siemens/freertos-cell) +* [ERIKA3 RTOS](http://www.erika-enterprise.com/wiki/index.php?title=ERIKA3_on_the_Jailhouse_hypervisor) +* [Zephyr](https://www.zephyrproject.org) + + +Debugging +--------- + +**Q: When I enable Jailhouse or run an inmate, my machine hangs. How do I know +what's going on? Can I use dmesg, ftrace or similar tool?** + +A: No. Jailhouse runs at the level lower than the Linux kernel, and if something +goes wrong, there are no guarantees that Linux can continue executing. Instead, +Jailhouse provides its own logging mechanism. In nested QEMU setup (see +README.md), log messages are simply sent to the virtual terminal; on real +hardware, you'll need a serial cable. Connect it to the COM port on your +motherboard. Many modern motherboards come with no COM ports, but they usually +have a header you can attach the socket to. Servers often have serial console +available through IPMI. + +If everything else fails, consider buying a PCI serial adapter. Now, attach +a Linux machine to the other side of serial connection and use terminal emulator +like minicom to grab the log messages. + +To enable error tracing, put ```#define CONFIG_TRACE_ERROR``` in file +include/jailhouse/config.h before compiling. + +Please note Jailhouse developers may ask you for these logs, shall you come for +help to jailhouse-dev mailing list, because they are extremely useful to analyze +machine hangs. So please have the logs at hand, if possible. + + +Development +----------- + +**Q: How do I create automatic documentation of Jailhouse ?** + +Run ```make docs``` to create automatic documentation (it needs Doxygen +installed). The documentation will be generated inside the +```Documentation/generated/``` directory. diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..2258a62c17ed16858f97cdf1f478fc05b2085324 --- /dev/null +++ b/Kbuild @@ -0,0 +1,83 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2017 +# +# Authors: +# Jan Kiszka +# Benjamin Block +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +ALWAYS_COMPAT_MK := $(src)/scripts/always-compat.mk +export ALWAYS_COMPAT_MK + +INC_CONFIG_H = $(src)/include/jailhouse/config.h +export INC_CONFIG_H + +define filechk_config_mk +( \ + echo "\$$(foreach config,\$$(filter CONFIG_%, \$$(.VARIABLES)), \ + \$$(eval undefine \$$(config)))"; \ + if [ -f $(INC_CONFIG_H) ]; then \ + sed -e "/^#define \([^[:space:]]*\)[[:space:]]*1/!d; \ + s/^#define \([^[:space:]]*\)[[:space:]]*1/\1=y/"\ + $(INC_CONFIG_H); \ + fi \ +) +endef + +GEN_CONFIG_MK := $(obj)/hypervisor/include/generated/config.mk +export GEN_CONFIG_MK + +$(GEN_CONFIG_MK): $(src)/Makefile FORCE + $(call filechk,config_mk) + +define filechk_version + $(src)/scripts/gen_version_h $(src)/ +endef + +GEN_VERSION_H := $(obj)/hypervisor/include/generated/version.h + +$(GEN_VERSION_H): $(src)/Makefile FORCE + $(call filechk,version) + +quiet_cmd_gen_pci_defs = GEN $@ +define cmd_gen_pci_defs + $(filter-out FORCE,$^) > $@ +endef + +GEN_PCI_DEFS_PY := $(obj)/pyjailhouse/pci_defs.py + +$(GEN_PCI_DEFS_PY): $(src)/scripts/gen_pci_defs.sh $(src)/include/jailhouse/pci_defs.h FORCE + $(call if_changed,gen_pci_defs) + +targets += pyjailhouse/pci_defs.py + +subdir-y := hypervisor configs inmates tools + +obj-m := driver/ + +# Do not generate files by creating dependencies if we are cleaning up +ifeq ($(filter %/Makefile.clean,$(MAKEFILE_LIST)),) + +$(obj)/driver $(addprefix $(obj)/,$(subdir-y)): $(GEN_CONFIG_MK) + +$(obj)/driver $(obj)/hypervisor: $(GEN_VERSION_H) + +$(obj)/tools: $(GEN_PCI_DEFS_PY) + +endif + +clean-files := pyjailhouse/*.pyc pyjailhouse/pci_defs.py + +CLEAN_DIRS := Documentation/generated hypervisor/include/generated \ + pyjailhouse/__pycache__ + +ifeq ($(shell test $(VERSION) -ge 5 && test $(PATCHLEVEL) -ge 4 && echo 1),1) +clean-files += $(CLEAN_DIRS) +else +clean-dirs += $(CLEAN_DIRS) +endif diff --git a/LICENSING.md b/LICENSING.md new file mode 100644 index 0000000000000000000000000000000000000000..b2f737404b5922b9fd4331c105ad4a3985e6f19f --- /dev/null +++ b/LICENSING.md @@ -0,0 +1,91 @@ +Jailhouse Licensing +=================== + +The Jailhouse hypervisor is primarily licensed under the terms of the GNU +General Public License version 2. + +Each of its source code files contains a license declaration in its header. +Whenever a file is provided under an additional or different license than +GPLv2, this is stated in the file header. Any file that may lack such a +header has to be considered licensed under GPLv2 (default license). + +The binary font file hypervisor/arch/x86/altc-8x16 was taken from the KBD +project in version 2.0.4 (https://www.kernel.org/pub/linux/utils/kbd, +http://kbd-project.org) which is distributed under the GNU GPL version 2 or +later (SPDX identifier GPL-2.0-or-later). + +If two licenses are specified in a file header, you are free to pick the one +that suits best your particular use case. You can also continue to use the +file under the dual license. When choosing only one, remove the reference to +the other from the file header. + + +License Usage +------------- + +The default license GPLv2 shall be used unless valid reasons are provided for a +deviation. Note the additional statement in GPLv2.txt about which code is not +considered derivative work of Jailhouse before considering a different license. + +For code that shall be licensed under more permissive terms, a dual-license +model of GPLv2 together with the BSD 2-clause license is preferred. This form +can be applicable on + + - interfaces to code that runs inside Jailhouse cells + - library-like code that applications or operating systems can include to + run in a Jailhouse cell + - generated configuration files + + +License Header Format +--------------------- + +Use the following template (replacing comment markers as required) when +creating a new file in the Jailhouse project: + +``` +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) , + * + * Authors: + * Your Name + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +``` + +When applying a dual GPL/BSD license, append the following to the above: + +``` + ... + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ +``` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..74017395f8c7412e801357d0621d706079a73c96 --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +# Check make version +need := 3.82 +ifneq ($(need),$(firstword $(sort $(MAKE_VERSION) $(need)))) +$(error Too old make version $(MAKE_VERSION), at least $(need) required) +endif + +# no recipes above this one (also no includes) +all: modules + +# includes installation-related variables and definitions +include scripts/include.mk + +# out-of-tree build for our kernel-module, firmware and inmates +KDIR ?= /lib/modules/`uname -r`/build + +INSTALL_MOD_PATH ?= $(DESTDIR) +export INSTALL_MOD_PATH + +DOXYGEN ?= doxygen + +kbuild = -C $(KDIR) M=$$PWD $@ + +ifneq ($(DESTDIR),) +PIP_ROOT = --root=$(shell readlink -f $(DESTDIR)) +endif + +modules clean: + $(Q)$(MAKE) $(kbuild) + +# documentation, build needs to be triggered explicitly +docs: + $(DOXYGEN) Documentation/Doxyfile + +modules_install: modules + $(Q)$(MAKE) $(kbuild) + +firmware_install: $(DESTDIR)$(firmwaredir) modules + $(INSTALL_DATA) hypervisor/jailhouse*.bin $< + +tool_inmates_install: $(DESTDIR)$(libexecdir)/jailhouse + $(INSTALL_DATA) inmates/tools/$(ARCH)/*.bin $< + +install: modules_install firmware_install tool_inmates_install + $(Q)$(MAKE) -C tools $@ src=. +ifeq ($(strip $(PYTHON_PIP_USABLE)), yes) + $(PIP) install --upgrade --force-reinstall $(PIP_ROOT) . +endif + +.PHONY: modules_install install clean firmware_install modules tools docs \ + docs_clean diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000000000000000000000000000000000000..e923ce76ee36a7381507c2f691a82dfebf3f8a05 --- /dev/null +++ b/TODO.md @@ -0,0 +1,88 @@ +Things to be addressed, at some point, or at least before releasing version 1.0 +(tagged with [v1.0]). Otherwise unsorted, unprioritized, likely incomplete. + +x86 support + - AMD interrupt remapping support + - power management [v1.0] + - block + - allow per cell (managing inter-core/inter-cell impacts) + - NMI control/status port - moderation or emulation required? [v1.0] + - whitelist-based MSR access [v1.0] + - CAT enhancements + - add support for CDP (code/data L3 partitioning) + - add support for L2 partitioning (-> Apollo Lake), including accurate + modeling of the partitioning scope (affected CPUs) + - Enable first-level only paging for VT-d + - share page table with EPT + - deprecate support for legacy format (second-level only)? + +ARM support + - v7 (32-bit) + - analyze cp15 system control registers access, trap critical ones + - v8 (64-bit) + - check if we need arch_inject_dabt + - analyze system control registers access, specifically regarding cache + maintenance and side effects on neighboring cores + - common (v7 and v8) + - System MMU v2 support + - re-evaluate IRQ priorities for GIC emulation and possibly add support + - properly reset interrupts on cell reset or reassignment + +Configuration + - review of format, rework of textual representation + - refactor config generator + - better internal structure, also to prepare non-x86 support + - enhance config generator + - confine the created root cell config to the essentially required + resources (e.g. PCI BARs) + - generate non-root cell configs + - add knowledge base about resource access rules that need manual review or + configurations that are known to be problematic (e.g. INTx sharing + between cells) + +Setup validation + - check integrity of configurations + - check integrity of runtime environment (hypervisor core & page_pool, + probably just excluding volatile Linux-related state variables) + - pure software solution (without security requirements) + - Intel TXT support? [WIP: master thesis] + - secure boot? + - check for execution inside hypervisor, allow only when enabled in config + - clear memory regions before reassignment to prevent information leaks? + +Inter-cell communication + - finalize and specify shared memory device [v1.0] + - 3 types of regions (r/w both, r/w local, r/o local) + - unprivileged MMIO register region (UIO-suitable) + - fast-path for checking remote state (vmexit-free) + - clarify: "ivshmem 2.0" or own device (with own IDs) + - specify virtual Ethernet protocol [v1.0] + - specify and implements virtual console protocol + - upstream Linux drivers + +Testing + - unit tests + - system tests, also in QEMU/KVM, maybe using Lava + Fuego + +Inmates + - reusable runtime environment for cell inmates + - skeleton in separate directory + - inter-cell communication library + - port free small-footprint RTOS to Jailhouse bare-metal environment + - RTEMS upstream support + - Zephyr? + - upstream Linux support + - discuss remaining patches + +Hardware error handling + - MCE processing + managed forwarding [v1.0] + - PCI AER + - APEI + - Thermal + - ... + +Monitoring + - report error-triggering devices behind IOMMUs via sysfs + - cell software watchdog via comm region messages + -> time out pending comm region messages and kill failing cells + (includes timeouts of unanswered shutdown requests) diff --git a/VERSION b/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..fc6f7a7094d3d17703eda326e78b3c484493d85b --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +v0.12 diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 0000000000000000000000000000000000000000..639ec80e8062d2d10557a236ef2aa83b40b90e45 --- /dev/null +++ b/ci/README.md @@ -0,0 +1,14 @@ +Jailhouse Continuous Integration Build Environment +================================================== + +This collects tools and generates the Linux kernel binaries required to build +Jailhouse in continuous integration environments. Currently, GitHub Actions is +the target environment. + +How to use +---------- + +- Prepare an Ubuntu system according to .github/workflows/main.yaml. +- Run gen-kernel-build.sh on that system. +- Upload ci/out/kernel-build.tar.xz to the location where Jailhouse's CI + expects it. diff --git a/ci/build-all-configs.sh b/ci/build-all-configs.sh new file mode 100755 index 0000000000000000000000000000000000000000..ef7ae2b7c47fa709e18a2f471747b07dfae06517 --- /dev/null +++ b/ci/build-all-configs.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015, 2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +set -e + +CONFIGS="x86 banana-pi amd-seattle" + +PREFIX= +if [ "$1" == "--cov" ]; then + export COVERITY_UNSUPPORTED=1 + PREFIX="cov-build --append-log --dir $2 $3" +fi + +for CONFIG in $CONFIGS; do + echo + echo "*** Building configuration $CONFIG ***" + + cp ci/jailhouse-config.h include/jailhouse/config.h + + case $CONFIG in + x86) + ARCH=x86_64 + CROSS_COMPILE= + ;; + amd-seattle) + ARCH=arm64 + CROSS_COMPILE=aarch64-linux-gnu- + ;; + *) + ARCH=arm + CROSS_COMPILE=arm-linux-gnueabihf- + ;; + esac + + $PREFIX make KDIR=ci/linux/build-$CONFIG ARCH=$ARCH \ + CROSS_COMPILE=$CROSS_COMPILE -j $((2*`nproc`)) + + # Keep the clean run out of sight for cov-build so that results are + # accumulated as far as possible. Multiple compilations of the same + # file will still leave only the last run in the results. + make KDIR=ci/linux/build-$CONFIG ARCH=$ARCH \ + CROSS_COMPILE=$CROSS_COMPILE clean +done diff --git a/ci/coverity_model.c b/ci/coverity_model.c new file mode 100644 index 0000000000000000000000000000000000000000..0bff8f388862af11a75b71e8d8ff3b036b38cbdc --- /dev/null +++ b/ci/coverity_model.c @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define __MODEL_GFP_USER (0x10u | 0x40u | 0x80u | 0x20000u) +#define __MODEL_GFP_NOWARN 0x200u + +void *kmalloc(size_t size, unsigned flags) +{ + void *ptr; + + if (flags == (__MODEL_GFP_USER | __MODEL_GFP_NOWARN)) + __coverity_tainted_data_sanitize__(size); + else + __coverity_tainted_data_sink__(size); + + ptr = __coverity_alloc__(size); + + __coverity_mark_as_uninitialized_buffer__(ptr); + __coverity_mark_as_afm_allocated__(ptr, "kfree"); + + return ptr; +} diff --git a/ci/gen-kernel-build.sh b/ci/gen-kernel-build.sh new file mode 100755 index 0000000000000000000000000000000000000000..6d7e2ee8d89b7a2e53f56d9f0ca93fcbb5a24603 --- /dev/null +++ b/ci/gen-kernel-build.sh @@ -0,0 +1,252 @@ +#!/bin/bash +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014-2021 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +BASEDIR=`cd \`dirname $0\`; pwd` + +if test -z $KERNEL; then + KERNEL=https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.xz +fi +if test -z $PARALLEL_BUILD; then + PARALLEL_BUILD=-j16 +fi +if test -z $OUTDIR; then + OUTDIR=$BASEDIR/out +fi + +prepare_out() +{ + rm -rf $OUTDIR + mkdir -p $OUTDIR + cd $OUTDIR +} + +prepare_kernel() +{ + ARCHIVE_FILE=`basename $KERNEL` + if ! test -f $BASEDIR/$ARCHIVE_FILE; then + wget $KERNEL -O $BASEDIR/$ARCHIVE_FILE + fi + tar xJf $BASEDIR/$ARCHIVE_FILE + ln -s linux-* linux + cd linux + patch -p1 << EOF +diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h +index dd9697b2bde8..47600a5894b1 100644 +--- a/arch/arm/include/asm/virt.h ++++ b/arch/arm/include/asm/virt.h +@@ -39,6 +39,8 @@ static inline void sync_boot_mode(void) + sync_cache_r(&__boot_cpu_mode); + } + ++void __hyp_set_vectors(unsigned long phys_vector_base); ++void __hyp_reset_vectors(void); + #else + #define __boot_cpu_mode (SVC_MODE) + #define sync_boot_mode() +@@ -73,6 +75,9 @@ static inline bool is_kernel_in_hyp_mode(void) + + #define HVC_SET_VECTORS 0 + #define HVC_SOFT_RESTART 1 ++#define HVC_RESET_VECTORS 2 ++ ++#define HVC_STUB_HCALL_NR 3 + + #endif /* __ASSEMBLY__ */ + +diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c +index 82e96ac83684..354ab3e4e41f 100644 +--- a/arch/arm/kernel/armksyms.c ++++ b/arch/arm/kernel/armksyms.c +@@ -16,6 +16,7 @@ + + #include + #include ++#include + + /* + * libgcc functions - functions that are used internally by the +@@ -175,3 +176,7 @@ EXPORT_SYMBOL(__pv_offset); + EXPORT_SYMBOL(__arm_smccc_smc); + EXPORT_SYMBOL(__arm_smccc_hvc); + #endif ++ ++#ifdef CONFIG_ARM_VIRT_EXT ++EXPORT_SYMBOL_GPL(__boot_cpu_mode); ++#endif +diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S +index 26d8e03b1dd3..c01622e6d9a4 100644 +--- a/arch/arm/kernel/hyp-stub.S ++++ b/arch/arm/kernel/hyp-stub.S +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -189,19 +190,19 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE + ENDPROC(__hyp_stub_install_secondary) + + __hyp_stub_do_trap: +-#ifdef ZIMAGE + teq r0, #HVC_SET_VECTORS + bne 1f +- /* Only the ZIMAGE stubs can change the HYP vectors */ + mcr p15, 4, r1, c12, c0, 0 @ set HVBAR + b __hyp_stub_exit +-#endif + + 1: teq r0, #HVC_SOFT_RESTART +- bne 2f ++ bne 1f + bx r1 + +-2: ldr r0, =HVC_STUB_ERR ++1: teq r0, #HVC_RESET_VECTORS ++ beq __hyp_stub_exit ++ ++ ldr r0, =HVC_STUB_ERR + __ERET + + __hyp_stub_exit: +@@ -210,9 +211,26 @@ __hyp_stub_exit: + ENDPROC(__hyp_stub_do_trap) + + /* +- * __hyp_set_vectors is only used when ZIMAGE must bounce between HYP +- * and SVC. For the kernel itself, the vectors are set once and for +- * all by the stubs. ++ * __hyp_set_vectors: Call this after boot to set the initial hypervisor ++ * vectors as part of hypervisor installation. On an SMP system, this should ++ * be called on each CPU. ++ * ++ * r0 must be the physical address of the new vector table (which must lie in ++ * the bottom 4GB of physical address space. ++ * ++ * r0 must be 32-byte aligned. ++ * ++ * Before calling this, you must check that the stub hypervisor is installed ++ * everywhere, by waiting for any secondary CPUs to be brought up and then ++ * checking that BOOT_CPU_MODE_HAVE_HYP(__boot_cpu_mode) is true. ++ * ++ * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or ++ * something else went wrong... in such cases, trying to install a new ++ * hypervisor is unlikely to work as desired. ++ * ++ * When you call into your shiny new hypervisor, sp_hyp will contain junk, ++ * so you will need to set that to something sensible at the new hypervisor's ++ * initialisation entry point. + */ + ENTRY(__hyp_set_vectors) + mov r1, r0 +@@ -228,6 +246,12 @@ ENTRY(__hyp_soft_restart) + ret lr + ENDPROC(__hyp_soft_restart) + ++ENTRY(__hyp_reset_vectors) ++ mov r0, #HVC_RESET_VECTORS ++ __HVC(0) ++ ret lr ++ENDPROC(__hyp_reset_vectors) ++ + #ifndef ZIMAGE + .align 2 + .L__boot_cpu_mode_offset: +@@ -245,4 +269,5 @@ __hyp_stub_trap: W(b) __hyp_stub_do_trap + __hyp_stub_irq: W(b) . + __hyp_stub_fiq: W(b) . + ENDPROC(__hyp_stub_vectors) ++EXPORT_SYMBOL_GPL(__hyp_stub_vectors) + +diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S +index 160f5881a0b7..a055e28be5c2 100644 +--- a/arch/arm64/kernel/hyp-stub.S ++++ b/arch/arm64/kernel/hyp-stub.S +@@ -10,6 +10,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -42,6 +43,7 @@ SYM_CODE_START(__hyp_stub_vectors) + ventry el1_fiq_invalid // FIQ 32-bit EL1 + ventry el1_error_invalid // Error 32-bit EL1 + SYM_CODE_END(__hyp_stub_vectors) ++EXPORT_SYMBOL_GPL(__hyp_stub_vectors) + + .align 11 + +diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c +index b3eef1d5c903..b1a6e9c550d4 100644 +--- a/arch/x86/kernel/apic/apic.c ++++ b/arch/x86/kernel/apic/apic.c +@@ -196,6 +196,7 @@ static struct resource lapic_resource = { + }; + + unsigned int lapic_timer_period = 0; ++EXPORT_SYMBOL_GPL(lapic_timer_period); + + static void apic_pm_activate(void); + +diff --git a/mm/ioremap.c b/mm/ioremap.c +index 5fa1ab41d152..d63c4ba067f9 100644 +--- a/mm/ioremap.c ++++ b/mm/ioremap.c +@@ -248,6 +248,7 @@ int ioremap_page_range(unsigned long addr, + + return err; + } ++EXPORT_SYMBOL_GPL(ioremap_page_range); + + #ifdef CONFIG_GENERIC_IOREMAP + void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot) +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 6ae491a8b210..ae80dbaf743c 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -2097,6 +2097,7 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags, + return __get_vm_area_node(size, 1, flags, start, end, NUMA_NO_NODE, + GFP_KERNEL, caller); + } ++EXPORT_SYMBOL_GPL(__get_vm_area_caller); + + /** + * get_vm_area - reserve a contiguous kernel virtual area +EOF +} + +build_kernel() +{ + mkdir build-$1 + cp $BASEDIR/kernel-config-$1 build-$1/.config + make O=build-$1 olddefconfig $PARALLEL_BUILD ARCH=$2 CROSS_COMPILE=$3 + make O=build-$1 $PARALLEL_BUILD ARCH=$2 CROSS_COMPILE=$3 + # clean up some unneeded build output + find build-$1 \( -name "*.o" -o -name "*.cmd" -o -name ".tmp_*" \) -exec rm -rf {} \; +} + +package_out() +{ + cd $OUTDIR + tar cJf kernel-build.tar.xz linux-* linux +} + +prepare_out +prepare_kernel +build_kernel x86 x86_64 +build_kernel banana-pi arm arm-linux-gnueabihf- +build_kernel amd-seattle arm64 aarch64-linux-gnu- +package_out diff --git a/ci/jailhouse-config.h b/ci/jailhouse-config.h new file mode 100644 index 0000000000000000000000000000000000000000..a4562125bb9e2f2a2ea07f13587ee0159bf47934 --- /dev/null +++ b/ci/jailhouse-config.h @@ -0,0 +1,3 @@ +#define CONFIG_TRACE_ERROR 1 +#define CONFIG_CRASH_CELL_ON_PANIC 1 +#define CONFIG_TEST_DEVICE 1 diff --git a/ci/kernel-config-amd-seattle b/ci/kernel-config-amd-seattle new file mode 100644 index 0000000000000000000000000000000000000000..a86a2dc8829822ef3973f5cbc8cee709b929bf70 --- /dev/null +++ b/ci/kernel-config-amd-seattle @@ -0,0 +1,330 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ_FULL=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_ARCH_SEATTLE=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_CMDLINE="mem=16G" +# CONFIG_SUSPEND is not set +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_JUMP_LABEL=y +# CONFIG_SECCOMP is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_AIX_PARTITION=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_KSM=y +CONFIG_CLEANCACHE=y +CONFIG_FRONTSWAP=y +CONFIG_ZSWAP=y +CONFIG_ZSMALLOC=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_MIGRATE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_MIP6=y +# CONFIG_IPV6_SIT is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_NETLABEL=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_EMATCH=y +CONFIG_NET_CLS_ACT=y +CONFIG_DCB=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_NET_DROP_MONITOR=y +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +CONFIG_PCIE_ECRC=y +CONFIG_PCI_STUB=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_HOTPLUG_PCI=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DEBUG_DEVRES=y +CONFIG_VEXPRESS_CONFIG=y +CONFIG_CONNECTOR=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_MEGARAID_NEWGEN=y +CONFIG_SCSI_DH=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_XGENE=y +CONFIG_ATA_PIIX=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_MIRROR=y +CONFIG_DM_ZERO=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_NET_FC=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +CONFIG_AMD_XGBE=y +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_I825XX is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_SERIO_AMBAKMI=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST=y +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_HW_RANDOM=y +CONFIG_RAW_DRIVER=y +CONFIG_MAX_RAW_DEVS=8192 +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_VEXPRESS=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_FB=y +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_ARMCLCD=y +CONFIG_FB_SIMPLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_NTRIG=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_ACCESSIBILITY=y +CONFIG_A11Y_BRAILLE_CONSOLE=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_SYSTOHC is not set +CONFIG_DMADEVICES=y +CONFIG_ASYNC_TX_DMA=y +CONFIG_AUXDISPLAY=y +CONFIG_VFIO=y +CONFIG_VFIO_PCI=y +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +CONFIG_COMMON_CLK_XGENE=y +CONFIG_ARM_SMMU=y +CONFIG_PWM=y +CONFIG_RESET_CONTROLLER=y +CONFIG_PHY_XGENE=y +CONFIG_ARM_CCN=y +CONFIG_DAX=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_EFIVAR_FS=y +CONFIG_PSTORE=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_NFSD=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_V4_SECURITY_LABEL=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_NETWORK_XFRM=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=m +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_DEV_CCP=y +# CONFIG_CRYPTO_DEV_CCP_DD is not set +CONFIG_PRINTK_TIME=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FRAME_WARN=1024 +CONFIG_STRIP_ASM_SYMS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_FUNCTION_GRAPH_TRACER is not set +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_ATOMIC64_SELFTEST=y +CONFIG_TEST_KSTRTOX=y diff --git a/ci/kernel-config-banana-pi b/ci/kernel-config-banana-pi new file mode 100644 index 0000000000000000000000000000000000000000..3ce0ad7295242a731418f6ce334bf169650f46e9 --- /dev/null +++ b/ci/kernel-config-banana-pi @@ -0,0 +1,145 @@ +CONFIG_USELIB=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PERF_EVENTS=y +CONFIG_ARCH_SUNXI=y +# CONFIG_MACH_SUN4I is not set +# CONFIG_MACH_SUN5I is not set +# CONFIG_MACH_SUN6I is not set +# CONFIG_MACH_SUN8I is not set +# CONFIG_MACH_SUN9I is not set +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_SMP=y +CONFIG_HIGHMEM=y +# CONFIG_ARM_MODULE_PLTS is not set +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_SECCOMP is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +CONFIG_CFG80211=y +CONFIG_CFG80211_DEBUGFS=y +CONFIG_MAC80211=y +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_SD=y +CONFIG_ATA=y +CONFIG_AHCI_SUNXI=y +CONFIG_NETDEVICES=y +CONFIG_SUN4I_EMAC=y +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_CARL9170=m +CONFIG_RTL_CARDS=m +CONFIG_RTL8192CU=m +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=8 +CONFIG_SERIAL_8250_RUNTIME_UARTS=8 +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_HW_RANDOM is not set +CONFIG_DEVKMEM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MV64XXX=y +CONFIG_SPI=y +CONFIG_SPI_SUN4I=y +CONFIG_SPI_SUN6I=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_SUPPLY=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_SUNXI_WATCHDOG=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_FB=y +CONFIG_FB_SIMPLE=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_MMC=y +CONFIG_MMC_SUNXI=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_INTF_SYSFS is not set +# CONFIG_RTC_INTF_PROC is not set +CONFIG_RTC_DRV_SUNXI=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_GENERIC_PHY=y +CONFIG_EXT4_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=m +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_KGDB=y +CONFIG_KGDB_TESTS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SCHEDSTATS=y +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LOCKING_API_SELFTESTS=y +# CONFIG_RCU_TRACE is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_DEBUG_USER=y diff --git a/ci/kernel-config-x86 b/ci/kernel-config-x86 new file mode 100644 index 0000000000000000000000000000000000000000..167cb8ed85e0d58f80da48a57a654a44b7b0af5f --- /dev/null +++ b/ci/kernel-config-x86 @@ -0,0 +1,293 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_SMP=y +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_MICROCODE_AMD=y +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_NUMA=y +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +# CONFIG_MTRR_SANITIZER is not set +CONFIG_EFI=y +CONFIG_HZ_1000=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +CONFIG_HIBERNATION=y +CONFIG_PM_DEBUG=y +CONFIG_PM_TRACE_RTC=y +CONFIG_ACPI_DOCK=y +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_IA32_EMULATION=y +CONFIG_EFI_VARS=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_BINFMT_MISC=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_TCP_MD5SIG=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_ADVANCED is not set +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_NET_SCHED=y +CONFIG_NET_EMATCH=y +CONFIG_NET_CLS_ACT=y +CONFIG_HAMRADIO=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +CONFIG_HOTPLUG_PCI=y +CONFIG_PCCARD=y +CONFIG_YENTA=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DEBUG_DEVRES=y +CONFIG_CONNECTOR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_ATA_PIIX=y +CONFIG_PATA_AMD=y +CONFIG_PATA_OLDPIIX=y +CONFIG_PATA_SCH=y +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_MIRROR=y +CONFIG_DM_ZERO=y +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +# CONFIG_NET_VENDOR_AURORA is not set +CONFIG_TIGON3=y +CONFIG_NET_TULIP=y +CONFIG_E100=y +CONFIG_E1000=y +CONFIG_SKY2=y +CONFIG_FORCEDETH=y +CONFIG_8139TOO=y +CONFIG_FDDI=y +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +# CONFIG_SERIAL_8250_MID is not set +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_AMD is not set +CONFIG_DEVKMEM=y +CONFIG_NVRAM=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP is not set +CONFIG_I2C_I801=y +CONFIG_WATCHDOG=y +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_DRM=y +CONFIG_DRM_I915=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_EFI=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_HRTIMER=y +CONFIG_SND_SEQUENCER=y +CONFIG_SND_SEQ_DUMMY=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_PREALLOC_SIZE=64 +CONFIG_HIDRAW=y +CONFIG_HID_GYRATION=y +CONFIG_LOGITECH_FF=y +CONFIG_HID_NTRIG=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PLANTRONICS=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_PRINTER=y +CONFIG_USB_STORAGE=y +CONFIG_EDAC=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_DMADEVICES=y +CONFIG_EEEPC_LAPTOP=y +CONFIG_AMD_IOMMU=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_DAX=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +# CONFIG_EFIVAR_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_DES=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +# CONFIG_RCU_TRACE is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_PROVIDE_OHCI1394_DMA_INIT=y +# CONFIG_STRICT_DEVMEM is not set +CONFIG_EARLY_PRINTK_DBGP=y +CONFIG_DEBUG_BOOT_PARAMS=y diff --git a/configs/Makefile b/configs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..327043b71298b7ba4e994ffbe8f5008c09b9602f --- /dev/null +++ b/configs/Makefile @@ -0,0 +1,42 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +LINUXINCLUDE := -I$(src)/../hypervisor/arch/$(SRCARCH)/include \ + -I$(src)/../hypervisor/include \ + -I$(src)/../include +KBUILD_CFLAGS := -Werror -Wall -Wextra -D__LINUX_COMPILER_TYPES_H + +ifneq ($(wildcard $(obj)/../include/jailhouse/config.h),) +KBUILD_CFLAGS += -include $(obj)/../include/jailhouse/config.h +endif + +OBJCOPYFLAGS := -O binary --remove-section=.note.gnu.property + +CONFIGS = $(shell cd $(src); ls $(SRCARCH)/*.c) + +always-y := $(CONFIGS:.c=.cell) + +targets += $(CONFIGS:.c=.o) $(CONFIGS:.c=.cell) + +DTS = $(shell cd $(src); ls $(SRCARCH)/dts/*.dts 2>/dev/null) +always-y += $(DTS:.dts=.dtb) +targets += $(DTS:.dts=.dtb) + +# prevent deleting intermediate files which would cause rebuilds +.SECONDARY: $(addprefix $(obj)/,$(CONFIGS:.c=.o)) + +$(obj)/%.cell: $(obj)/%.o FORCE + $(call if_changed,objcopy) diff --git a/configs/arm/bananapi-inmate-demo.c b/configs/arm/bananapi-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..a83aff88bf4e423233c3b7a2517ea8b3757706fa --- /dev/null +++ b/configs/arm/bananapi-inmate-demo.c @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Banana Pi: + * 1 CPU, 64K RAM, serial ports 4-7, CCU+GPIO + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[5]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "bananapi-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0x01c29c00, + .clock_reg = 0x01c2006c, + .gate_nr = 23, + .divider = 0x0d, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* CCU */ { + .phys_start = 0x01c20000, + .virt_start = 0x01c20000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* GPIO: port H */ { + .phys_start = 0x01c208fc, + .virt_start = 0x01c208fc, + .size = 0x24, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART 4-7 */ { + .phys_start = 0x01c29000, + .virt_start = 0x01c29000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bfe0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, +}; diff --git a/configs/arm/bananapi-linux-demo.c b/configs/arm/bananapi-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..9819091e29ac46e89eb7d2992cfe18300d5e70c0 --- /dev/null +++ b/configs/arm/bananapi-linux-demo.c @@ -0,0 +1,115 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Banana Pi: + * 1 CPU, 64M RAM, serial port 7 + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[9]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "bananapi-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 123, + + .console = { + .address = 0x01c29c00, + .clock_reg = 0x01c2006c, + .gate_nr = 23, + .divider = 0x0d, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 1), + /* CCU (HACK) */ { + .phys_start = 0x01c2006c, + .virt_start = 0x01c2006c, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART 7 */ { + .phys_start = 0x01c29c00, + .virt_start = 0x01c29c00, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x78000000, + .virt_start = 0x78000000, + .size = 0x3ef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 1 << (52-32), 0, 0, 1 << (156-128), + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/bananapi.c b/configs/arm/bananapi.c new file mode 100644 index 0000000000000000000000000000000000000000..4e566380b9924f6f692e0d394ed0f970e9dd1b17 --- /dev/null +++ b/configs/arm/bananapi.c @@ -0,0 +1,210 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for Banana Pi board (A20 dual-core Cortex-A7, 1G RAM) + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[20]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7c000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0x01c28000, + .size = 0x1000, + /* .clock_reg = 0x01c2006c, */ + /* .gate_nr = 16 */ + /* .divider = 0x0d, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x2000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0x01c81000, + .gicc_base = 0x01c82000, + .gich_base = 0x01c84000, + .gicv_base = 0x01c86000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Banana-Pi", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 108, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 0), + /* SPI */ { + .phys_start = 0x01c05000, + .virt_start = 0x01c05000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMC */ { + .phys_start = 0x01c0f000, + .virt_start = 0x01c0f000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB + PMU1 */ { + .phys_start = 0x01c14000, + .virt_start = 0x01c14000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SATA */ { + .phys_start = 0x01c18000, + .virt_start = 0x01c18000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB + PMU2 */ { + .phys_start = 0x01c1c000, + .virt_start = 0x01c1c000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CCU */ { + .phys_start = 0x01c20000, + .virt_start = 0x01c20000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Ints */ { + .phys_start = 0x01c20400, + .virt_start = 0x01c20400, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* GPIO: ports A-G */ { + .phys_start = 0x01c20800, + .virt_start = 0x01c20800, + .size = 0xfc, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* GPIO: port H */ { + .phys_start = 0x01c208fc, + .virt_start = 0x01c208fc, + .size = 0x24, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* GPIO: port I */ { + .phys_start = 0x01c20920, + .virt_start = 0x01c20920, + .size = 0x24, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* GPIO: intr config */ { + .phys_start = 0x01c20a00, + .virt_start = 0x01c20a00, + .size = 0x1c, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Timer */ { + .phys_start = 0x01c20c00, + .virt_start = 0x01c20c00, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART0-3 */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GMAC */ { + .phys_start = 0x01c50000, + .virt_start = 0x01c50000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HSTIMER */ { + .phys_start = 0x01c60000, + .virt_start = 0x01c60000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3bf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/dts/inmate-bananapi.dts b/configs/arm/dts/inmate-bananapi.dts new file mode 100644 index 0000000000000000000000000000000000000000..78a29301f0ebb8c4c35868765ab616b486fff016 --- /dev/null +++ b/configs/arm/dts/inmate-bananapi.dts @@ -0,0 +1,116 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Banana Pi board, + * corresponds to configs/arm/bananapi-linux-demo.c + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on Banana Pi"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@1 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <1>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x78000000 0x3ef0000>; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: clk24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + apb1_gates: clk@01c2006c { + #clock-cells = <1>; + compatible = "allwinner,sun7i-a20-apb1-gates-clk"; + reg = <0x01c2006c 0x4>; + clocks = <&osc24M>; + clock-indices = <23>; + clock-output-names = "apb1_uart7"; + }; + }; + + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uart: serial@01c29c00 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c29c00 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <24000000>; + clocks = <&apb1_gates 23>; + }; + + pci@2000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 123 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 125 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 126 IRQ_TYPE_EDGE_RISING>; + reg = <0x2000000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm/dts/inmate-emtrion-emconrzg1e.dts b/configs/arm/dts/inmate-emtrion-emconrzg1e.dts new file mode 100644 index 0000000000000000000000000000000000000000..d04bd3e7581111463ab447763dc9d54242dbba7e --- /dev/null +++ b/configs/arm/dts/inmate-emtrion-emconrzg1e.dts @@ -0,0 +1,182 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on emCON-RZ/G1E board, + * corresponds to configs/arm/emtrion-emconrzg1e-linux-demo.c + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define R8A7745_PD_CA7_CPU1 6 +#define R8A7745_PD_ALWAYS_ON 32 + +/dts-v1/; + +/memreserve/ 0x0000000070000000 0x0000000000002000; +/ { + model = "Jailhouse cell on emCON-RZ/G1E"; + compatible = "emtrion,emconrzg1e", "renesas,r8a7745"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + aliases { + i2c2 = "/i2c@e6530000"; + serial4 = "/serial@e6ee0000"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@1 { + enable-method = "psci"; + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <1>; + clock-frequency = <1000000000>; + power-domains = <&sysc R8A7745_PD_CA7_CPU1>; + }; + }; + + memory@70000000 { + device_type = "memory"; + reg = <0x0 0x70000000 0x0 0x0bef0000>; + }; + + chosen { + bootargs = "console=ttySC4,115200 root=/dev/sda1 rootwait + ip=dhcp loglevel=8 vt.global_cursor_default=0 + consoleblank=0"; + stdout-path = "/serial@e6ee0000"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + vcc_sdhi0: regulator@0 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + + }; + + vccq_sdhi0: regulator@1 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 VccQ"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + }; + + gic: interrupt-controller@f1001000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x0 0xf1001000 0x0 0x1000>, + <0x0 0xf1002000 0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + sysc: system-controller@e6180000 { + compatible = "renesas,r8a7745-sysc"; + reg = <0 0xe6180000 0 0x0200>; + #power-domain-cells = <1>; + }; + + pfc: pin-controller@e6060000 { + compatible = "renesas,pfc-r8a7745"; + reg = <0x0 0xe6060000 0x0 0x11c>; + + serial4 { + renesas,groups = "scif4_data_c"; + renesas,function = "scif4"; + }; + + sdhi0_pins: sd0 { + renesas,groups = "sdhi0_data4", "sdhi0_ctrl", + "sdhi0_cd", "sdhi0_wp"; + renesas,function = "sdhi0"; + }; + }; + + clocks { + scif4_clk: scif4_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <65000000>; + clock-output-names = "scif4_clk"; + }; + sdhi0_clk: sdhi0_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <195000000>; + clock-output-names = "sdhi0_clk"; + }; + i2c2_clk: i2c2_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000>; + clock-output-names = "i2c2_clk"; + }; + }; + + scif4: serial@e6ee0000 { + compatible = "renesas,scif-r8a7745", "renesas,scif"; + reg = <0 0xe6ee0000 0 0x40>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&scif4_clk 0>; + clock-names = "peripheral_clk"; + pinctrl-names = "default"; + }; + + sdhi0: sd@ee100000 { + compatible = "renesas,sdhi-r8a7745"; + reg = <0 0xee100000 0 0x200>; + interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&sdhi0_clk 0>; + vmmc-supply = <&vcc_sdhi0>; + vqmmc-supply = <&vccq_sdhi0>; + }; + + i2c2: i2c@e6530000 { + compatible = "renesas,i2c-r8a7745"; + reg = <0 0xe6530000 0 0x40>; + interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + clocks = <&i2c2_clk 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; +}; diff --git a/configs/arm/dts/inmate-emtrion-emconrzg1h.dts b/configs/arm/dts/inmate-emtrion-emconrzg1h.dts new file mode 100644 index 0000000000000000000000000000000000000000..e90e23ff6d10a5613d55f696eb6905a3c1cbf88f --- /dev/null +++ b/configs/arm/dts/inmate-emtrion-emconrzg1h.dts @@ -0,0 +1,182 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on emCON-RZ/G1H board, + * corresponds to configs/arm/emtrion-emconrzg1h-linux-demo.c + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define R8A7742_PD_CA15_CPU3 3 +#define R8A7742_PD_ALWAYS_ON 32 + +/dts-v1/; + +/memreserve/ 0x0000000070000000 0x0000000000002000; +/ { + model = "Jailhouse cell on emCON-RZ/G1H"; + compatible = "emtrion,emconrzg1h", "renesas,r8a7742"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + aliases { + i2c2 = "/i2c@e6530000"; + serial5 = "/serial@e6c40000"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@3 { + enable-method = "psci"; + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <3>; + clock-frequency = <1400000000>; + power-domains = <&sysc R8A7742_PD_CA15_CPU3>; + }; + }; + + memory@70000000 { + device_type = "memory"; + reg = <0x0 0x70000000 0x0 0x0bef0000>; + }; + + chosen { + bootargs = "console=ttySC5,115200 root=/dev/sda1 rootwait + ip=dhcp loglevel=8 vt.global_cursor_default=0 + consoleblank=0"; + stdout-path = "/serial@e6c40000"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + vcc_sdhi0: regulator@0 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + + }; + + vccq_sdhi0: regulator@1 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 VccQ"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + }; + + gic: interrupt-controller@f1001000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x0 0xf1001000 0x0 0x1000>, + <0x0 0xf1002000 0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + sysc: system-controller@e6180000 { + compatible = "renesas,r8a7742-sysc"; + reg = <0 0xe6180000 0 0x0200>; + #power-domain-cells = <1>; + }; + + pfc: pin-controller@e6060000 { + compatible = "renesas,pfc-r8a7742"; + reg = <0 0xe6060000 0 0x250>; + + serial5 { + renesas,groups = "scifa0_data_b"; + renesas,function = "scifa0"; + }; + + sdhi0_pins: sd0 { + renesas,groups = "sdhi0_data4", "sdhi0_ctrl", + "sdhi0_cd", "sdhi0_wp"; + renesas,function = "sdhi0"; + }; + }; + + clocks { + scifa0_clk: scifa0_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <52000000>; + clock-output-names = "scifa0_clk"; + }; + sdhi0_clk: sdhi0_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <195000000>; + clock-output-names = "sdhi0_clk"; + }; + i2c2_clk: i2c2_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000>; + clock-output-names = "i2c2_clk"; + }; + }; + + scifa0: serial@e6c40000 { + compatible = "renesas,scifa-r8a7742", "renesas,scifa"; + reg = <0 0xe6c40000 0 0x40>; + interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&scifa0_clk 0>; + clock-names = "peripheral_clk"; + pinctrl-names = "default"; + }; + + sdhi0: sd@ee100000 { + compatible = "renesas,sdhi-r8a7742"; + reg = <0 0xee100000 0 0x200>; + interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&sdhi0_clk 0>; + vmmc-supply = <&vcc_sdhi0>; + vqmmc-supply = <&vccq_sdhi0>; + }; + + i2c2: i2c@e6530000 { + compatible = "renesas,i2c-r8a7742"; + reg = <0 0xe6530000 0 0x40>; + interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; + clocks = <&i2c2_clk 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; +}; diff --git a/configs/arm/dts/inmate-emtrion-emconrzg1m.dts b/configs/arm/dts/inmate-emtrion-emconrzg1m.dts new file mode 100644 index 0000000000000000000000000000000000000000..d95a03d21481bb37e592c00a146baca13b616d07 --- /dev/null +++ b/configs/arm/dts/inmate-emtrion-emconrzg1m.dts @@ -0,0 +1,182 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on emCON-RZ/G1M board, + * corresponds to configs/arm/emtrion-emconrzg1m-linux-demo.c + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define R8A7743_PD_CA15_CPU1 1 +#define R8A7743_PD_ALWAYS_ON 32 + +/dts-v1/; + +/memreserve/ 0x0000000070000000 0x0000000000002000; +/ { + model = "Jailhouse cell on emCON-RZ/G1M"; + compatible = "emtrion,emconrzg1m", "renesas,r8a7743"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + aliases { + i2c2 = "/i2c@e6530000"; + serial6 = "/serial@e6ee0000"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@1 { + enable-method = "psci"; + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <1>; + clock-frequency = <1500000000>; + power-domains = <&sysc R8A7743_PD_CA15_CPU1>; + }; + }; + + memory@70000000 { + device_type = "memory"; + reg = <0x0 0x70000000 0x0 0x0bef0000>; + }; + + chosen { + bootargs = "console=ttySC6,115200 root=/dev/sda1 rootwait + ip=dhcp loglevel=8 vt.global_cursor_default=0 + consoleblank=0"; + stdout-path = "/serial@e6ee0000"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + vcc_sdhi0: regulator@0 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + + }; + + vccq_sdhi0: regulator@1 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 VccQ"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-boot-on; + regulator-always-on; + }; + + gic: interrupt-controller@f1001000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x0 0xf1001000 0x0 0x1000>, + <0x0 0xf1002000 0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + sysc: system-controller@e6180000 { + compatible = "renesas,r8a7743-sysc"; + reg = <0 0xe6180000 0 0x0200>; + #power-domain-cells = <1>; + }; + + pfc: pin-controller@e6060000 { + compatible = "renesas,pfc-r8a7743"; + reg = <0x0 0xe6060000 0x0 0x11c>; + + serial6 { + renesas,groups = "scif4_data_c"; + renesas,function = "scif4"; + }; + + sdhi0_pins: sd0 { + renesas,groups = "sdhi0_data4", "sdhi0_ctrl", + "sdhi0_cd", "sdhi0_wp"; + renesas,function = "sdhi0"; + }; + }; + + clocks { + scif4_clk: scif4_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <65000000>; + clock-output-names = "scif4_clk"; + }; + sdhi0_clk: sdhi0_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <195000000>; + clock-output-names = "sdhi0_clk"; + }; + i2c2_clk: i2c2_clk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000>; + clock-output-names = "i2c2_clk"; + }; + }; + + scif4: serial@e6ee0000 { + compatible = "renesas,scif-r8a7743", "renesas,scif"; + reg = <0 0xe6ee0000 0 0x40>; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&scif4_clk 0>; + clock-names = "peripheral_clk"; + pinctrl-names = "default"; + }; + + sdhi0: sd@ee100000 { + compatible = "renesas,sdhi-r8a7743"; + reg = <0 0xee100000 0 0x200>; + interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + status = "okay"; + clocks = <&sdhi0_clk 0>; + vmmc-supply = <&vcc_sdhi0>; + vqmmc-supply = <&vccq_sdhi0>; + }; + + i2c2: i2c@e6530000 { + compatible = "renesas,i2c-r8a7743"; + reg = <0 0xe6530000 0 0x40>; + interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + clocks = <&i2c2_clk 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; +}; diff --git a/configs/arm/dts/inmate-jetson-tk1.dts b/configs/arm/dts/inmate-jetson-tk1.dts new file mode 100644 index 0000000000000000000000000000000000000000..f055b48dbcf0d5ab261deba8c0d538c2be529992 --- /dev/null +++ b/configs/arm/dts/inmate-jetson-tk1.dts @@ -0,0 +1,99 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Jetson TK1 board, + * corresponds to configs/arm/jetson-tk1-linux-demo.c + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on NVIDIA Jetson TK1"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <0x2>; + }; + + cpu@3 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <0x3>; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + gic: interrupt-controller@50041000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x50041000 0x1000>, + <0x50042000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + serial@70006300 { + compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; + reg = <0x70006300 0x40>; + reg-shift = <2>; + interrupts = ; + clock-frequency = <408000000>; + status = "okay"; + }; + + pci@48000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 152 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 153 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 155 IRQ_TYPE_EDGE_RISING>; + reg = <0x48000000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm/dts/inmate-orangepi0.dts b/configs/arm/dts/inmate-orangepi0.dts new file mode 100644 index 0000000000000000000000000000000000000000..cfdb7cdadd913143bc7b5e0667473d232ebbd3dd --- /dev/null +++ b/configs/arm/dts/inmate-orangepi0.dts @@ -0,0 +1,112 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Orange Pi Zero board, + * corresponds to configs/arm/orangepi0-linux-demo.c + * + * Copyright (c) Siemens AG, 2016-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on Orange Pi Zero"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <3>; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: clk24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + }; + + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uart: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <24000000>; + }; + + pci@2000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 123 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 125 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 126 IRQ_TYPE_EDGE_RISING>; + reg = <0x2000000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm/dts/inmate-qemu-arm.dts b/configs/arm/dts/inmate-qemu-arm.dts new file mode 100644 index 0000000000000000000000000000000000000000..06e92912bc93e40d3dfd803705e4a07130da5d3b --- /dev/null +++ b/configs/arm/dts/inmate-qemu-arm.dts @@ -0,0 +1,105 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on QEMU ARM target, + * corresponds to configs/arm/qemu-arm-linux-demo.c + * + * Copyright (c) Siemens AG, 2016-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on QEMU ARM"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <3>; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@8000000 { + compatible = "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x08000000 0x1000>, /* GICD */ + <0x08010000 0x1000>; /* GICC */ + }; + + apb_pclk: clk24mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clk24mhz"; + }; + + uart0: serial@9000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x09000000 0x1000>; + interrupts = ; + clocks = <&apb_pclk>, <&apb_pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pci@7000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 109 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 111 IRQ_TYPE_EDGE_RISING>; + reg = <0x08e00000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm/emtrion-rzg1e-inmate-demo.c b/configs/arm/emtrion-rzg1e-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..d8f21a70c5f3413c78e867d2478f4eba019b8fb2 --- /dev/null +++ b/configs/arm/emtrion-rzg1e-inmate-demo.c @@ -0,0 +1,71 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on emCON-RZ/G1E: + * 1 CPU, 64K RAM, serial ports SCIF4, CCU + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1e-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0xe6ee0000, + .clock_reg = 0xe615014c, + .gate_nr = 15, + .divider = 0x10, + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* SCIF4 */ { + .phys_start = 0xe6ee0000, + .virt_start = 0xe6ee0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_8 | + JAILHOUSE_MEM_IO_16 | JAILHOUSE_MEM_IO_32, + }, + /* RAM */ { + .phys_start = 0x7bff0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm/emtrion-rzg1e-linux-demo.c b/configs/arm/emtrion-rzg1e-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..b76b8e84441881840a0d27855fd4d22b34690187 --- /dev/null +++ b/configs/arm/emtrion-rzg1e-linux-demo.c @@ -0,0 +1,164 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on emCON-RZ/G1E: + * 1 CPU, 64M RAM, I2C bus I2C2, serial port SCIF4, SDHI0 + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[14]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1e-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 123, */ + + .console = { + .address = 0xe6ee0000, + .clock_reg = 0xe615014c, + .gate_nr = 15, + .divider = 0x10, + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 1), + /* RST, MODEMR */ { + .phys_start = 0xe6160060, + .virt_start = 0xe6160060, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Generic Counter */ { + .phys_start = 0xe6080000, + .virt_start = 0xe6080000, + .size = 0x40, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* PFC (HACK) */ { + .phys_start = 0xe6060000, + .virt_start = 0xe6060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SYSC (HACK) */ { + .phys_start = 0xe6180000, + .virt_start = 0xe6180000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SCIF4 */ { + .phys_start = 0xe6ee0000, + .virt_start = 0xe6ee0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32 | + JAILHOUSE_MEM_IO_16 | JAILHOUSE_MEM_IO_8, + }, + /* SDHI0: SDC */ { + .phys_start = 0xee100000, + .virt_start = 0xee100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0xbef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 32, + .pin_bitmap = { + 1 << (24+32 - 32), /* SCIF4 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0, 1 << (165+32 - 192) /* SDHI0 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 1 << (286+32 - 288), /* I2C2 */ + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/emtrion-rzg1e.c b/configs/arm/emtrion-rzg1e.c new file mode 100644 index 0000000000000000000000000000000000000000..f392bf00464e07a72daba821e97f378c3c62c7c7 --- /dev/null +++ b/configs/arm/emtrion-rzg1e.c @@ -0,0 +1,238 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for emtrion's emCON-RZ/G1E board + * (RZ/G1E dual-core Cortex-A7, 1G RAM) + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[22]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7c000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0xe62d0000, + .size = 0x1000, + .clock_reg = 0xe615014c, + .gate_nr = 13, + /* .divider = 0x2e, */ + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4 | + JAILHOUSE_CON_INVERTED_GATE, + }, + .platform_info = { + /* .pci_mmconfig_base = 0x2000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, */ + .arm = { + .gic_version = 2, + .gicd_base = 0xf1001000, + .gicc_base = 0xf1002000, + .gich_base = 0xf1004000, + .gicv_base = 0xf1006000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "emCON-RZ/G1E", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 108, */ + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 0), + /* CPG */ { + .phys_start = 0xe6150000, + .virt_start = 0xe6150000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* APMU */ { + .phys_start = 0xe6151000, + .virt_start = 0xe6151000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* IRQC */ { + .phys_start = 0xe61c0000, + .virt_start = 0xe61c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT0 */ { + .phys_start = 0xffca0000, + .virt_start = 0xffca0000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT1 */ { + .phys_start = 0xe6130000, + .virt_start = 0xe6130000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* TMU0 */ { + .phys_start = 0xe61e0000, + .virt_start = 0xe61e0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* HSCIF2 */ { + .phys_start = 0xe62d0000, + .virt_start = 0xe62d0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* EtherAVB */ { + .phys_start = 0xe6800000, + .virt_start = 0xe6800000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMCIF: eMMC */ { + .phys_start = 0xee200000, + .virt_start = 0xee200000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB0 */ { + .phys_start = 0xee080000, + .virt_start = 0xee080000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPDU */ { + .phys_start = 0xfe930000, + .virt_start = 0xfe930000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DU */ { + .phys_start = 0xfeb00000, + .virt_start = 0xfeb00000, + .size = 0x00040000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN0 */ { + .phys_start = 0xe6e80000, + .virt_start = 0xe6e80000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN1 */ { + .phys_start = 0xe6e88000, + .virt_start = 0xe6e88000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C0 */ { + .phys_start = 0xe6508000, + .virt_start = 0xe6508000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C1 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6540000, + .virt_start = 0xe6540000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3bf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/emtrion-rzg1h-inmate-demo.c b/configs/arm/emtrion-rzg1h-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..11695b75e6f219dbeabc9dae557df613451a5e61 --- /dev/null +++ b/configs/arm/emtrion-rzg1h-inmate-demo.c @@ -0,0 +1,70 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on emCON-RZ/G1H: + * 1 CPU, 64K RAM, serial ports SCIFA0, CCU + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1h-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0xe6c40000, + .clock_reg = 0xe6150138, + .gate_nr = 4, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_SCIFA, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* SCIFA0 */ { + .phys_start = 0xe6c40000, + .virt_start = 0xe6c40000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bff0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm/emtrion-rzg1h-linux-demo.c b/configs/arm/emtrion-rzg1h-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..a41c94dd729529a98dc4827a6817e715d0ceee61 --- /dev/null +++ b/configs/arm/emtrion-rzg1h-linux-demo.c @@ -0,0 +1,178 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on emCON-RZ/G1H: + * 1 CPU, 64M RAM, I2C bus I2C2, serial port SCIFA0, SDHI0 + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1h-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 123, */ + + .console = { + .address = 0xe6c40000, + .clock_reg = 0xe6150138, + .gate_nr = 4, + .divider = 0x1b, + .type= JAILHOUSE_CON_TYPE_SCIFA, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 1), + /* RST, MODEMR */ { + .phys_start = 0xe6160060, + .virt_start = 0xe6160060, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* RST, CA15RESCNT */ { + .phys_start = 0xe6160040, + .virt_start = 0xe6160040, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* IRQC */ { + .phys_start = 0xe61c0000, + .virt_start = 0xe61c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Generic Counter */ { + .phys_start = 0xe6080000, + .virt_start = 0xe6080000, + .size = 0x40, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* PFC (HACK) */ { + .phys_start = 0xe6060000, + .virt_start = 0xe6060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SYSC (HACK) */ { + .phys_start = 0xe6180000, + .virt_start = 0xe6180000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SCIFA0 */ { + .phys_start = 0xe6c40000, + .virt_start = 0xe6c40000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32 | + JAILHOUSE_MEM_IO_16 | JAILHOUSE_MEM_IO_8, + }, + /* SDHI0: SDC */ { + .phys_start = 0xee100000, + .virt_start = 0xee100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0xbef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 128, + .pin_bitmap = { + 1 << (144+32 - 160), /* SCIFA0 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0, 1 << (165+32 - 192) /* SDHI0 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 1 << (286+32 - 288), /* I2C2 */ + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/emtrion-rzg1h.c b/configs/arm/emtrion-rzg1h.c new file mode 100644 index 0000000000000000000000000000000000000000..26fa624a6565a35a1f86471a0e0f9d79fedf1078 --- /dev/null +++ b/configs/arm/emtrion-rzg1h.c @@ -0,0 +1,364 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for emtrion's emCON-RZ/G1H board + * (RZ/G1H octa-core Cortex-A7/Cortex-A15, 2G RAM) + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[40]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xbc000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0xe6c50000, + .size = 0x1000, + .clock_reg = 0xe6150138, + .gate_nr = 3, + /* .divider = 0x2e, */ + .type= JAILHOUSE_CON_TYPE_SCIFA, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4 | + JAILHOUSE_CON_INVERTED_GATE, + }, + .platform_info = { + /* .pci_mmconfig_base = 0x2000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, */ + .arm = { + .gic_version = 2, + .gicd_base = 0xf1001000, + .gicc_base = 0xf1002000, + .gich_base = 0xf1004000, + .gicv_base = 0xf1006000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "emCON-RZ/G1H", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 108, */ + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 0), + /* SYS-DMAC */ { + .phys_start = 0xe6700000, + .virt_start = 0xe6700000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SYS-DMAC */ { + .phys_start = 0xe6720000, + .virt_start = 0xe6720000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SDHI1 */ { + .phys_start = 0xee120000, + .virt_start = 0xee120000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* PWM */ { + .phys_start = 0xe6e30000, + .virt_start = 0xe6e30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* R-GP2D */ { + .phys_start = 0xe6ec0000, + .virt_start = 0xe6ec0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Thermal Sensor */ { + .phys_start = 0xe61f0000, + .virt_start = 0xe61f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CPG */ { + .phys_start = 0xe6150000, + .virt_start = 0xe6150000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* APMU Cortex-A7 */ { + .phys_start = 0xe6151000, + .virt_start = 0xe6151000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* APMU Cortex-A15 */ { + .phys_start = 0xe6152000, + .virt_start = 0xe6152000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* APMU Cortex-A7 and Cortex-A15 */ { + .phys_start = 0xe6154000, + .virt_start = 0xe6154000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* RES */ { + .phys_start = 0xe6160000, + .virt_start = 0xe6160000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* IRQC */ { + .phys_start = 0xe61c0000, + .virt_start = 0xe61c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT0 */ { + .phys_start = 0xffca0000, + .virt_start = 0xffca0000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT1 */ { + .phys_start = 0xe6130000, + .virt_start = 0xe6130000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* TMU0 */ { + .phys_start = 0xe61e0000, + .virt_start = 0xe61e0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SCIFA1 */ { + .phys_start = 0xe6c50000, + .virt_start = 0xe6c50000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* EtherAVB */ { + .phys_start = 0xe6800000, + .virt_start = 0xe6800000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMCIF: eMMC */ { + .phys_start = 0xee220000, + .virt_start = 0xee220000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB0 */ { + .phys_start = 0xee080000, + .virt_start = 0xee080000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DU */ { + .phys_start = 0xfeb00000, + .virt_start = 0xfeb00000, + .size = 0x00040000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* LVDS */ { + .phys_start = 0xfeb90000, + .virt_start = 0xfeb90000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN0 */ { + .phys_start = 0xe6e80000, + .virt_start = 0xe6e80000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN1 */ { + .phys_start = 0xe6e88000, + .virt_start = 0xe6e88000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C0 */ { + .phys_start = 0xe6508000, + .virt_start = 0xe6508000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C1 */ { + .phys_start = 0xe6518000, + .virt_start = 0xe6518000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C3 */ { + .phys_start = 0xe6540000, + .virt_start = 0xe6540000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IIC0 */ { + .phys_start = 0xe6500000, + .virt_start = 0xe6500000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IIC1 */ { + .phys_start = 0xe6510000, + .virt_start = 0xe6510000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IIC2 */ { + .phys_start = 0xe6520000, + .virt_start = 0xe6520000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IIC3 */ { + .phys_start = 0xe60b0000, + .virt_start = 0xe60b0000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD0 */ { + .phys_start = 0xfe920000, + .virt_start = 0xfe920000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD1 */ { + .phys_start = 0xfe928000, + .virt_start = 0xfe928000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD2 */ { + .phys_start = 0xfe930000, + .virt_start = 0xfe930000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD3 */ { + .phys_start = 0xfe938000, + .virt_start = 0xfe938000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3bf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/emtrion-rzg1m-inmate-demo.c b/configs/arm/emtrion-rzg1m-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..b406b8bd8385862b3e91814d48adb5a39e9c0ac4 --- /dev/null +++ b/configs/arm/emtrion-rzg1m-inmate-demo.c @@ -0,0 +1,70 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on emCON-RZ/G1M: + * 1 CPU, 64K RAM, serial ports SCIF4, CCU + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1m-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0xe6ee0000, + .clock_reg = 0xe615014c, + .gate_nr = 15, + .divider = 0x10, + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* SCIF4 */ { + .phys_start = 0xe6ee0000, + .virt_start = 0xe6ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bff0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm/emtrion-rzg1m-linux-demo.c b/configs/arm/emtrion-rzg1m-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..75f34e72482df8d0a00d59e366b6509c881f8018 --- /dev/null +++ b/configs/arm/emtrion-rzg1m-linux-demo.c @@ -0,0 +1,178 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on emCON-RZ/G1M: + * 1 CPU, 64M RAM, I2C bus I2C2, serial port SCIF4, SDHI0 + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "emtrion-emconrzg1m-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 123, */ + + .console = { + .address = 0xe6ee0000, + .clock_reg = 0xe615014c, + .gate_nr = 15, + .divider = 0x10, + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 1), + /* RST, MODEMR */ { + .phys_start = 0xe6160060, + .virt_start = 0xe6160060, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* RST, CA15RESCNT */ { + .phys_start = 0xe6160040, + .virt_start = 0xe6160040, + .size = 0x4, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* IRQC */ { + .phys_start = 0xe61c0000, + .virt_start = 0xe61c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Generic Counter */ { + .phys_start = 0xe6080000, + .virt_start = 0xe6080000, + .size = 0x40, + .flags = JAILHOUSE_MEM_READ | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* PFC (HACK) */ { + .phys_start = 0xe6060000, + .virt_start = 0xe6060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SYSC (HACK) */ { + .phys_start = 0xe6180000, + .virt_start = 0xe6180000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* SCIF4 */ { + .phys_start = 0xe6ee0000, + .virt_start = 0xe6ee0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32 | + JAILHOUSE_MEM_IO_16 | JAILHOUSE_MEM_IO_8, + }, + /* SDHI0: SDC */ { + .phys_start = 0xee100000, + .virt_start = 0xee100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0xbef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 32, + .pin_bitmap = { + 1 << (24+32 - 32), /* SCIF4 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0, 1 << (165+32 - 192) /* SDHI0 */ + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 1 << (286+32 - 288), /* I2C2 */ + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/emtrion-rzg1m.c b/configs/arm/emtrion-rzg1m.c new file mode 100644 index 0000000000000000000000000000000000000000..4ee1a40c8b208264098a9bc2d183ef985c819acf --- /dev/null +++ b/configs/arm/emtrion-rzg1m.c @@ -0,0 +1,273 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for emtrion's emCON-RZ/G1M board + * (RZ/G1M dual-core Cortex-A15, 1G RAM) + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Jan von Wiarda + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[27]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7c000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0xe62c0000, + .size = 0x1000, + .clock_reg = 0xe615014c, + .gate_nr = 17, + /* .divider = 0x2e, */ + .type = JAILHOUSE_CON_TYPE_HSCIF, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4 | + JAILHOUSE_CON_INVERTED_GATE, + }, + .platform_info = { + /* .pci_mmconfig_base = 0x2000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, */ + .arm = { + .gic_version = 2, + .gicd_base = 0xf1001000, + .gicc_base = 0xf1002000, + .gich_base = 0xf1004000, + .gicv_base = 0xf1006000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "emCON-RZ/G1M", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 108, */ + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 0), + /* Thermal Sensor */ { + .phys_start = 0xe61f0000, + .virt_start = 0xe61f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CPG */ { + .phys_start = 0xe6150000, + .virt_start = 0xe6150000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* APMU */ { + .phys_start = 0xe6151000, + .virt_start = 0xe6151000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* IRQC */ { + .phys_start = 0xe61c0000, + .virt_start = 0xe61c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT0 */ { + .phys_start = 0xffca0000, + .virt_start = 0xffca0000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* CMT1 */ { + .phys_start = 0xe6130000, + .virt_start = 0xe6130000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* TMU0 */ { + .phys_start = 0xe61e0000, + .virt_start = 0xe61e0000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* HSCIF0 */ { + .phys_start = 0xe62c0000, + .virt_start = 0xe62c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* EtherAVB */ { + .phys_start = 0xe6800000, + .virt_start = 0xe6800000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMCIF: eMMC */ { + .phys_start = 0xee200000, + .virt_start = 0xee200000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB0 */ { + .phys_start = 0xee080000, + .virt_start = 0xee080000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPDU */ { + .phys_start = 0xfe930000, + .virt_start = 0xfe930000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DU */ { + .phys_start = 0xfeb00000, + .virt_start = 0xfeb00000, + .size = 0x00040000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* LVDS */ { + .phys_start = 0xfeb90000, + .virt_start = 0xfeb90000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN0 */ { + .phys_start = 0xe6e80000, + .virt_start = 0xe6e80000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CAN1 */ { + .phys_start = 0xe6e88000, + .virt_start = 0xe6e88000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C0 */ { + .phys_start = 0xe6518000, + .virt_start = 0xe6518000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C1 */ { + .phys_start = 0xe6520000, + .virt_start = 0xe6520000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C2 */ { + .phys_start = 0xe6528000, + .virt_start = 0xe6528000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C3 */ { + .phys_start = 0xe6530000, + .virt_start = 0xe6530000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD0 */ { + .phys_start = 0xfe930000, + .virt_start = 0xfe930000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* VSPD1 */ { + .phys_start = 0xfe938000, + .virt_start = 0xfe938000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3bf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf1001000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xf1001000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/jetson-tk1-inmate-demo.c b/configs/arm/jetson-tk1-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..a4dd0a34e4f6317b4cc7cd54f00c947c0e460273 --- /dev/null +++ b/configs/arm/jetson-tk1-inmate-demo.c @@ -0,0 +1,76 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Nvidia Jetson TK1: + * 1 CPU, 64K RAM, serial port 0 + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "jetson-tk1-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .cpu_reset_address = CONFIG_INMATE_BASE, + + .console = { + .address = 0x70006300, + /* .clock_reg = 0x60006000 + 0x330, */ + /* .gate_nr = (65 % 32), */ + /* .divider = 0xdd, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xfbef0000, + .virt_start = CONFIG_INMATE_BASE, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, +}; diff --git a/configs/arm/jetson-tk1-linux-demo.c b/configs/arm/jetson-tk1-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..52e11c1e22b869717448abc7cc6de9233a3e9274 --- /dev/null +++ b/configs/arm/jetson-tk1-linux-demo.c @@ -0,0 +1,118 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Jetson TK1: + * 2 CPUs, 239M RAM, serial port D + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "jetson-tk1-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 152, + + .console = { + .address = 0x70006300, + /* .clock_reg = 0x60006000 + 0x330, */ + /* .gate_nr = (65 % 32), */ + /* .divider = 0xdd, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfbf00000, 1), + /* UART */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xfbef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0xe8000000, + /* cannot go higher than this, must be 128M-aligned */ + .virt_start = 0xe8000000, + .size = 0xeef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x50041000, + .pin_base = 32, + .pin_bitmap = { + 0, 0, 1 << (90+32 - 96) + }, + }, + /* GIC */ { + .address = 0x50041000, + .pin_base = 160, + .pin_bitmap = { + 1 << (153+32 - 160), + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/jetson-tk1.c b/configs/arm/jetson-tk1.c new file mode 100644 index 0000000000000000000000000000000000000000..f815218d54057af5f38cafc8ee02811aa7a4b552 --- /dev/null +++ b/configs/arm/jetson-tk1.c @@ -0,0 +1,262 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for Jetson TK1 board + * (NVIDIA Tegra K1 quad-core Cortex-A15, 2G RAM) + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=1920M vmalloc=512M" to the kernel command line. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[25]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfc000000, + .size = 0x4000000 - 0x100000, /* -1MB (PSCI) */ + }, + .debug_console = { + .address = 0x70006300, + .size = 0x40, + /* .clock_reg = 0x60006000 + 0x330, */ + /* .gate_nr = (65 % 32), */ + /* .divider = 0xdd, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x48000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + .arm = { + .gic_version = 2, + .gicd_base = 0x50041000, + .gicc_base = 0x50042000, + .gich_base = 0x50044000, + .gicv_base = 0x50046000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Jetson-TK1", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 148, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfbf00000, 0), + /* PCIe */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x3f000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /*50000000-50033fff : /host1x@0,50000000*/ { + .phys_start = 0x50000000, + .virt_start = 0x50000000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /*54200000-5423ffff : /host1x@0,50000000/dc@0,54200000*/ { + .phys_start = 0x54200000, + .virt_start = 0x54200000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /*54240000-5427ffff : /host1x@0,50000000/dc@0,54240000*/ { + .phys_start = 0x54240000, + .virt_start = 0x54240000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /*54280000-542bffff : /host1x@0,50000000/hdmi@0,54280000 */ { + .phys_start = 0x54280000, + .virt_start = 0x54280000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HACK: GPU */ { + .phys_start = 0x57000000, + .virt_start = 0x57000000, + .size = 0x02000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* + * HACK: 0x1400@0x60002000: APBDMA + * HACK: 0x0500@0x60004000: Legacy Interrupt Controller, + * HACK: 0x0400@0x60005000: Nvidia Timers (TMR + WDT), + * HACK: 0x1000@0x60006000: Clock and Reset Controller + */ { + .phys_start = 0x60002000, + .virt_start = 0x60002000, + .size = 0x5000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPIO */ { + .phys_start = 0x6000d000, + .virt_start = 0x6000d000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HACK: apbmisc "Chip Revision" */ { + .phys_start = 0x70000800, + .virt_start = 0x70000800, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C, including HDMI_DDC*/ { + .phys_start = 0x7000c000, + .virt_start = 0x7000c000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C5/6, SPI */ { + .phys_start = 0x7000d000, + .virt_start = 0x7000d000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RTC + PMC + apbmisc "Strapping Options" */ { + .phys_start = 0x7000e000, + .virt_start = 0x7000e000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HACK: Memory Controller */ { + .phys_start = 0x70019000, + .virt_start = 0x70019000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* XUSB_HOST */ { + .phys_start = 0x70090000, + .virt_start = 0x70090000, + .size = 0xa000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* XUSB_PADCTL */ { + .phys_start = 0x7009f000, + .virt_start = 0x7009f000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMC0/1 */ { + .phys_start = 0x700b0000, + .virt_start = 0x700b0000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* XUSB_DEV */ { + .phys_start = 0x700d0000, + .virt_start = 0x700d0000, + .size = 0xa000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HACK: CPU_DFLL clock */ { + .phys_start = 0x70110000, + .virt_start = 0x70110000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x7d004000, + .virt_start = 0x7d004000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x7c000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x50041000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x50041000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/orangepi0-inmate-demo.c b/configs/arm/orangepi0-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..bcbf48231b4652378b7a0cfa999541fbf64b4566 --- /dev/null +++ b/configs/arm/orangepi0-inmate-demo.c @@ -0,0 +1,138 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Orange Pi Zero: + * 1 CPU, 64K RAM, serial ports 0-3, GPIO PA + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[9]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "orangepi0-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 125, + + .console = { + .address = 0x01c28000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x4f6f0000, + .virt_start = 0x4f6f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6f1000, + .virt_start = 0x4f6f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fa000, + .virt_start = 0x4f6fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fc000, + .virt_start = 0x4f6fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fe000, + .virt_start = 0x4f6fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* GPIO: port A */ { + .phys_start = 0x01c20800, + .virt_start = 0x01c20800, + .size = 0x24, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART 0-3 */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x4f600000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + 1 << (157-128), + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm/orangepi0-linux-demo.c b/configs/arm/orangepi0-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..af0dd1a65efd7c2c707e8efc399607c24a3efff6 --- /dev/null +++ b/configs/arm/orangepi0-linux-demo.c @@ -0,0 +1,151 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Orange Pi Zero: + * 1 CPU, 64M RAM, serial port 0 + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "orangepi0-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 123, + + .console = { + .address = 0x01c28000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x4f6f0000, + .virt_start = 0x4f6f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6f1000, + .virt_start = 0x4f6f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fa000, + .virt_start = 0x4f6fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fc000, + .virt_start = 0x4f6fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x4f6fe000, + .virt_start = 0x4f6fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x4f700000, 1), + /* UART 0-3 */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x4f610000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x48000000, + .virt_start = 0x48000000, + .size = 0x7600000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 1 << (32-32), + 0, + 0, + (1 << (155-128)) | (1 << (156-128)), + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/orangepi0.c b/configs/arm/orangepi0.c new file mode 100644 index 0000000000000000000000000000000000000000..c24344e01607954dbf2bc34be01b0e0c9b2c65ea --- /dev/null +++ b/configs/arm/orangepi0.c @@ -0,0 +1,198 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for Orange Pi Zero (H2+ quad-core Cortex-A7, 256MB RAM) + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[18]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x4f800000, + .size = 0x800000 - 0x100000, /* -1MB (PSCI) */ + }, + .debug_console = { + .address = 0x01c28000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x2000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0x01c81000, + .gicc_base = 0x01c82000, + .gich_base = 0x01c84000, + .gicv_base = 0x01c86000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Orange-Pi0", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 108, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x4f6f0000, + .virt_start = 0x4f6f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x4f6f1000, + .virt_start = 0x4f6f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x4f6fa000, + .virt_start = 0x4f6fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x4f6fc000, + .virt_start = 0x4f6fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x4f6fe000, + .virt_start = 0x4f6fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x4f700000, 0), + /* MMIO 1 (permissive) */ { + .phys_start = 0x01c00000, + .virt_start = 0x01c00000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clock (permissive) */ { + .phys_start = 0x01c20000, + .virt_start = 0x01c20000, + .size = 0x800, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* pinctrl PA */ { + .phys_start = 0x01c20800, + .virt_start = 0x01c20800, + .size = 0x24, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* pinctrl rest */ { + .phys_start = 0x01c20824, + .virt_start = 0x01c20824, + .size = 0x3dc, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* watchdog */ { + .phys_start = 0x01c20ca0, + .virt_start = 0x01c20ca0, + .size = 0x20, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* MMIO 2 (permissive) */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RTC */ { + .phys_start = 0x01f00000, + .virt_start = 0x01f00000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* MMIO 3 (permissive) */ { + .phys_start = 0x01f01000, + .virt_start = 0x01f01000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0xf620000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/qemu-arm-inmate-demo.c b/configs/arm/qemu-arm-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..3f835d9eb8132c0f8025de63072a5683a1e77373 --- /dev/null +++ b/configs/arm/qemu-arm-inmate-demo.c @@ -0,0 +1,132 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on QEMU arm6virtual target + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2017-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 144-32, + + .console = { + .address = 0x09000000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b0010, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7fa00000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + (1 << (144 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm/qemu-arm-linux-demo.c b/configs/arm/qemu-arm-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..e0124baabcdd3f69d6598f8f451cb169bc6adb47 --- /dev/null +++ b/configs/arm/qemu-arm-linux-demo.c @@ -0,0 +1,152 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on QEMU arm: + * 2 CPUs, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "qemu-arm-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + + .console = { + .address = 0x09000000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b1100, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 1), + /* UART */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7f900000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 1 << (33 - 32), + 0, + 0, + (1 << (140 - 128)) | (1 << (141 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm/qemu-arm.c b/configs/arm/qemu-arm.c new file mode 100644 index 0000000000000000000000000000000000000000..4a3eac7bb85f4726a0f2fb83afe0ab4083b5d365 --- /dev/null +++ b/configs/arm/qemu-arm.c @@ -0,0 +1,154 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for QEMU arm virtual target, 1G RAM, 8 cores + * + * Copyright (c) Siemens AG, 2017-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=768M" to the kernel command line. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[11]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7fc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x09000000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x08e00000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0x08000000, + .gicc_base = 0x08010000, + .gich_base = 0x08030000, + .gicv_base = 0x08040000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "qemu-arm", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 128-32, + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x37000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3fa10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0001:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0001:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/amd-seattle-inmate-demo.c b/configs/arm64/amd-seattle-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..d920804c766937cad27f71f792d3cb14bc9307ae --- /dev/null +++ b/configs/arm64/amd-seattle-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on AMD Seattle: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0xe1010000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x10, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0xe1010000, + .virt_start = 0xe1010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x83b0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/amd-seattle-linux-demo.c b/configs/arm64/amd-seattle-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..f4ed12d7e779852c7fb4f46f71b8c62e006b3553 --- /dev/null +++ b/configs/arm64/amd-seattle-linux-demo.c @@ -0,0 +1,147 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on AMD Seattle: + * 2 CPUs, 512MB RAM, 1 serial port + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[12]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .console = { + .address = 0xe1010000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc0, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x83e4000000, 1), + /* UART */ { + .phys_start = 0xe1010000, + .virt_start = 0xe1010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* xgmac */ { + .phys_start = 0xe0900000, + .virt_start = 0xe0900000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* phy */ { + .phys_start = 0xe1240000, + .virt_start = 0xe1240000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* phy */ { + .phys_start = 0xe1250000, + .virt_start = 0xe1250000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x83dfff0000, + .virt_start = 0x0, + .size = 0x10000, /* 64 KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x83c0000000, + .virt_start = 0x83c0000000, + .size = 0x1fff0000, /* 512 MB - 64 KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* v2m */ { + .phys_start = 0xe1180000, + .virt_start = 0xe1180000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_IO | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xe1110000, + .pin_base = 32, + .pin_bitmap = { + 0, 0, + (1 << (100 - 96)) /* MSI */ + }, + }, + /* GIC */ { + .address = 0xe1110000, + .pin_base = 352, + .pin_bitmap = { + (1 << (354 - 352)) | /* xgmac1 */ + (1 << (356 - 352)) | /* xgmac1 */ + (1 << (360 - 352)) | /* uart */ + (1 << (373 - 352)) | /* xgmac1 */ + (1 << (374 - 352)) | /* xgmac1 */ + (1 << (375 - 352)) | /* xgmac1 */ + (1 << (376 - 352)) /* xgmac1 */ + }, + }, + }, + + .pci_devices = { + /* 00:0f.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0x0078, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/amd-seattle.c b/configs/arm64/amd-seattle.c new file mode 100644 index 0000000000000000000000000000000000000000..6409d93403e51743842253144145ae6ee26c0847 --- /dev/null +++ b/configs/arm64/amd-seattle.c @@ -0,0 +1,225 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for AMD Seattle + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[20]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[3]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x83e0000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0xe1010000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xf0000000, + .pci_mmconfig_end_bus = 255, + .arm = { + .gic_version = 2, + .gicd_base = 0xe1110000, + .gicc_base = 0xe112f000, + .gich_base = 0xe1140000, + .gicv_base = 0xe116f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "amd-seattle", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x83e4000000, 0), + /* gpio */ { + .phys_start = 0xe0030000, + .virt_start = 0xe0030000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio */ { + .phys_start = 0xe0080000, + .virt_start = 0xe0080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio */ { + .phys_start = 0xe1050000, + .virt_start = 0xe1050000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata */ { + .phys_start = 0xe0300000, + .virt_start = 0xe0300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* xgmac */ { + .phys_start = 0xe0700000, + .virt_start = 0xe0700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* xgmac */ { + .phys_start = 0xe0900000, + .virt_start = 0xe0900000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* smmu */ { + .phys_start = 0xe0600000, + .virt_start = 0xe0600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* smmu */ { + .phys_start = 0xe0800000, + .virt_start = 0xe0800000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serial */ { + .phys_start = 0xe1010000, + .virt_start = 0xe1010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ssp */ { + .phys_start = 0xe1020000, + .virt_start = 0xe1020000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ssp */ { + .phys_start = 0xe1030000, + .virt_start = 0xe1030000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* phy */ { + .phys_start = 0xe1240000, + .virt_start = 0xe1240000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* phy */ { + .phys_start = 0xe1250000, + .virt_start = 0xe1250000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ccn */ { + .phys_start = 0xe8000000, + .virt_start = 0xe8000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x8000000000, + .virt_start = 0x8000000000, + .size = 0x3e0000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM */ { + .phys_start = 0x83f0000000, + .virt_start = 0x83f0000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + .irqchips = { + /* GIC */ { + .address = 0xe1110000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0xe1110000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0xe1110000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + .pci_devices = { + /* 00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .bdf = 0x0000, + }, + /* 00:02.0 */ { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .bdf = 0x0010, + }, + /* 00:0f.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0x0078, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/dts/inmate-amd-seattle.dts b/configs/arm64/dts/inmate-amd-seattle.dts new file mode 100644 index 0000000000000000000000000000000000000000..89b7d50b607651215662fcc97005838d160e1d55 --- /dev/null +++ b/configs/arm64/dts/inmate-amd-seattle.dts @@ -0,0 +1,190 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on AMD Seattle, + * corresponds to configs/arm64/amd-seattle-linux-demo.c + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on AMD Seattle"; + compatible = "amd,seattle-overdrive", "amd,seattle"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon"; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@300 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + cpu@301 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x301>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + }; + }; + + aliases { + serial0 = &serial0; + }; + + gic: interrupt-controller@e1110000 { + compatible = "arm,gic-400", "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + interrupt-controller; + reg = <0x0 0xe1110000 0 0x1000>, + <0x0 0xe112f000 0 0x2000>; + ranges = <0 0 0 0xe1100000 0 0x100000>; + v2m0: v2m@e0080000 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0x0 0x00080000 0 0x1000>; + arm,msi-base-spi = <100>; + arm,msi-num-spis = <1>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 0xff04>, + <1 14 0xff04>, + <1 11 0xff04>; + }; + + uartspiclk_100mhz: clk100mhz_1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "uartspiclk_100mhz"; + }; + + serial0: uart@e1010000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xe1010000 0x0 0x1000>; + interrupts = <0 328 4>; + clocks = <&uartspiclk_100mhz>, <&uartspiclk_100mhz>; + clock-names = "uartclk", "apb_pclk"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + smb0: smb { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + xgmacclk1_dma_250mhz: clk250mhz_2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; + clock-output-names = "xgmacclk1_dma_250mhz"; + }; + + xgmacclk1_ptp_250mhz: clk250mhz_3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; + clock-output-names = "xgmacclk1_ptp_250mhz"; + }; + + xgmac1_phy: phy@e1240c00 { + compatible = "amd,xgbe-phy-seattle-v1a"; + reg = <0 0xe1240c00 0 0x00400>, /* SERDES RX/TX1 */ + <0 0xe1250080 0 0x00060>, /* SERDES IR 1/2 */ + <0 0xe12500fc 0 0x00004>; /* SERDES IR 2/2 */ + interrupts = <0 322 4>; + amd,speed-set = <0>; + amd,serdes-blwc = <1>, <1>, <0>; + amd,serdes-cdr-rate = <2>, <2>, <7>; + amd,serdes-pq-skew = <10>, <10>, <18>; + amd,serdes-tx-amp = <15>, <15>, <10>; + amd,serdes-dfe-tap-config = <3>, <3>, <1>; + amd,serdes-dfe-tap-enable = <0>, <0>, <127>; + }; + + xgmac1: xgmac@e0900000 { + compatible = "amd,xgbe-seattle-v1a"; + reg = <0 0xe0900000 0 0x80000>, + <0 0xe0980000 0 0x80000>; + interrupts = <0 324 4>, + <0 341 1>, <0 342 1>, <0 343 1>, <0 344 1>; + amd,per-channel-interrupt; + mac-address = [ 02 B1 B2 B3 B4 B5 ]; + clocks = <&xgmacclk1_dma_250mhz>, <&xgmacclk1_ptp_250mhz>; + clock-names = "dma_clk", "ptp_clk"; + phy-handle = <&xgmac1_phy>; + phy-mode = "xgmii"; + #stream-id-cells = <24>; + dma-coherent; + }; + + pcie0: pcie@f0000000 { + compatible = "pci-host-ecam-generic"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + bus-range = <0 0x7f>; + msi-parent = <&v2m0>; + reg = <0 0xf0000000 0 0x10000000>; + + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = + <0x1000 0x0 0x0 0x1 &gic 0x0 0x0 0x0 0x120 IRQ_TYPE_EDGE_RISING>, + <0x1000 0x0 0x0 0x2 &gic 0x0 0x0 0x0 0x121 IRQ_TYPE_EDGE_RISING>, + <0x1000 0x0 0x0 0x3 &gic 0x0 0x0 0x0 0x122 IRQ_TYPE_EDGE_RISING>, + <0x1000 0x0 0x0 0x4 &gic 0x0 0x0 0x0 0x123 IRQ_TYPE_EDGE_RISING>; + + dma-coherent; + dma-ranges = <0x43000000 0x0 0x0 0x0 0x0 0x100 0x0>; + ranges = + /* I/O Memory (size=64K) */ + <0x01000000 0x00 0x00000000 0x00 0xefff0000 0x00 0x00010000>, + /* 32-bit MMIO (size=2G) */ + <0x02000000 0x00 0x40000000 0x00 0x40000000 0x00 0x80000000>, + /* 64-bit MMIO (size= 124G) */ + <0x03000000 0x01 0x00000000 0x01 0x00000000 0x7f 0x00000000>; + }; + }; +}; diff --git a/configs/arm64/dts/inmate-espressobin.dts b/configs/arm64/dts/inmate-espressobin.dts new file mode 100644 index 0000000000000000000000000000000000000000..40e59414c0a97364be7befc9db4267dab57dbf85 --- /dev/null +++ b/configs/arm64/dts/inmate-espressobin.dts @@ -0,0 +1,90 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on ESPRESSObin, + * corresponds to configs/arm64/espressobin-linux-demo.c + * + * Copyright (c) Siemens AG, 2016-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on ESPRESSObin"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@1 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@d1d00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0xd1d00000 0x0 0x10000>, /* GICD */ + <0x0 0xd1d60000 0x0 0x20000>; /* GICR */ + }; + + uart0: serial@d0012000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x0 0xd0012000 0x0 0x200>; + interrupts = , + , + ; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + pci@fc000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 109 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 111 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfc000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-foundation-v8.dts b/configs/arm64/dts/inmate-foundation-v8.dts new file mode 100644 index 0000000000000000000000000000000000000000..184cdb980d4acae69e2870275794d5c0a5401c99 --- /dev/null +++ b/configs/arm64/dts/inmate-foundation-v8.dts @@ -0,0 +1,110 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on ARM Foundation Model for ARMv8, + * corresponds to configs/arm64/foundation-v8-linux-demo.c + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Dmitry Voytik + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * ARMv8 Foundation model DTS + * + */ + +/dts-v1/; + +/* 64 KiB */ +/memreserve/ 0x0 0x00010000; + +/ { + model = "Jailhouse-Foundation-v8A"; + compatible = "arm,foundation-aarch64", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon"; + }; + + aliases { + serial0 = &serial0; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x10000000>; /* 256 MiB starts at 0x0 */ + }; + + gic: interrupt-controller@2c001000 { + compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x0 0x2c001000 0 0x1000>, + <0x0 0x2c002000 0 0x1000>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>; + clock-frequency = <100000000>; + }; + + v2m_clk24mhz: clk24mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "v2m:clk24mhz"; + }; + + serial0: uart@1c090000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0x1c090000 0x0 0x1000>; + interrupts = <0 8 1>; + clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; + clock-names = "uartclk", "apb_pclk"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; +}; diff --git a/configs/arm64/dts/inmate-hikey.dts b/configs/arm64/dts/inmate-hikey.dts new file mode 100644 index 0000000000000000000000000000000000000000..828d494b928f23d6426d3f19c8dc5c4e9517abc2 --- /dev/null +++ b/configs/arm64/dts/inmate-hikey.dts @@ -0,0 +1,112 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Banana Pi board, + * corresponds to configs/arm/bananapi-linux-demo.c + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on HiKey"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@102 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x102>; + enable-method = "psci"; + next-level-cache = <&CLUSTER1_L2>; + }; + + cpu@103 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x103>; + enable-method = "psci"; + next-level-cache = <&CLUSTER1_L2>; + }; + + CLUSTER1_L2: l2-cache1 { + compatible = "cache"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f6801000 { + compatible = "arm,gic-400"; + reg = <0x0 0xf6801000 0x0 0x1000>, + <0x0 0xf6802000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uartclk: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <19200000>; + }; + + uart: serial@f7113000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xf7113000 0x0 0x1000>; + interrupts = ; + clocks = <&uartclk>, <&uartclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pci@f6000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 111 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 112 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 113 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 114 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xf6000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-imx8mm-evk.dts b/configs/arm64/dts/inmate-imx8mm-evk.dts new file mode 100644 index 0000000000000000000000000000000000000000..591c354372b67700b51b43908b14c397d36ac61f --- /dev/null +++ b/configs/arm64/dts/inmate-imx8mm-evk.dts @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include + +/ { + model = "Freescale i.MX8MM EVK"; + compatible = "fsl,imx8mm-evk", "fsl,imx8mm"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial3 = &uart4; + mmc2 = &usdhc3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + interrupt-affinity = <&A53_2>, <&A53_3>; + }; + + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */ + <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */ + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + clock-frequency = <8333333>; + }; + + clk_dummy: clock@7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dummy"; + }; + + /* The clocks are configured by 1st OS */ + clk_200m: clock@8 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "200m"; + }; + clk_266m: clock@9 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <266000000>; + clock-output-names = "266m"; + }; + clk_80m: clock@10 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <80000000>; + clock-output-names = "80m"; + }; + + osc_24m: clock-osc-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; + }; + + pci@bb800000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 74 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 75 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 76 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 77 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xbb800000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x3e000000>; + + aips3: bus@30800000 { + compatible = "fsl,aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x30800000 0x30800000 0x400000>, + <0x8000000 0x8000000 0x10000000>; + + uart4: serial@30a60000 { + compatible = "fsl,imx8mm-uart", "fsl,imx6q-uart"; + reg = <0x30a60000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + usdhc3: mmc@30b60000 { + compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc"; + reg = <0x30b60000 0x10000>; + interrupts = ; + clock-names = "ipg", "ahb", "per"; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + status = "disabled"; + }; + }; + }; +}; + +&uart4 { + clocks = <&osc_24m>, + <&osc_24m>; + clock-names = "ipg", "per"; + /delete-property/ dmas; + /delete-property/ dmas-names; + status = "okay"; +}; + +&usdhc3 { + clocks = <&clk_dummy>, + <&clk_266m>, + <&clk_200m>; + /delete-property/assigned-clocks; + /delete-property/assigned-clock-rates; + clock-names = "ipg", "ahb", "per"; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/configs/arm64/dts/inmate-imx8mn-ddr4-evk.dts b/configs/arm64/dts/inmate-imx8mn-ddr4-evk.dts new file mode 100644 index 0000000000000000000000000000000000000000..e5a87d0341ada8c63eabb32941618407e6a2b6b4 --- /dev/null +++ b/configs/arm64/dts/inmate-imx8mn-ddr4-evk.dts @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include + +/ { + model = "Freescale i.MX8MN EVK"; + compatible = "fsl,imx8mn-evk", "fsl,imx8mm"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial3 = &uart4; + mmc2 = &usdhc3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clock-latency = <61036>; + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clock-latency = <61036>; + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupt-parent = <&gic>; + interrupts = ; + interrupt-affinity = <&A53_2>, <&A53_3>; + }; + + osc_24m: clock-osc-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; + }; + + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */ + <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */ + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + clock-frequency = <8333333>; + }; + + clk_dummy: clock@7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dummy"; + }; + + /* The clocks are configured by 1st OS */ + clk_200m: clock@8 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "200m"; + }; + clk_266m: clock@9 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <266000000>; + clock-output-names = "266m"; + }; + clk_80m: clock@10 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <80000000>; + clock-output-names = "80m"; + }; + + pci@bb800000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 76 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xbb800000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x3e000000>; + dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>; + + aips3: bus@30800000 { + compatible = "fsl,imx8mq-aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x30800000 0x30800000 0x400000>, + <0x08000000 0x08000000 0x10000000>; + + uart4: serial@30a60000 { + compatible = "fsl,imx8mn-uart", "fsl,imx6q-uart"; + reg = <0x30a60000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + usdhc3: mmc@30b60000 { + compatible = "fsl,imx8mn-usdhc", "fsl,imx8mm-usdhc"; + reg = <0x30b60000 0x10000>; + interrupts = ; + clock-names = "ipg", "ahb", "per"; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + bus-width = <4>; + status = "disabled"; + }; + }; + }; +}; + +&uart4 { + clocks = <&osc_24m>, + <&osc_24m>; + clock-names = "ipg", "per"; + /delete-property/ dmas; + /delete-property/ dmas-names; + status = "okay"; +}; + +&usdhc3 { + clocks = <&clk_dummy>, + <&clk_266m>, + <&clk_200m>; + /delete-property/assigned-clocks; + /delete-property/assigned-clock-rates; + clock-names = "ipg", "ahb", "per"; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/configs/arm64/dts/inmate-imx8mp-evk.dts b/configs/arm64/dts/inmate-imx8mp-evk.dts new file mode 100644 index 0000000000000000000000000000000000000000..b4068771a14d5e4d150d64f98e8317cbc79ee189 --- /dev/null +++ b/configs/arm64/dts/inmate-imx8mp-evk.dts @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include + +/ { + model = "Freescale i.MX8MP EVK"; + compatible = "fsl,imx8mp-evk", "fsl,imx8mp"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial3 = &uart4; + mmc2 = &usdhc3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupt-parent = <&gic>; + interrupts = ; + interrupt-affinity = <&A53_2>, <&A53_3>; + }; + + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */ + <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */ + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + clock-frequency = <8333333>; + }; + + clk_dummy: clock@7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dummy"; + }; + + /* The clocks are configured by 1st OS */ + clk_400m: clock@8 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "200m"; + }; + + clk_266m: clock@9 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <266000000>; + clock-output-names = "266m"; + }; + + osc_24m: clock@1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "osc_24m"; + }; + + pci@fd700000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 154 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 155 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 156 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 157 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfd700000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x3e000000>; + + aips3: bus@30800000 { + compatible = "simple-bus"; + reg = <0x30800000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + uart4: serial@30a60000 { + compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart"; + reg = <0x30a60000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + usdhc3: mmc@30b60000 { + compatible = "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc"; + reg = <0x30b60000 0x10000>; + interrupts = ; + fsl,tuning-start-tap = <20>; + fsl,tuning-step= <2>; + status = "disabled"; + }; + }; + }; +}; + +&uart4 { + clocks = <&osc_24m>, + <&osc_24m>; + clock-names = "ipg", "per"; + status = "okay"; +}; + +&usdhc3 { + clocks = <&clk_dummy>, + <&clk_266m>, + <&clk_400m>; + clock-names = "ipg", "ahb", "per"; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/configs/arm64/dts/inmate-imx8mq-evk.dts b/configs/arm64/dts/inmate-imx8mq-evk.dts new file mode 100644 index 0000000000000000000000000000000000000000..45b42c947f02538cfb5335c267c62f249fbcb5c4 --- /dev/null +++ b/configs/arm64/dts/inmate-imx8mq-evk.dts @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2020 NXP + */ + +/dts-v1/; + +#include + +/ { + model = "Freescale i.MX8MQ EVK"; + compatible = "fsl,imx8mq-evk", "fsl,imx8mq"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial1 = &uart2; + mmc2 = &usdhc1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + A53_2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clock-latency = <61036>; /* two CLK32 periods */ + next-level-cache = <&A53_L2>; + enable-method = "psci"; + #cooling-cells = <2>; + }; + + A53_L2: l2-cache0 { + compatible = "cache"; + }; + }; + + pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = ; + interrupt-parent = <&gic>; + interrupt-affinity = <&A53_2>, <&A53_3>; + }; + + osc_25m: clock-osc-25m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "osc_25m"; + }; + + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x38800000 0 0x10000>, /* GIC Dist */ + <0x0 0x38880000 0 0xC0000>; /* GICR (RD_base + SGI_base) */ + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + clock-frequency = <8333333>; + }; + + clk_dummy: clock@7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dummy"; + }; + + /* The clocks are configured by 1st OS */ + clk_400m: clock@8 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + clock-output-names = "400m"; + }; + clk_266m: clock@9 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <266000000>; + clock-output-names = "266m"; + }; + clk_80m: clock@10 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <80000000>; + clock-output-names = "80m"; + }; + + pci@bfb00000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 51 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 52 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 53 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 54 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xbfb00000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x3e000000>; + dma-ranges = <0x40000000 0x0 0x40000000 0xc0000000>; + + aips3: bus@30800000 { + compatible = "fsl,imx8mq-aips-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x30800000 0x30800000 0x400000>, + <0x08000000 0x08000000 0x10000000>; + + uart2: serial@30890000 { + compatible = "fsl,imx8mq-uart", + "fsl,imx6q-uart"; + reg = <0x30890000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + usdhc1: mmc@30b40000 { + compatible = "fsl,imx8mq-usdhc", + "fsl,imx7d-usdhc"; + reg = <0x30b40000 0x10000>; + interrupts = ; + clock-names = "ipg", "ahb", "per"; + fsl,tuning-start-tap = <20>; + fsl,tuning-step = <2>; + status = "disabled"; + }; + }; + }; +}; + +&uart2 { + clocks = <&osc_25m>, + <&osc_25m>; + clock-names = "ipg", "per"; + /delete-property/ dmas; + /delete-property/ dmas-names; + status = "okay"; +}; + +&usdhc1 { + clocks = <&clk_dummy>, + <&clk_266m>, + <&clk_400m>; + /delete-property/assigned-clocks; + /delete-property/assigned-clock-rates; + clock-names = "ipg", "ahb", "per"; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/configs/arm64/dts/inmate-jetson-tx1.dts b/configs/arm64/dts/inmate-jetson-tx1.dts new file mode 100644 index 0000000000000000000000000000000000000000..739a48b9335aef12ed5dd24be0adbe7d7f73163a --- /dev/null +++ b/configs/arm64/dts/inmate-jetson-tx1.dts @@ -0,0 +1,103 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Jetson TX1 board, + * corresponds to configs/arm64/jetson-tx1-linux-demo.c + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on NVIDIA Jetson TX1"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x2>; + }; + + cpu@3 { + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x3>; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + gic: interrupt-controller@50041000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x50041000 0x1000>, + <0x50042000 0x1000>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + interrupt-parent = <&gic>; + }; + + serial@70006000 { + compatible = "nvidia,tegra210-uart", "nvidia,tegra20-uart"; + reg = <0x70006000 0x40>; + reg-shift = <2>; + interrupts = ; + clock-frequency = <408000000>; + status = "okay"; + }; + + pci@48000000 { + status = "okay"; + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 152 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 153 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 155 IRQ_TYPE_EDGE_RISING>; + reg = <0x48000000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-k3-am625-sk-emmc.dts b/configs/arm64/dts/inmate-k3-am625-sk-emmc.dts new file mode 100644 index 0000000000000000000000000000000000000000..2fb07d529f135446d07cf07e421479aa79ef3b1c --- /dev/null +++ b/configs/arm64/dts/inmate-k3-am625-sk-emmc.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +#include "inmate-k3-am625-sk.dts" + +/ { + sdhci0: mmc@fa10000 { + compatible = "ti,am62-sdhci"; + reg = <0x0 0xfa10000 0x0 0x260>, <0x0 0xfa18000 0x0 0x134>; + power-domains = <&k3_pds 57 1>; + clocks = <&k3_clks 57 5>, <&k3_clks 57 6>; + clock-names = "clk_ahb", "clk_xin"; + interrupts = ; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x9>; + ti,otap-del-sel-hs200 = <0x6>; + }; +}; + +&sdhci0 { + /* eMMC */ + non-removable; + ti,driver-strength-ohm = <50>; + bus-width = <8>; + disable-wp; +}; diff --git a/configs/arm64/dts/inmate-k3-am625-sk.dts b/configs/arm64/dts/inmate-k3-am625-sk.dts new file mode 100644 index 0000000000000000000000000000000000000000..c14550731b47017c38692f51150b0cf9ff81e7ec --- /dev/null +++ b/configs/arm64/dts/inmate-k3-am625-sk.dts @@ -0,0 +1,163 @@ +/dts-v1/; + +#include + +/ { + model = "Texas Instruments AM625 Inmate Model"; + compatible = "ti,am625-evm", "ti,am625"; + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial1 = &main_uart1; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + memory@e0000000 { + device_type = "memory"; + reg = <0x0 0xe0000000 0x0 0x1fff0000>; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a53"; + reg = <0x002>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a53"; + reg = <0x003>; + device_type = "cpu"; + enable-method = "psci"; + }; + + }; + + pmu: pmu { + compatible = "arm,armv8-pmuv3"; + /* Recommendation from GIC500 TRM Table A.3 */ + interrupts = ; + }; + + a53_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = , /* cntpsirq */ + , /* cntpnsirq */ + , /* cntvirq */ + ; /* cnthpirq */ + }; + + cbass_main: interconnect@f0000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ + <0x00 0x01880000 0x00 0xC0000>; /* GICR */ + interrupts = ; + }; + + main_uart1: serial@2810000 { + compatible = "ti,am64-uart", "ti,am654-uart"; + reg = <0x00 0x02810000 0x00 0x100>; + interrupts = ; + power-domains = <&k3_pds 152 1>; + current-speed = <115200>; + clock-frequency = <48000000>; + }; + + pci@76000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = + <0 0 0 1 &gic500 GIC_SPI 157 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic500 GIC_SPI 158 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic500 GIC_SPI 159 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic500 GIC_SPI 160 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x76000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x20000>; + }; + + dmss: bus@48000000 { + compatible = "simple-mfd"; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ranges = <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>; + + ti,sci-dev-id = <25>; + + secure_proxy_main: mailbox@4d000000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x4d000000 0x00 0x80000>, + <0x00 0x4a600000 0x00 0x80000>, + <0x00 0x4a400000 0x00 0x80000>; + interrupt-names = "rx_014"; + interrupts = ; + }; + }; + + dmsc: system-controller@44043000 { + compatible = "ti,k2g-sci"; + ti,host-id = <13>; + mbox-names = "rx", "tx"; + mboxes = <&secure_proxy_main 14>, + <&secure_proxy_main 15>; + reg-names = "debug_messages"; + reg = <0x00 0x44043000 0x00 0xfe0>; + + k3_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <2>; + }; + + k3_clks: clock-controller { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + }; +}; diff --git a/configs/arm64/dts/inmate-k3-am654-idk-emmc.dts b/configs/arm64/dts/inmate-k3-am654-idk-emmc.dts new file mode 100644 index 0000000000000000000000000000000000000000..150e31fed1c97830eb35891749c86cc19ab9ec3c --- /dev/null +++ b/configs/arm64/dts/inmate-k3-am654-idk-emmc.dts @@ -0,0 +1,45 @@ +/dts-v1/; + +#include "inmate-k3-am654-idk.dts" + +/ { + sdhci0: mmc@4f80000 { + compatible = "ti,am654-sdhci-5.1"; + reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>; + power-domains = <&k3_pds 47 1>; + clocks = <&k3_clks 47 0>, <&k3_clks 47 1>; + clock-names = "clk_ahb", "clk_xin"; + interrupts = ; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0x0>; + ti,otap-del-sel-sdr25 = <0x0>; + ti,otap-del-sel-sdr50 = <0x8>; + ti,otap-del-sel-sdr104 = <0x7>; + ti,otap-del-sel-ddr50 = <0x5>; + ti,otap-del-sel-ddr52 = <0x5>; + ti,otap-del-sel-hs200 = <0x5>; + ti,otap-del-sel-hs400 = <0x0>; + ti,trm-icp = <0x8>; + dma-coherent; + }; +}; + +&mcu_uart0 { + power-domains = <&k3_pds 149 1>; +}; + +&k3_pds { + #power-domain-cells = <2>; +}; + +&sdhci0 { + /* eMMC */ + non-removable; + ti,driver-strength-ohm = <50>; + bus-width = <8>; + disable-wp; +}; diff --git a/configs/arm64/dts/inmate-k3-am654-idk.dts b/configs/arm64/dts/inmate-k3-am654-idk.dts new file mode 100644 index 0000000000000000000000000000000000000000..e6d0b547cca6fe4f5648f839408e42169d89f168 --- /dev/null +++ b/configs/arm64/dts/inmate-k3-am654-idk.dts @@ -0,0 +1,164 @@ +/dts-v1/; + +#include + +/ { + model = "Texas Instruments AM654 Inmate Model"; + compatible = "ti,am654-evm", "ti,am654"; + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial1 = &mcu_uart0; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x8 0xe0000000 0x0 0x1fff0000>; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x100>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x101>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + pmu: pmu { + compatible = "arm,armv8-pmuv3"; + /* Recommendation from GIC500 TRM Table A.3 */ + interrupts = ; + }; + + a53_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = , /* cntpsirq */ + , /* cntpnsirq */ + , /* cntvirq */ + ; /* cnthpirq */ + }; + + cbass_main: interconnect@100000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ + <0x00 0x01880000 0x00 0x90000>; /* GICR */ + interrupts = ; + }; + + pci@76000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = + <0 0 0 1 &gic500 GIC_SPI 157 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic500 GIC_SPI 158 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic500 GIC_SPI 159 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic500 GIC_SPI 160 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x76000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x20000>; + }; + + secure_proxy_main: mailbox@32c00000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x32c00000 0x00 0x100000>, + <0x00 0x32400000 0x00 0x100000>, + <0x00 0x32800000 0x00 0x100000>; + interrupt-names = "rx_016"; + interrupts = ; + }; + + cbass_mcu: interconnect@28380000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + mcu_uart0: serial@40a00000 { + compatible = "ti,am654-uart"; + reg = <0x00 0x40a00000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = ; + clock-frequency = <96000000>; + current-speed = <115200>; + power-domains = <&k3_pds 149>; + }; + + cbass_wakeup: interconnect@42040000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + /* WKUP Basic peripherals */ + ranges = <0x42040000 0x00 0x42040000 0x03ac2400>; + dmsc: dmsc { + compatible = "ti,k2g-sci"; + ti,host-id = <13>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mbox-names = "rx", "tx"; + + mboxes= <&secure_proxy_main 16>, + <&secure_proxy_main 18>; + + k3_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <1>; + }; + + k3_clks: clocks { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + }; + }; + }; +}; diff --git a/configs/arm64/dts/inmate-k3-j7200-evm.dts b/configs/arm64/dts/inmate-k3-j7200-evm.dts new file mode 100644 index 0000000000000000000000000000000000000000..7a3e6adcbf5d75c2dc9c056b8997e257de9c99b6 --- /dev/null +++ b/configs/arm64/dts/inmate-k3-j7200-evm.dts @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for J7200 Jailhouse inmate kernel + * + * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; + +#include +#include +#include +#include + +#define TI_SCI_PD_EXCLUSIVE 1 + +/ { + model = "Texas Instruments J7200 Inmate Model"; + compatible = "ti,j7200-evm", "ti,j7200"; + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial3 = &main_uart1; + }; + + chosen { + stdout-path = "serial3:115200n8"; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + memory@8a0000000 { + device_type = "memory"; + reg = <0x8 0xa0000000 0x0 0x60000000>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0: cluster0 { + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a72"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xC000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <2048>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + }; + + a72_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = , /* cntpsirq */ + , /* cntpnsirq */ + , /* cntvirq */ + ; /* cnthpirq */ + }; + + pmu: pmu { + compatible = "arm,armv8-pmuv3"; + /* Recommendation from GIC500 TRM Table A.3 */ + interrupts = ; + }; + + firmware { + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + }; + + pci@76000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = + <0 0 0 1 &gic500 0 0 GIC_SPI 163 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic500 0 0 GIC_SPI 164 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic500 0 0 GIC_SPI 165 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic500 0 0 GIC_SPI 166 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x76000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + cbass_main: bus@100000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ + <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ + <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */ + <0x00 0x00A40000 0x00 0x00A40000 0x00 0x00000800>, /* timesync router */ + <0x00 0x06000000 0x00 0x06000000 0x00 0x00400000>, /* USBSS0 */ + <0x00 0x06400000 0x00 0x06400000 0x00 0x00400000>, /* USBSS1 */ + <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ + <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/ + <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */ + <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */ + <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ + <0x4d 0x81800000 0x4d 0x81800000 0x00 0x00800000>, /* C66_1 */ + <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */ + + /* MCUSS_WKUP Range */ + <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, + <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>; + + cbass_mcu_wakeup: interconnect@28380000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/ + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, /* First peripheral window */ + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */ + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */ + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */ + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, /* MCU SRAM */ + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP peripheral window */ + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */ + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */ + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, /* OSPI register space */ + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS OSPI0/1 data region 0 */ + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS OSPI0 data region 3 */ + <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>; /* FSS OSPI1 data region 3*/ + }; + }; +}; + +&cbass_main { + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ + + /* vcpumntirq: virtual CPU interface maintenance interrupt */ + interrupts = ; + }; + + main_gpio_intr: interrupt-controller0 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <131>; + ti,interrupt-ranges = <8 392 56>; + }; + + cbass_main_navss: interconnect0 { + compatible = "simple-mfd"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; + ti,sci-dev-id = <199>; + + main_navss_intr: interrupt-controller1 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <4>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <213>; + ti,interrupt-ranges = <0 64 64>, + <64 448 64>, + <128 672 64>; + }; + + main_udmass_inta: interrupt-controller@33d00000 { + compatible = "ti,sci-inta"; + reg = <0x0 0x33d00000 0x0 0x100000>; + interrupt-controller; + interrupt-parent = <&main_navss_intr>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <209>; + ti,interrupt-ranges = <0 0 256>; + }; + + secure_proxy_main: mailbox@32c00000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x32c00000 0x00 0x100000>, + <0x00 0x32400000 0x00 0x100000>, + <0x00 0x32800000 0x00 0x100000>; + interrupt-names = "rx_016"; + interrupts = ; + }; + }; + + main_pmx0: pinmux@11c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x0 0x11c000 0x0 0x2b4>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_uart1: serial@2810000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02810000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = ; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 278 2>; + clock-names = "fclk"; + }; + + main_gpio2: gpio@610000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x0 0x00610000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <154>, <155>, <156>, <157>, <158>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <69>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 107 0>; + clock-names = "gpio"; + }; + + main_sdhci0: sdhci@4f8000 { + compatible = "ti,j7200-sdhci-8bit", "ti,j721e-sdhci-8bit"; + reg = <0x0 0x04f80000 0x0 0x260>, <0x0 0x4f88000 0x0 0x134>; + interrupts = ; + power-domains = <&k3_pds 91 TI_SCI_PD_EXCLUSIVE>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&k3_clks 91 3>, <&k3_clks 91 0>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x8>; + ti,otap-del-sel-hs400 = <0x0>; + ti,strobe-sel = <0x77>; + ti,trm-icp = <0x8>; + bus-width = <8>; + mmc-hs400-1_8v; + mmc-ddr-1_8v; + dma-coherent; + }; +}; + +&cbass_mcu_wakeup { + dmsc: dmsc@44083000 { + compatible = "ti,k2g-sci"; + ti,host-id = <13>; + + mbox-names = "rx", "tx"; + + mboxes= <&secure_proxy_main 16>, + <&secure_proxy_main 18>; + + reg-names = "debug_messages"; + reg = <0x00 0x44083000 0x0 0x1000>; + + k3_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <2>; + }; + + k3_clks: clocks { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + + wkup_pmx0: pinmux@4301c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c000 0x00 0x178>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; +}; + +/* Board specific device tree entries */ + +&main_sdhci0 { + /* eMMC */ + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; +}; diff --git a/configs/arm64/dts/inmate-k3-j721e-evm.dts b/configs/arm64/dts/inmate-k3-j721e-evm.dts new file mode 100644 index 0000000000000000000000000000000000000000..ba4bbddce8dc5181929461e749f60416b7b0bfdd --- /dev/null +++ b/configs/arm64/dts/inmate-k3-j721e-evm.dts @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for J721E Jailhouse inmate kernel + * + * Copyright (C) 2016-2019 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; + +#include +#include +#include +#include + +#define J721E_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) + +#define PULLUDEN_SHIFT (16) +#define RXACTIVE_SHIFT (18) + +#define PULL_DISABLE (1 << PULLUDEN_SHIFT) + +#define INPUT_EN (1 << RXACTIVE_SHIFT) +#define INPUT_DISABLE (0 << RXACTIVE_SHIFT) + +#define PIN_OUTPUT (INPUT_DISABLE | PULL_DISABLE) +#define PIN_INPUT (INPUT_EN | PULL_DISABLE) + +#define TI_SCI_PD_EXCLUSIVE 1 + +/ { + model = "Texas Instruments J721E Inmate Model"; + compatible = "ti,j721e-evm", "ti,j721e"; + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial3 = &main_uart1; + }; + + chosen { + stdout-path = "serial3:115200n8"; + }; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + memory@8a0000000 { + device_type = "memory"; + reg = <0x8 0xa0000000 0x0 0x60000000>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0: cluster0 { + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a72"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xC000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <2048>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + }; + + a72_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = , /* cntpsirq */ + , /* cntpnsirq */ + , /* cntvirq */ + ; /* cnthpirq */ + }; + + pmu: pmu { + compatible = "arm,armv8-pmuv3"; + /* Recommendation from GIC500 TRM Table A.3 */ + interrupts = ; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + pci@76000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = + <0 0 0 1 &gic500 0 0 GIC_SPI 163 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic500 0 0 GIC_SPI 164 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic500 0 0 GIC_SPI 165 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic500 0 0 GIC_SPI 166 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x76000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x100000>; + }; + + cbass_main: interconnect@100000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ + <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ + <0x00 0x00900000 0x00 0x00900000 0x00 0x00012000>, /* serdes */ + <0x00 0x00A40000 0x00 0x00A40000 0x00 0x00000800>, /* timesync router */ + <0x00 0x06000000 0x00 0x06000000 0x00 0x00400000>, /* USBSS0 */ + <0x00 0x06400000 0x00 0x06400000 0x00 0x00400000>, /* USBSS1 */ + <0x00 0x01000000 0x00 0x01000000 0x00 0x0af02400>, /* Most peripherals */ + <0x00 0x30800000 0x00 0x30800000 0x00 0x0bc00000>, /* MAIN NAVSS */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x01000000>, /* PCIe Core*/ + <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */ + <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */ + <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ + <0x4d 0x81800000 0x4d 0x81800000 0x00 0x00800000>, /* C66_1 */ + <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */ + + /* MCUSS_WKUP Range */ + <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, + <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>; + + cbass_mcu_wakeup: interconnect@28380000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/ + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, /* First peripheral window */ + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */ + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */ + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */ + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, /* MCU SRAM */ + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP peripheral window */ + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */ + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */ + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, /* OSPI register space */ + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS OSPI0/1 data region 0 */ + <0x05 0x00000000 0x05 0x00000000 0x01 0x00000000>, /* FSS OSPI0 data region 3 */ + <0x07 0x00000000 0x07 0x00000000 0x01 0x00000000>; /* FSS OSPI1 data region 3*/ + }; + }; +}; + +&cbass_main { + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ + + /* vcpumntirq: virtual CPU interface maintenance interrupt */ + interrupts = ; + }; + + main_gpio_intr: interrupt-controller0 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <2>; + ti,sci = <&dmsc>; + ti,sci-dst-id = <14>; + ti,sci-rm-range-girq = <0x1>; + }; + + cbass_main_navss: interconnect0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + main_navss_intr: interrupt-controller1 { + compatible = "ti,sci-intr"; + ti,intr-trigger-type = <4>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <2>; + ti,sci = <&dmsc>; + ti,sci-dst-id = <14>; + ti,sci-rm-range-girq = <4>; + }; + + main_udmass_inta: interrupt-controller@33d00000 { + compatible = "ti,sci-inta"; + reg = <0x0 0x33d00000 0x0 0x100000>; + interrupt-controller; + interrupt-parent = <&main_navss_intr>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <209>; + ti,sci-rm-range-vint = <0xa>; + ti,sci-rm-range-global-event = <0xd>; + }; + }; + + secure_proxy_main: mailbox@32c00000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x32c00000 0x00 0x100000>, + <0x00 0x32400000 0x00 0x100000>, + <0x00 0x32800000 0x00 0x100000>; + interrupt-names = "rx_016"; + interrupts = ; + }; + + main_pmx0: pinmux@11c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x0 0x11c000 0x0 0x2b4>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_uart1: serial@2810000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02810000 0x00 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = ; + clock-frequency = <48000000>; + current-speed = <115200>; + power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 278 0>; + clock-names = "fclk"; + }; + + main_gpio2: gpio@610000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x0 0x00610000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <107 0>, <107 1>, <107 2>, <107 3>, + <107 4>, <107 5>, <107 6>, <107 7>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <128>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 107 0>; + clock-names = "gpio"; + }; + + main_gpio3: gpio@611000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x0 0x00611000 0x0 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <108 0>, <108 1>, <108 2>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <36>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 108 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 108 0>; + clock-names = "gpio"; + }; + + main_sdhci0: sdhci@4f80000 { + compatible = "ti,j721e-sdhci-8bit"; + reg = <0x0 0x4f80000 0x0 0x1000>, <0x0 0x4f88000 0x0 0x400>; + interrupts = ; + power-domains = <&k3_pds 91 TI_SCI_PD_EXCLUSIVE>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&k3_clks 91 1>, <&k3_clks 91 0>; + assigned-clocks = <&k3_clks 91 1>; + assigned-clock-parents = <&k3_clks 91 2>; + bus-width = <8>; + mmc-hs400-1_8v; + mmc-ddr-1_8v; + ti,otap-del-sel = <0x2>; + ti,trm-icp = <0x8>; + ti,strobe-sel = <0x77>; + dma-coherent; + }; + + usbss1: cdns_usb@4114000 { + compatible = "ti,j721e-usb"; + reg = <0x00 0x4114000 0x00 0x100>; + dma-coherent; + power-domains = <&k3_pds 289 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 289 15>, <&k3_clks 289 3>; + clock-names = "ref", "lpm"; + assigned-clocks = <&k3_clks 289 15>; /* USB2_REFCLK */ + assigned-clock-parents = <&k3_clks 289 16>; /* HFOSC0 */ + #address-cells = <2>; + #size-cells = <2>; + ranges; + + usb1: usb@6400000 { + compatible = "cdns,usb3"; + reg = <0x00 0x6400000 0x00 0x10000>, + <0x00 0x6410000 0x00 0x10000>, + <0x00 0x6420000 0x00 0x10000>; + reg-names = "otg", "xhci", "dev"; + interrupts = , /* irq.0 */ + , /* irq.6 */ + ; /* otgirq.0 */ + interrupt-names = "host", + "peripheral", + "otg"; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + }; +}; + +&cbass_mcu_wakeup { + dmsc: dmsc@44083000 { + compatible = "ti,k2g-sci"; + ti,host-id = <13>; + + mbox-names = "rx", "tx"; + + mboxes= <&secure_proxy_main 16>, + <&secure_proxy_main 18>; + + reg-names = "debug_messages"; + reg = <0x00 0x44083000 0x0 0x1000>; + + k3_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <2>; + }; + + k3_clks: clocks { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + + wkup_pmx0: pinmux@4301c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c000 0x00 0x178>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; +}; + +/* Board specific device tree entries */ + +/ { + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + pinctrl-names = "default"; + pinctrl-0 = <&sw10_button_pins_default>; + + sw10 { + label = "GPIO Key USER1"; + linux,code = ; + gpios = <&main_gpio2 0 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&main_pmx0 { + main_uart1_pins_default: main_uart1_pins_default { + pinctrl-single,pins = < + J721E_IOPAD(0x1f8, PIN_INPUT, 0) /* (AA4) UART1_RXD */ + J721E_IOPAD(0x1fc, PIN_OUTPUT, 0) /* (AB4) UART1_TXD */ + >; + }; + + sw10_button_pins_default: sw10_button_pins_default { + pinctrl-single,pins = < + /* PADCONFIG[5:4] = GPIO group select = 1 */ + J721E_IOPAD(0x0, PIN_INPUT, 23) /* (AC18) EXTINTn.GPIO2_0 */ + >; + }; + + main_usbss1_pins_default: main_usbss1_pins_default { + pinctrl-single,pins = < + J721E_IOPAD(0x214, PIN_OUTPUT, 4) /* (V4) MCAN1_TX.USB1_DRVVBUS */ + >; + }; +}; + +&main_uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_uart1_pins_default>; +}; + +&main_sdhci0 { + /* eMMC */ + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&usbss1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_usbss1_pins_default>; + ti,usb2-only; +}; + +&usb1 { + dr_mode = "host"; + maximum-speed = "high-speed"; +}; diff --git a/configs/arm64/dts/inmate-ls1028a-rdb.dts b/configs/arm64/dts/inmate-ls1028a-rdb.dts new file mode 100644 index 0000000000000000000000000000000000000000..bf196b92247a380aa780b113c8386d73231439ab --- /dev/null +++ b/configs/arm64/dts/inmate-ls1028a-rdb.dts @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP LS1028ARDB platform + * + * Copyright 2021 NXP + * + * Anda-Alexandra Dorneanu + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls1028a-rdb", "fsl,ls1028a"; + model = "LS1028A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &duart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x1>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PW20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + l2: l2-cache { + compatible = "cache"; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + idle-states { + entry-method = "psci"; + + CPU_PW20: cpu-pw20 { + compatible = "arm,idle-state"; + idle-state-name = "PW20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <2000>; + exit-latency-us = <2000>; + min-residency-us = <6000>; + }; + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@6000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x6000000 0 0x10000>, + <0x0 0x6040000 0 0x40000>; + interrupts = ; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ddr: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = ; + big-endian; + }; + + clockgen: clock-controller@1300000 { + compatible = "fsl,ls1028a-clockgen"; + reg = <0x0 0x1300000 0x0 0xa0000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 1>; + status = "okay"; + }; + }; + + pci@fb500000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 8 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 9 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 10 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 11 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfb500000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; +}; diff --git a/configs/arm64/dts/inmate-ls1043a-rdb-dpaa.dts b/configs/arm64/dts/inmate-ls1043a-rdb-dpaa.dts new file mode 100644 index 0000000000000000000000000000000000000000..34629a418a41a1fb9fdf396b9d3932e69b3d35d3 --- /dev/null +++ b/configs/arm64/dts/inmate-ls1043a-rdb-dpaa.dts @@ -0,0 +1,930 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP ls1043a RDB platform + * + * Copyright 2020 NXP + * + * hongbo.wang + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls1043a-rdb", "fsl,ls1043a"; + model = "LS1043A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + aliases { + serial0 = &duart1; + fman0 = &fman0; + ethernet0 = &enet0; + ethernet1 = &enet1; + ethernet2 = &enet2; + ethernet3 = &enet3; + ethernet4 = &enet4; + ethernet5 = &enet5; + ethernet6 = &enet6; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + l2: l2-cache { + compatible = "cache"; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + idle-states { + entry-method = "psci"; + + CPU_PH20: cpu-ph20 { + compatible = "arm,idle-state"; + idle-state-name = "PH20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <1000>; + exit-latency-us = <1000>; + min-residency-us = <3000>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + bman_fbpr: bman-fbpr { + compatible = "shared-dma-pool"; + size = <0 0x1000000>; + alignment = <0 0x1000000>; + no-map; + }; + + qman_fqd: qman-fqd { + compatible = "shared-dma-pool"; + size = <0 0x400000>; + alignment = <0 0x400000>; + no-map; + }; + + qman_pfdr: qman-pfdr { + compatible = "shared-dma-pool"; + size = <0 0x2000000>; + alignment = <0 0x2000000>; + no-map; + }; + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + reboot { + compatible ="syscon-reboot"; + regmap = <&dcfg>; + offset = <0xb0>; + mask = <0x02>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 0xf08>, /* Physical Secure PPI */ + <1 14 0xf08>, /* Physical Non-Secure PPI */ + <1 11 0xf08>, /* Virtual PPI */ + <1 10 0xf08>; /* Hypervisor PPI */ + }; + + gic: interrupt-controller@1410000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x1410000 0 0x10000>, /* GICD */ + <0x0 0x142f000 0 0x1000>, /* GICC */ + <0x0 0x1440000 0 0x20000>, /* GICH */ + <0x0 0x146f000 0 0x1000>; /* GICV */ + interrupts = <1 9 0xf08>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>; + + + ddr: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = <0 144 0x4>; + big-endian; + dma-coherent; + }; + + + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1043a-dcfg", "syscon"; + reg = <0x0 0x1ee0000 0x0 0x1000>; + big-endian; + dma-coherent; + }; + + clockgen: clocking@1ee1000 { + compatible = "fsl,ls1043a-clockgen"; + reg = <0x0 0x1ee1000 0x0 0x1000>; + #clock-cells = <2>; + clocks = <&sysclk>; + dma-coherent; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 0>; + status = "okay"; + dma-coherent; + }; + + qman: qman@1880000 { + compatible = "fsl,qman"; + reg = <0x0 0x1880000 0x0 0x10000>; + interrupts = ; + memory-region = <&qman_fqd &qman_pfdr>; + dma-coherent; + clock-frequency = <400000000>; + }; + + bman: bman@1890000 { + compatible = "fsl,bman"; + reg = <0x0 0x1890000 0x0 0x10000>; + interrupts = ; + memory-region = <&bman_fbpr>; + dma-coherent; + }; + + bportals: bman-portals@508000000 { + ranges = <0x0 0x5 0x08000000 0x8000000>; + dma-coherent; + }; + + qportals: qman-portals@500000000 { + ranges = <0x0 0x5 0x00000000 0x8000000>; + dma-coherent; + }; + + ptp_timer0: ptp-timer@1afe000 { + compatible = "fsl,fman-ptp-timer", "fsl,fman-rtc"; + reg = <0x0 0x1afe000 0x0 0x1000>; + interrupts = ; + clocks = <&clockgen 3 0>; + dma-coherent; + }; + + /* fman3-0 */ + fman0: fman@1a00000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + compatible = "fsl,fman"; + ranges = <0x0 0x0 0x1a00000 0xfe000>; + reg = <0x0 0x1a00000 0x0 0xfe000>; + interrupts = , + ; + clocks = <&clockgen 3 0>; + clock-names = "fmanclk"; + fsl,qman-channel-range = <0x800 0x10>; + ptimer-handle = <&ptp_timer0>; + dma-coherent; + + cc { + compatible = "fsl,fman-cc"; + }; + + muram@0 { + compatible = "fsl,fman-muram"; + reg = <0x0 0x60000>; + }; + + bmi@80000 { + compatible = "fsl,fman-bmi"; + reg = <0x80000 0x400>; + }; + + qmi@80400 { + compatible = "fsl,fman-qmi"; + reg = <0x80400 0x400>; + }; + + fman0_oh1: port@82000 { + cell-index = <0>; + compatible = "fsl,fman-port-oh"; + reg = <0x82000 0x1000>; + fsl,qman-channel-id = <0x809>; + }; + + fman0_oh2: port@83000 { + cell-index = <1>; + compatible = "fsl,fman-port-oh"; + reg = <0x83000 0x1000>; + fsl,qman-channel-id = <0x80a>; + }; + + fman0_oh3: port@84000 { + cell-index = <2>; + compatible = "fsl,fman-port-oh"; + reg = <0x84000 0x1000>; + fsl,qman-channel-id = <0x80b>; + }; + + fman0_oh4: port@85000 { + cell-index = <3>; + compatible = "fsl,fman-port-oh"; + reg = <0x85000 0x1000>; + fsl,qman-channel-id = <0x80c>; + }; + + fman0_oh5: port@86000 { + cell-index = <4>; + compatible = "fsl,fman-port-oh"; + reg = <0x86000 0x1000>; + fsl,qman-channel-id = <0x80d>; + }; + + fman0_oh6: port@87000 { + cell-index = <5>; + compatible = "fsl,fman-port-oh"; + reg = <0x87000 0x1000>; + fsl,qman-channel-id = <0x80e>; + }; + + policer@c0000 { + compatible = "fsl,fman-policer"; + reg = <0xc0000 0x1000>; + }; + + keygen@c1000 { + compatible = "fsl,fman-keygen"; + reg = <0xc1000 0x1000>; + }; + + dma@c2000 { + compatible = "fsl,fman-dma"; + reg = <0xc2000 0x1000>; + }; + + fpm@c3000 { + compatible = "fsl,fman-fpm"; + reg = <0xc3000 0x1000>; + }; + + parser@c7000 { + compatible = "fsl,fman-parser"; + reg = <0xc7000 0x1000>; + }; + + vsps@dc000 { + compatible = "fsl,fman-vsps"; + reg = <0xdc000 0x1000>; + }; + + mdio0: mdio@fc000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xfc000 0x1000>; + }; + + xmdio0: mdio@fd000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xfd000 0x1000>; + }; + + /* fman3-0-1g-0 */ + fman0_rx_0x08: port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x88000 0x1000>; + }; + + fman0_tx_0x28: port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xa8000 0x1000>; + fsl,qman-channel-id = <0x802>; + }; + + ethernet@e0000 { + cell-index = <0>; + compatible = "fsl,fman-memac"; + reg = <0xe0000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy0>; + }; + + mdio@e1000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xe1000 0x1000>; + + pcsphy0: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-1g-1 */ + fman0_rx_0x09: port@89000 { + cell-index = <0x9>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x89000 0x1000>; + }; + + fman0_tx_0x29: port@a9000 { + cell-index = <0x29>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xa9000 0x1000>; + fsl,qman-channel-id = <0x803>; + }; + + ethernet@e2000 { + cell-index = <1>; + compatible = "fsl,fman-memac"; + reg = <0xe2000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy1>; + }; + + mdio@e3000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xe3000 0x1000>; + + pcsphy1: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-1g-2 */ + fman0_rx_0x0a: port@8a000 { + cell-index = <0xa>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x8a000 0x1000>; + }; + + fman0_tx_0x2a: port@aa000 { + cell-index = <0x2a>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xaa000 0x1000>; + fsl,qman-channel-id = <0x804>; + }; + + ethernet@e4000 { + cell-index = <2>; + compatible = "fsl,fman-memac"; + reg = <0xe4000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy2>; + }; + + mdio@e5000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xe5000 0x1000>; + + pcsphy2: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-1g-3 */ + fman0_rx_0x0b: port@8b000 { + cell-index = <0xb>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x8b000 0x1000>; + }; + + fman0_tx_0x2b: port@ab000 { + cell-index = <0x2b>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xab000 0x1000>; + fsl,qman-channel-id = <0x805>; + }; + + ethernet@e6000 { + cell-index = <3>; + compatible = "fsl,fman-memac"; + reg = <0xe6000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy3>; + }; + + mdio@e7000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xe7000 0x1000>; + + pcsphy3: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-1g-4 */ + fman0_rx_0x0c: port@8c000 { + cell-index = <0xc>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x8c000 0x1000>; + }; + + fman0_tx_0x2c: port@ac000 { + cell-index = <0x2c>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xac000 0x1000>; + fsl,qman-channel-id = <0x806>; + }; + + ethernet@e8000 { + cell-index = <4>; + compatible = "fsl,fman-memac"; + reg = <0xe8000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy4>; + }; + + mdio@e9000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xe9000 0x1000>; + + pcsphy4: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-1g-5 */ + fman0_rx_0x0d: port@8d000 { + cell-index = <0xd>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; + reg = <0x8d000 0x1000>; + }; + + fman0_tx_0x2d: port@ad000 { + cell-index = <0x2d>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; + reg = <0xad000 0x1000>; + fsl,qman-channel-id = <0x807>; + }; + + ethernet@ea000 { + cell-index = <5>; + compatible = "fsl,fman-memac"; + reg = <0xea000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>; + ptp-timer = <&ptp_timer0>; + pcsphy-handle = <&pcsphy5>; + }; + + mdio@eb000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xeb000 0x1000>; + + pcsphy5: ethernet-phy@0 { + reg = <0x0>; + }; + }; + + /* fman3-0-10g-0 */ + fman0_rx_0x10: port@90000 { + cell-index = <0x10>; + compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx"; + reg = <0x90000 0x1000>; + fsl,fman-10g-port; + }; + + fman0_tx_0x30: port@b0000 { + cell-index = <0x30>; + compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx"; + reg = <0xb0000 0x1000>; + fsl,fman-10g-port; + fsl,qman-channel-id = <0x800>; + }; + + ethernet@f0000 { + cell-index = <0x8>; + compatible = "fsl,fman-memac"; + reg = <0xf0000 0x1000>; + fsl,fman-ports = <&fman0_rx_0x10 &fman0_tx_0x30>; + pcsphy-handle = <&pcsphy6>; + }; + + mdio@f1000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + + pcsphy6: ethernet-phy@0 { + reg = <0x0>; + }; + }; + }; + + fsldpaa: fsl,dpaa { + compatible = "fsl,ls1043a-dpaa", "simple-bus", "fsl,dpaa"; + dma-coherent; + ethernet@0 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet0>; + dma-coherent; + }; + ethernet@1 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet1>; + dma-coherent; + }; + ethernet@2 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet2>; + dma-coherent; + }; + ethernet@3 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet3>; + dma-coherent; + }; + ethernet@4 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet4>; + dma-coherent; + }; + ethernet@5 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet5>; + dma-coherent; + }; + ethernet@8 { + compatible = "fsl,dpa-ethernet"; + fsl,fman-mac = <&enet6>; + dma-coherent; + }; + }; + + }; + + pci@c0700000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xc0700000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + +}; + +&qportals { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + + qportal0: qman-portal@0 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x0 0x4000>, <0x4000000 0x4000>; + interrupts = ; + cell-index = <0>; + }; + + qportal1: qman-portal@10000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x10000 0x4000>, <0x4010000 0x4000>; + interrupts = ; + cell-index = <1>; + }; + + qportal2: qman-portal@20000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x20000 0x4000>, <0x4020000 0x4000>; + interrupts = ; + cell-index = <2>; + }; + + qportal3: qman-portal@30000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x30000 0x4000>, <0x4030000 0x4000>; + interrupts = ; + cell-index = <3>; + }; + + qportal4: qman-portal@40000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x40000 0x4000>, <0x4040000 0x4000>; + interrupts = ; + cell-index = <4>; + }; + + qportal5: qman-portal@50000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x50000 0x4000>, <0x4050000 0x4000>; + interrupts = ; + cell-index = <5>; + }; + + qportal6: qman-portal@60000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x60000 0x4000>, <0x4060000 0x4000>; + interrupts = ; + cell-index = <6>; + }; + + qportal7: qman-portal@70000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x70000 0x4000>, <0x4070000 0x4000>; + interrupts = ; + cell-index = <7>; + }; + + qportal8: qman-portal@80000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x80000 0x4000>, <0x4080000 0x4000>; + interrupts = ; + cell-index = <8>; + }; + + qportal9: qman-portal@90000 { + compatible = "fsl,qman-portal-3.2.0", "fsl,qman-portal"; + reg = <0x90000 0x4000>, <0x4090000 0x4000>; + interrupts = ; + cell-index = <9>; + }; + + qman-fqids@0 { + compatible = "fsl,fqid-range"; + fsl,fqid-range = <256 256>; + }; + + qman-fqids@1 { + compatible = "fsl,fqid-range"; + fsl,fqid-range = <32768 32768>; + }; + + qman-pools@0 { + compatible = "fsl,pool-channel-range"; + fsl,pool-channel-range = <0x401 0xf>; + }; + + qman-cgrids@0 { + compatible = "fsl,cgrid-range"; + fsl,cgrid-range = <0 256>; + }; + + qman-ceetm@0 { + compatible = "fsl,qman-ceetm"; + fsl,ceetm-lfqid-range = <0xf00000 0x1000>; + fsl,ceetm-sp-range = <0 16>; + fsl,ceetm-lni-range = <0 8>; + fsl,ceetm-channel-range = <0 32>; + }; +}; + +&bportals { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + + bman-portal@0 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x0 0x4000>, <0x4000000 0x4000>; + interrupts = ; + cell-index = <0>; + }; + + bman-portal@10000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x10000 0x4000>, <0x4010000 0x4000>; + interrupts = ; + cell-index = <1>; + }; + + bman-portal@20000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x20000 0x4000>, <0x4020000 0x4000>; + interrupts = ; + cell-index = <2>; + }; + + bman-portal@30000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x30000 0x4000>, <0x4030000 0x4000>; + interrupts = ; + cell-index = <3>; + }; + + bman-portal@40000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x40000 0x4000>, <0x4040000 0x4000>; + interrupts = ; + cell-index = <4>; + }; + + bman-portal@50000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x50000 0x4000>, <0x4050000 0x4000>; + interrupts = ; + cell-index = <5>; + }; + + bman-portal@60000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x60000 0x4000>, <0x4060000 0x4000>; + interrupts = ; + cell-index = <6>; + }; + + bman-portal@70000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x70000 0x4000>, <0x4070000 0x4000>; + interrupts = ; + cell-index = <7>; + }; + + bman-portal@80000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x80000 0x4000>, <0x4080000 0x4000>; + interrupts = ; + cell-index = <8>; + }; + + bman-portal@90000 { + compatible = "fsl,bman-portal-2.1.3", "fsl,bman-portal"; + reg = <0x90000 0x4000>, <0x4090000 0x4000>; + interrupts = ; + cell-index = <9>; + }; + + bman-bpids@0 { + compatible = "fsl,bpid-range"; + fsl,bpid-range = <32 32>; + }; +}; + +&fman0 { + fsl,erratum-a050385; + compatible = "fsl,fman", "simple-bus"; + + /* these aliases provide the FMan ports mapping */ + enet0: ethernet@e0000 { + phy-handle = <&qsgmii_phy1>; + phy-connection-type = "qsgmii"; + local-mac-address = [0e 09 00 01 03 05]; + }; + + enet1: ethernet@e2000 { + phy-handle = <&qsgmii_phy2>; + phy-connection-type = "qsgmii"; + local-mac-address = [0e 09 00 01 03 06]; + }; + + enet2: ethernet@e4000 { + phy-handle = <&rgmii_phy1>; + phy-connection-type = "rgmii-txid"; + local-mac-address = [0e 09 00 01 03 07]; + }; + + enet3: ethernet@e6000 { + phy-handle = <&rgmii_phy2>; + phy-connection-type = "rgmii-txid"; + local-mac-address = [0e 09 00 01 03 08]; + }; + + enet4: ethernet@e8000 { + phy-handle = <&qsgmii_phy3>; + phy-connection-type = "qsgmii"; + local-mac-address = [0e 09 00 01 03 09]; + }; + + enet5: ethernet@ea000 { + phy-handle = <&qsgmii_phy4>; + phy-connection-type = "qsgmii"; + local-mac-address = [0e 09 00 01 03 0a]; + }; + + enet6: ethernet@f0000 { /* 10GEC1 */ + phy-handle = <&aqr105_phy>; + phy-connection-type = "xgmii"; + local-mac-address = [0e 09 00 01 03 04]; + }; + + mdio@fc000 { + rgmii_phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + rgmii_phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + qsgmii_phy1: ethernet-phy@4 { + reg = <0x4>; + }; + + qsgmii_phy2: ethernet-phy@5 { + reg = <0x5>; + }; + + qsgmii_phy3: ethernet-phy@6 { + reg = <0x6>; + }; + + qsgmii_phy4: ethernet-phy@7 { + reg = <0x7>; + }; + }; + + mdio@fd000 { + aqr105_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + interrupts = <0 132 4>; + reg = <0x1>; + }; + }; +}; + +&bman_fbpr { + compatible = "fsl,bman-fbpr"; + alloc-ranges = <0 0 0x10000 0>; +}; +&qman_fqd { + compatible = "fsl,qman-fqd"; + alloc-ranges = <0 0 0x10000 0>; +}; +&qman_pfdr { + compatible = "fsl,qman-pfdr"; + alloc-ranges = <0 0 0x10000 0>; +}; + +&soc { + fman@1a00000 { +#include "inmate-ls1043a-rdb-fman-ucode.dtsi" + }; +}; diff --git a/configs/arm64/dts/inmate-ls1043a-rdb-fman-ucode.dtsi b/configs/arm64/dts/inmate-ls1043a-rdb-fman-ucode.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7c7427afed84e648ec73695e121ccbdfe1611962 --- /dev/null +++ b/configs/arm64/dts/inmate-ls1043a-rdb-fman-ucode.dtsi @@ -0,0 +1,1038 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP ls1043a RDB platform + * + * Copyright 2021 NXP + * + * hongbo.wang + */ + +/* +length:32604 version:1 magic:Q-E-F +*/ + +fman_fm0: fman-firmware { + name = "fman-firmware"; + compatible = "fsl,fman-firmware"; + fsl,firmware = < + 0x00007F5C 0x51454601 0x4D696372 0x6F636F64 0x65207665 0x7273696F 0x6E203130 0x362E342E + 0x31382066 0x6F72204C 0x53313034 0x33207231 0x2E310000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000001 0x04130101 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x4D696372 + 0x6F636F64 0x6520666F 0x72204C53 0x31303433 0x2072312E 0x31000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x20800000 + 0x00000000 0x00001F99 0x000000F4 0x6A041200 0x00000000 0xB7FF01D6 0x006A0412 0xB7FF01EA + 0xFFFFFFFF 0xB7FF01E8 0xFFFFFFFF 0xB7FF0222 0xFFFFFFFF 0xB7FF0812 0xFFFFFFFF 0xB7FF074E + 0xFFFFFFFF 0xB7FF185E 0xFFFFFFFF 0xB7FF1DA0 0xFFFFFFFF 0xB7FF0020 0xFFFFFFFF 0xB7FF00AC + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB7FF0110 0xFFFFFFFF 0xB7FF001B 0xFFFFFFFF 0xB7FF01A6 + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB7FF01A4 0xFFFFFFFF 0xB7FF01A4 0xFFFFFFFF 0xB7FF0176 + 0xFFFFFFFF 0xB7FF01E3 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB7FF01E9 0xFFFFFFFF 0xB7FF01E9 + 0xFFFFFFFF 0xB7FF1E82 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xC6500208 0xB3FF000D 0xD2DF027E + 0x0402D008 0xE542FFF0 0xEC222400 0xB47F0006 0x7804F907 0xD2C4313E 0xD344393E 0xB3FFFFF6 + 0x73E42107 0xC650020C 0xEBC90000 0x0200D016 0x0401D00C 0xF1401B0F 0xED40000F 0x1200D016 + 0x93630005 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB3FF0060 0x1409D0C4 0xB3FF001A + 0xE9C9000E 0xB3FF0018 0xE9C90006 0xB3FF0016 0xE9C9001E 0xB3FF0014 0xE9C90016 0xB3FF0012 + 0xE9C9003E 0xB3FF0010 0xE9C90036 0xB3FF000E 0xE9C90001 0xB3FF004F 0x1409D0C4 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB3FF004F 0xE9C90200 0xFFFFFFFF 0xFFFFFFFF 0xB3FF0002 + 0xE9C90802 0x1409D0C4 0xBFC9000F 0xE121F000 0xB43F000D 0xB689001C 0xD2C1B07E 0x1401D0C0 + 0xD9FF10B8 0xBC3F0007 0x7802F907 0xD2C228BE 0x73E21107 0xD2DFB07E 0xB3FF0039 0xC600001A + 0xD2DFB07E 0xBF690034 0x0402D008 0xD2C1F07E 0xBC020031 0x0602D000 0xE3DB2000 0x5402D0D0 + 0x141ED0CC 0xD341F07E 0xD349227E 0x1409D0C4 0xBFE90002 0xD2C1E07E 0x1401D00C 0x2E3F0006 + 0xFFFFFFFF 0xD2DFE07E 0xE9C9000D 0xB3FF0022 0x1409D0C4 0x0600D010 0xBCE10007 0xE3C1000D + 0xE9C1C000 0xCE40700D 0xD84100F8 0xB3FF0007 0xE843002C 0x7C11F801 0xEBC3000C 0xE0430008 + 0xCDD1A459 0xD84388F8 0x77631B00 0xE3DB2000 0x7810FB00 0x0600D0D0 0x0602D000 0xCEF0A4C9 + 0xCA801000 0xD8619878 0xD8C0F838 0xCF10E509 0xD854D538 0xCEF02549 0xEC550001 0x73F5AD00 + 0x041ED0CC 0x5500A000 0x2C3FF000 0xFFFFFFFF 0xD341F07E 0xBFE90002 0xD2C1E07E 0x1401D00C + 0x2C3FF000 0xFFFFFFFF 0xE921DFF1 0xB03F000E 0x1409D0C4 0xD2C1B07E 0x1401D0C0 0xD9FF10B8 + 0xBC3F0007 0x7802F907 0xD2C228BE 0x73E21107 0xD2DFB07E 0xB3FFFFF2 0xC600001A 0xB3FFFFF0 + 0xD2DFB07E 0xB3FFFFEC 0xD341D87E 0x0409D0C4 0x050AD01D 0x0400D014 0xB0E00005 0x150AD0CC + 0x7802F907 0xD2C228BE 0x73E21107 0x1200D09A 0xBBC9005C 0xB6C90001 0x0401D00C 0x0200D02A + 0xB4610002 0x1200D0C8 0xBF690003 0xD341F07E 0x1401D00C 0x040AD008 0xBC0A0019 0x7803F907 + 0xB7030017 0x7C11F801 0xEBC3038C 0xE0430008 0xCC1A41A1 0xCDD1A459 0xD84388F8 0x73661B00 + 0x77631B00 0x7810FB00 0xCDB041D1 0xED50FFFF 0xDC2681B8 0xBC3F0028 0x0210380E 0xB2C9000C + 0x0602D000 0xD86380F8 0xD8C2F8B8 0xE3DB2000 0x55A23800 0xF8705528 0x140AD008 0xBD210033 + 0xC600001A 0x2C3FF000 0xFFFFFFFF 0x04043808 0xBC24FFF5 0xA3FF1D41 0x0000D001 0x0602D000 + 0x06043800 0xCA841100 0x1604D000 0x0004380D 0xE54AE000 0x1004D001 0x7C11F801 0xEBC30384 + 0xE0430008 0xCDD1A459 0xD84388F8 0x73671B00 0xE8430004 0xCC1A4161 0xFA1A2E00 0x73651B00 + 0x7C00F911 0xED400001 0x77600111 0xB3FFFFE2 0x0401D00C 0x7810F800 0xEBC00060 0xE1C00008 + 0xF0508301 0xDBD0E0BD 0x73620300 0x77600300 0x7810FB00 0xDC301438 0xBC3FFFFC 0x73661B00 + 0x77631B00 0x7810FB00 0xEBC20060 0xE1C20008 0x737F1300 0xCDB041D1 0xED50FFFF 0xDC2681B8 + 0xBC3FFFED 0xB7FFFFC5 0xB6C90006 0xC6000016 0x050AD01D 0x151ED01D 0x151ED0CC 0x150AD0C0 + 0xC6440000 0x2C3FF000 0xFFFFFFFF 0x0401D0C4 0xBFA10046 0x0209D024 0xD341107E 0xBAC90043 + 0x1401D0C4 0x0009D037 0xB2810029 0xCB09E280 0x02095000 0x000C5002 0xEBCD86DD 0xB74C0002 + 0xEBCD0800 0xDA296A78 0xB43F0038 0x120D5000 0xB7E1000D 0x0205D0C8 0xDDDF4A78 0xE949FFFF + 0xD8454938 0xCFE48181 0xD8443138 0xE944FFFF 0xD8446938 0xCFE48181 0xD8443138 0xE944FFFF + 0x1204D0C8 0x0400D018 0xD2C0E83E 0x1400D018 0x000BD033 0x040CD00C 0x770B5903 0xCB1F6306 + 0x140CD00C 0x141FD022 0x101FD026 0x101FD021 0x141FD02C 0xC6440000 0xB7E10003 0x0200D0C8 + 0x1200D02A 0x2C3FF000 0xFFFFFFFF 0x000C5002 0xE84A0002 0xDBDCC21D 0x0017D03B 0x0407D008 + 0xDC5745F8 0xE547FFF0 0xB34C000D 0xDC47B9F8 0x12075002 0x121F500A 0xCF4C1301 0xEC4C0001 + 0x73FFFC01 0x6F60FC06 0x400C5000 0x7807FC01 0xEE470000 0x1207500A 0xB7FFFFDB 0xEC470028 + 0x12075004 0xB7FFFFD8 0xB7410420 0xBF810023 0x0008D026 0x051ED0C0 0xE94800E0 0xEC680040 + 0xBC3F001E 0x151ED01D 0x151ED0CC 0x0017D03E 0x0008D033 0xCB17E700 0x0407D008 0x0209E004 + 0xE547FFF0 0xDC5741B8 0xDC4731F8 0xBA810005 0x1207E004 0x121FE006 0xEC470010 0x1207E00A + 0xB7E1FFC1 0x0205D0C8 0xDDDF4A78 0xE949FFFF 0xD8454938 0xCFE48581 0xD844B138 0xE944FFFF + 0xD8443938 0xCFE48581 0xD844B138 0xE944FFFF 0x1204D0C8 0xB7FFFFB4 0x051ED0C0 0x151ED0CC + 0xB3FFFFB4 0x151ED01D 0x0401D0C0 0xB3FF0006 0x1401D00C 0x0401D00C 0xB521FFFC 0xD341E07E + 0x1401D00C 0xA3FF0005 0x0409D018 0xC6D40000 0x2C3FF000 0xFFFFFFFF 0xB889000F 0x000AD03B + 0x0000D026 0x000BD03E 0x040ED00C 0xE94000E0 0xEC600040 0xB83F0003 0xDC4B52F8 0xE84B0008 + 0xDBCB82FD 0xF1CB5880 0x140ED0B4 0x9BFFF400 0x140BD00C 0x9C09F401 0x040ED00C 0xDBDCC19D + 0xD84652B8 0xE3CB8000 0xCB0AE700 0x000AE000 0x000CD09C 0xB34A0003 0xEBCD0029 0xEBCD0004 + 0xD9CB6AF8 0xF90C5C20 0x140ED0B4 0x9BFFF400 0x140BD00C 0xB3FF1D65 0xEBC00000 0xB3FF1D63 + 0xEBC00001 0x0200D09A 0x0201D016 0x1200D016 0x7C0AF801 0x1201D02A 0xE12A3800 0xB03F0008 + 0x051ED0CC 0xEBCB0028 0xE04B0008 0xCDCAA299 0xD84B52F8 0x776B5B00 0x781EFB00 0xD35EBFBE + 0x151ED01D 0x2C3FF000 0xFFFFFFFF 0x7902F800 0x7904F800 0x7906F800 0x7908F800 0x790AF800 + 0x790CF800 0x790EF800 0x7910F800 0x7912F800 0x7914F800 0x7916F800 0x7918F800 0x791AF800 + 0x791CF800 0x791EF800 0x777FF802 0x777FF803 0x777FF804 0x7802F800 0xD9FF10B8 0xB03F0004 + 0x7900F800 0x281FF800 0xFFFFFFFF 0x7800F900 0xBC00FFFF 0xDBC0C0BD 0xC60C3078 0x777EF300 + 0x7809FB00 0xC8024A70 0x7369F300 0x77000001 0xC60C3000 0xE9C20203 0x7362F300 0x777EF300 + 0x7800FB00 0x2E1F0002 0xFFFFFFFF 0xEBC00001 0x70E00101 0x2E3F0002 0xFFFFFFFF 0xC60C3074 + 0xE3C20080 0x7362F300 0x2E1FFFF9 0xFFFFFFFF 0x7801F907 0x0202D016 0xD341207E 0xE942000F + 0xEC620001 0xB03F02F8 0x73E10907 0xC65000C0 0x2C3FF000 0xFFFFFFFF 0xB3FF1CE5 0xEBC00000 + 0xB3FF1CE3 0xEBC00001 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x7C0AF801 0x0401D00C 0xEBC23000 + 0xD341887E 0x1401D00C 0xE1C2000C 0xDBCAC2BD 0xE1CA0002 0x736A1300 0x0200D0B0 0xDBC0203D + 0x0614D030 0x0616D038 0xB3FF0009 0x06040008 0xFFFFFFFF 0x0400D018 0x0614D030 0x0403D00C + 0x0616D038 0xB7430305 0x06040008 0x06180000 0xDBC411BD 0xBC380008 0x93E60077 0xB4180001 + 0x0604C008 0xD9DFC038 0xB3FFFFFA 0x0618C000 0xFFFFFFFF 0xB404001C 0xB818000B 0x0610D010 + 0xB4580002 0xFB112400 0xB0E40004 0xDBD9C65D 0x7812F907 0xD9D99678 0x73F9C907 0x2C3F2000 + 0xFFFFFFFF 0xBC840008 0xB4790007 0xB4E40006 0x7812F907 0xDBD2C4BD 0xD9D99678 0xD359E67E + 0xD2C4C13E 0xBCC40002 0xC8F1CE70 0xCA11CE40 0x1618D010 0x2C382000 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xB884000C 0x0610D010 0xB4790005 0x0412D018 0xD352CCBE 0xB3FF000C 0x1412D018 + 0xDBC5849D 0xC2FFFFBC 0x1212D0B0 0xB3FF0007 0x141ED08C 0xBC240005 0x0481000C 0xB7DFFFFF + 0xE8410001 0x1481000C 0xBC44002F 0xBC180016 0xBC840008 0xB4790007 0xB0E4000A 0xDBD9C01D + 0x7812F907 0xD9C09038 0xB3FF0006 0xD340203E 0xB0E40004 0xDBD9C01D 0x7812F907 0xD9C09038 + 0x73E00107 0xB4580002 0xFB112400 0x73E42106 0xCD992009 0xB3FFFFB6 0x06040008 0xFFFFFFFF + 0xFFFFFFFF 0xB4E40007 0x7800F907 0xDBC0C03D 0xBC840003 0xB4790002 0xD340E03E 0xD9D90678 + 0xCD992009 0xBCC40002 0xC8F1CE70 0xCA11CE40 0x1618D010 0x73E42106 0x7758C104 0xDBD8C61D + 0xFAF9C410 0x7778C107 0xDBD9C65D 0x73F9C907 0xB3FFFF9F 0x06040008 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xBC18FFB0 0xBC840008 0xB4790007 0xB0E4000A 0xDBD9C01D 0x7812F907 0xD9C09038 + 0xB3FF0006 0xD340203E 0xB0E40004 0xDBD9C01D 0x7812F907 0xD9C09038 0x73E00107 0xB4580002 + 0xFB112400 0x2C3F2000 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB14E000 0x0608E000 0x73F8C420 + 0x4D48C800 0x2E5F01D4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB14E000 0x0608E006 0x73F8C420 + 0x4D48C800 0x2E5F01CC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB15E000 0x0408E000 0x73F8C420 + 0x4C48C800 0x2E5F01C4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB15E400 0x0404E000 0x73F8C420 + 0x4E44C800 0x2E5F01BC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB15E600 0x0404E000 0x73F8C420 + 0x4E44C800 0x2E5F01B4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E200 0x0408E006 0x73F8C420 + 0x4C48C800 0x2E5F01AC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E400 0x0404E000 0x73F8C420 + 0x4EC4C800 0x2E5F01A4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E600 0x0404E000 0x73F8C420 + 0x4EC4C800 0x2E5F019C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0408E010 0x73F8C420 + 0x4CC8C800 0x2E5F0194 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0404E001 0x73F8C420 + 0x4E04C800 0x2E5F018C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0408E009 0x73F8C420 + 0x4C08C800 0x2E5F0184 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0408E00C 0x73F8C420 + 0x4CC8C800 0x2E5F017C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0608E00C 0x73F8C420 + 0x4DC8C800 0x2E5F0174 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0404E000 0x73F8C420 + 0x4EC4C800 0x2E5F016C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0408E006 0x73F8C420 + 0x4C08C800 0x2E5F0164 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0xEBC4000F 0xF05C4318 + 0xF8044630 0x73F8C420 0x4808C800 0x2E5F015A 0xFFFFFFFF 0xFB16E000 0xEBC4000F 0xF05C4308 + 0xF8044630 0x73F8C420 0x4808C800 0x2E5F0152 0xFFFFFFFF 0xFB17E400 0x0408E002 0x73F8C420 + 0x4C48C800 0x2E5F014C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E000 0x73F8C420 + 0x4C08C800 0x2E5F0144 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E004 0x73F8C420 + 0x4CC8C800 0x2E5F013C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E008 0x73F8C420 + 0x4CC8C800 0x2E5F0134 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0608E004 0x73F8C420 + 0x4DC8C800 0x2E5F012C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E010 0x73F8C420 + 0x4CC8C800 0x2E5F0124 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0404E001 0x73F8C420 + 0x4E04C800 0x2E5F011C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E009 0x73F8C420 + 0x4C08C800 0x2E5F0114 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E00C 0x73F8C420 + 0x4CC8C800 0x2E5F010C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0608E00C 0x73F8C420 + 0x4DC8C800 0x2E5F0104 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0404E000 0x73F8C420 + 0x4EC4C800 0x2E5F00FC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0x0408E006 0x73F8C420 + 0x4C08C800 0x2E5F00F4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E200 0xEBC4000F 0xF05C4318 + 0xF8044630 0x73F8C420 0x4808C800 0x2E5F00EA 0xFFFFFFFF 0xFB17E200 0xEBC4000F 0xF05C4308 + 0xF8044630 0x73F8C420 0x4808C800 0x2E5F00E2 0xFFFFFFFF 0xFB17E600 0x0408E000 0x73F8C420 + 0x4C48C800 0x2E5F00DC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E600 0x0408E002 0x73F8C420 + 0x4C48C800 0x2E5F00D4 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB17E600 0x0408E000 0x73F8C420 + 0x4CC8C800 0x2E5F00CC 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xE55CFF00 0xFB14E200 0xC858E230 + 0x73F8C420 0x4808C800 0x2E5F00C3 0xFFFFFFFF 0xFFFFFFFF 0xE55CFF00 0xFB14E400 0xC858E230 + 0x73F8C420 0x4808C800 0x2E5F00BB 0xFFFFFFFF 0xFFFFFFFF 0xE55CFF00 0xFB14E600 0xC858E230 + 0x73F8C420 0x4808C800 0x2E5F00B3 0xFFFFFFFF 0xFFFFFFFF 0xCF6443C1 0xD84FD3F8 0x73E52C14 + 0x00087820 0xFB04E43C 0xD848E278 0xB3FF0092 0xC8584A30 0xCF6443C1 0xD84FD3F8 0x73E52C14 + 0x00087820 0xB3FF0090 0xCB08E27C 0xFFFFFFFF 0xFFFFFFFF 0xFB04E43C 0xC858E230 0x73F8C420 + 0x4808C800 0x2E5F009C 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFB04E43C 0x73E52C14 0xC858E230 + 0x73F8C420 0x4808C800 0x2E5F0093 0xFFFFFFFF 0xFFFFFFFF 0xFB16E000 0x0004E008 0xEBCB0010 + 0xEC240001 0xD0785803 0xB3FFFE39 0x06040008 0xFFFFFFFF 0xFB16E000 0x0004E007 0xEBCB0010 + 0xEC240001 0xD0785803 0xB3FFFE31 0x06040008 0xFFFFFFFF 0xD9DFD2F8 0xFB045C3C 0x73E52C14 + 0xC8585A30 0x73F8C420 0x4808C800 0x2E5F007A 0xFFFFFFFF 0xD9DFD2F8 0xFB045C00 0x02005800 + 0xD9402838 0xB3FF0084 0xD8580038 0xFFFFFFFF 0xFFFFFFFF 0xD9DFD2F8 0xFB045C3C 0xC8585A30 + 0x73F8C420 0x4808C800 0xD9DF04F8 0x2E5F0061 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xBB040005 0x7C1CF903 0xB7240106 + 0xB7FF0065 0xFFFFFFFF 0xB724005F 0xB3FF0046 0x0606D008 0xBF040004 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xB724005D 0xFFFFFFFF 0xB3FF1443 0x7C1CF903 0xB7040003 0xBF24005F 0xB7FF00E6 + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x73F8C420 0x4808C800 0x2E5F0016 + 0xFFFFFFFF 0xC8584A30 0x73F8C420 0x4808C800 0x2E5F0011 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x7809FC10 0xE179FF00 0xB43F0012 0x0499980C + 0xB7DFFFFF 0xDF594E78 0xB3FF0013 0x1499980C 0xFFFFFFFF 0xE179FF00 0xB43F0007 0x06040008 + 0x06180000 0xDBC411BD 0xBC38FDB3 0x93E6FE22 0xB418FDAC 0xD9DFC038 0xB3FFFFFA 0x06040008 + 0xD9DFC038 0xB3FFFFEE 0xD9DFFA78 0xFFFFFFFF 0xFFFFFFFF 0xB3FFFFF3 0x06040008 0xFFFFFFFF + 0xFFFFFFFF 0x0485000C 0xD9DF3078 0xB7DFFFFE 0xE8450001 0x1485000C 0xF15633FF 0xEC2600FF + 0xB43F0008 0xCF1C4201 0xE541FFF0 0xDC4641B8 0xDC413078 0xDBC481DD 0xDC613878 0xBC7F0006 + 0xB4580003 0x2E3FFB76 0xFFFFFFFF 0x283FF800 0xFFFFFFFF 0x1400D0D0 0xCD180001 0xB3FFFD84 + 0x06040008 0xB7FF0F3E 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xB7FF09DA 0xF55900FF 0x0406D018 + 0x06040008 0xD2C6C9BE 0xB3FFFD79 0x1406D018 0xFFFFFFFF 0xB6440042 0x0401D008 0x04822800 + 0xE541FFF0 0xB7DFFFFE 0xD84208B8 0x14822800 0xB624000B 0x04822804 0xB7DFFFFF 0xE8420001 + 0x14822804 0xB6040003 0x283FF800 0xFFFFFFFF 0xCD84A009 0xB3FFFD66 0x06040008 0x0708C000 + 0xEA28FFFF 0xB03F0029 0xE8450004 0xDC280A38 0xB45F0006 0x04822800 0xB7DFFFFF 0xE8420001 + 0xB3FFFFF1 0x14822800 0xEA29FFFF 0xB03F001F 0xE8450004 0xDC290A78 0xB45F0006 0x04822800 + 0xB7DFFFFF 0xE8420001 0xB3FFFFE7 0x14822800 0xEA2AFFFF 0xB03F0015 0xE8450004 0xDC2A0AB8 + 0xB45F0006 0x04822800 0xB7DFFFFF 0xE8420001 0xB3FFFFDD 0x14822800 0xEA2BFFFF 0xB03F000B + 0xE8450004 0xDC2B0AF8 0xB45F0006 0x04822800 0xB7DFFFFF 0xE8420001 0xB3FFFFD3 0x14822800 + 0xB3FFFFD7 0xE8580008 0x04822800 0xB7DFFFFF 0xE8420001 0xB3FFFFCC 0x14822800 0x02012816 + 0x0402D00C 0x1518D048 0x1505D04B 0xD2C2F0BE 0x1201D04E 0xB204FFC7 0x1402D00C 0x283FF800 + 0xFFFFFFFF 0x6B02F901 0x2E3F0002 0xFFFFFFFF 0x0505D04B 0x0202D04E 0x02012816 0x0518D048 + 0xDC211078 0xBC3F0022 0x0401D008 0x04822800 0xE541FFF0 0xB7DFFFFE 0xD84208B8 0x14822800 + 0x0708C000 0xDC280A38 0xB85F000A 0xDC290A78 0xB85F000D 0xDC2A0AB8 0xBC5F0010 0x04822810 + 0xB7DFFFFF 0xE8420001 0xB3FF0011 0x14822810 0x04822804 0xB7DFFFFF 0xE8420001 0xB3FF000C + 0x14822804 0x04822808 0xB7DFFFFF 0xE8420001 0xB3FF0007 0x14822808 0x0482280C 0xB7DFFFFF + 0xE8420001 0xB3FF0002 0x1482280C 0xC65000C0 0x2C3FF000 0xFFFFFFFF 0x7C11F801 0xEBC3030C + 0xE0430008 0xCDD1A459 0xD84388F8 0x77631B00 0x7810FB00 0x04018040 0xB8210005 0xC6000028 + 0xC600001A 0xD340C03E 0x1400D018 0x2C3FF000 0xFFFFFFFF 0xFB16E000 0x0001E000 0x73F8C420 + 0xB7410006 0x0404E001 0xDBC4111D 0x4E04C800 0x2E5FFF39 0xFFFFFFFF 0x0404E000 0xCC441131 + 0x4E04C800 0x2E5FFF34 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x0401D018 0x121FD098 0xD2C1E07E + 0x1401D018 0x0407D00C 0xE547E000 0xB878001C 0x1407D00C 0xBCF80003 0xD2C1D87E 0x1401D018 + 0xCE198081 0xD9FF10B8 0xB03F000E 0x1202D04A 0x1418D040 0x0003D026 0x0006D03E 0xE94300E0 + 0xEC630040 0xB83F0003 0xCB06E180 0xE8460008 0x04033004 0x1403D044 0xCE188091 0x1202D098 + 0xB4B8001A 0xB4D80019 0xBC440003 0xB3FFFF22 0xCD992009 0x283FF800 0xFFFFFFFF 0xFB16E000 + 0xF15633FF 0x0402E000 0x0400D008 0xB8420004 0x0202E002 0x0202E004 0xE8420028 0xCF1C41C1 + 0xDC4639F8 0xD84238B8 0xC9820000 0x1400D008 0xBC98FFEC 0xD2C1F87E 0x1401D018 0xDBC481DD + 0xB3FFFFE8 0x1007D09C 0xFB16E000 0x0402E000 0xB8420003 0xDBC2809D 0xDBC2209D 0xFA181410 + 0xB3FFFFE2 0x1202D098 0x0616D038 0x0400D048 0xFB16E000 0x0403E000 0xB8430003 0xDBC3809D + 0xDBC2209D 0xB86000A4 0xD9DFFB78 0xE920FFFF 0xB43F003A 0x0604D040 0xCE000189 0xCF800241 + 0xEBCB0001 0xDBCB4AFC 0xF44B6301 0xF145531F 0xDBC52B5D 0xD94D6478 0xDBD1147D 0xE8440004 + 0x048727FC 0xB7DFFFFF 0xDC653BF8 0xB47F0011 0xDBC72B9D 0xDBCF2BDD 0xDC2B7BF8 0xB45F007C + 0xEC6F0001 0xB45F001E 0xB7FF0003 0xEC6F0001 0xB45F0015 0xD84E7C38 0xE8500001 0xD9506438 + 0xDBD0143D 0xD8448438 0xB3FFFFF9 0x141F8000 0xD8453238 0xDC283A38 0xB47F006F 0xD8448C38 + 0x040E8000 0xE3CB8000 0xDBCB52DC 0xD92E5AF8 0xBC3F006D 0xD9CE5BB8 0x140E8000 0xB3FF000F + 0x148727FC 0xD8448C38 0xE3CB8000 0xDBCB52DC 0x140B8000 0xB3FF0009 0x148527FC 0xD8448C38 + 0x040E8000 0xE3CB8000 0xDBCB52DC 0xD9CE5BB8 0x140E8000 0x148527FC 0xBCA0001E 0xF1426303 + 0xCFC082C1 0xEC2B0000 0xB43F0019 0xEC2B0002 0xBC3F0006 0xEC2C0000 0xB43F0063 0xEC2C0001 + 0xB43F0061 0xB7FF0012 0xEC2B0001 0xBC3F000A 0xEC2C0000 0xB43F005C 0xEC2C0003 0xB43F005A + 0xEC2C0002 0xBC3F000A 0xEBCD0001 0xB3FF0008 0xEBCC0001 0xEC2C0000 0xB43F0053 0xEC2C0003 + 0xB43F0003 0xEBCD0001 0xEBCC0003 0xCBCC1080 0xBCC00003 0xEBCD0001 0xFB001404 0xEC2D0001 + 0xBC3FFB7B 0x0400D018 0xDBC3825D 0xD2C0E83E 0x1400D018 0xBC430004 0xF8821D28 0xB3FF001C + 0x1403E000 0xF9021C20 0x020AE00A 0x121FE00A 0x1403E000 0xCF435485 0xEC520001 0x73FFFC01 + 0x6F60FC06 0x4012E000 0x7812FC01 0xEA52FFFF 0x1212E00A 0x0400D00C 0x0205D0C8 0xB460FB64 + 0xDDDF52B8 0xE94AFFFF 0xD8455138 0xCFE48181 0xD8443138 0xE944FFFF 0xD8449178 0xCFE58181 + 0xD8453178 0xE945FFFF 0xB7FF0004 0x0400D00C 0x0205D0C8 0xB460FB56 0xDBC380DD 0xDDDF4A78 + 0xE949FFFF 0xD8454938 0xCFE48181 0xD8443138 0xE944FFFF 0xD8441938 0xCFE48181 0xD8443138 + 0xE944FFFF 0xB3FFFB4A 0x1204D0C8 0xB3FFFF88 0xD9DF5BF8 0x148727FC 0xE3C14040 0xB3FF0005 + 0xE8410083 0x148727FC 0xE3C14040 0xE8410084 0x1401D0C0 0xD2DFB07E 0x1401D00C 0xC600001A + 0x0400D018 0xD340C03E 0x1400D018 0x2C3FF000 0xFFFFFFFF 0xBCA0FFB7 0xEBCD0001 0xB3FFFFB5 + 0xFBC01400 0x0401D00C 0xD2C1B07E 0xE541F000 0x1401D00C 0x1401D0C0 0xC600001A 0x0400D018 + 0xD340C03E 0x1400D018 0x2C3FF000 0xFFFFFFFF 0x020308D8 0x0204000C 0xEBC20001 0xF4431B01 + 0xF4440308 0xDBC2003C 0xDBC32094 0xF0421301 0x120008DA 0xCA02F800 0x9FFFF400 0x020710D2 + 0x02830800 0xB7DFFFFF 0x0205000A 0x0204000C 0xDC252178 0xB01F0008 0xCA03F980 0x02030008 + 0xDC4328F8 0xD84418F8 0xDBC320D5 0xB3FF0005 0xCA03F8C0 0xDC4428F8 0xDBC320D5 0xCA03F8C0 + 0xDC2719F8 0xBC1F0005 0x0201000A 0xEBC00000 0xB3FF0004 0x120110D0 0x12860800 0xEBC00001 + 0x9FFFF400 0x0202000A 0xDBC1207D 0xCA01F8C0 0x02000008 0xD8421878 0xDC210078 0xB57F0009 + 0xDC200838 0xBC3F0003 0xB3FF0005 0xEBC00000 0xDC401038 0xDC430038 0xCA00F800 0xB7FF0002 + 0xCA01F800 0x9FFFF400 0xEBC200C0 0xF0411B0E 0xE1C20050 0x02811800 0xB7DFFFFF 0xCA01F840 + 0xF0410B01 0xCA01F840 0x12811800 0x02010000 0xBF810007 0xEBC03020 0xCF811045 0xE1C0000C + 0xD8410078 0xE3C04000 0x73600B00 0x2C3F1000 0xFFFFFFFF 0x020600D2 0xEBC30004 0xDC2330F8 + 0xB81F0003 0x06040000 0xF0433300 0x120600D6 0x020900D0 0xDBC6223D 0xD84940F8 0xCA03F8C0 + 0x041B0800 0x06061000 0xDBC9F855 0xD86749F8 0xD8C609B8 0xF0400390 0xCA862180 0x02011008 + 0xDC211878 0xBC1F000E 0xDC4308F8 0xDC481879 0xCA01F840 0x71E10D00 0x55060000 0x06061000 + 0xD8400839 0xCA862180 0xF4430B01 0xCA01F840 0x71E10D00 0xB3FF0006 0x55060000 0xF4480B01 + 0xCA01F840 0x71E10D00 0x55060000 0x2E3F0048 0xFFFFFFFF 0x020700D2 0xEBC30004 0xDC2338F8 + 0xB81F0006 0x06040000 0xF0473300 0xF0433B00 0xF4461B04 0x120300D2 0x120700D6 0x020800D0 + 0xDBC720FD 0xD84819B8 0xCA06FA40 0x041B0800 0x06061000 0xDBC8F855 0xD86741F8 0xD8C609B8 + 0xF0400B90 0xCA862180 0x02081008 0xDC284A38 0xBC1F0010 0xDC494238 0xDC4340F9 0xCA03F8C0 + 0x71E31D00 0x55260800 0x06061000 0xD8411879 0xCA862180 0xF4481301 0xCA02F880 0x71E21500 + 0x55260800 0xF0420B01 0xB3FF000E 0x120100D0 0xF4431301 0xCA02F8C0 0x71E31D00 0x55260800 + 0xDC294278 0xBC3F0003 0xB3FF0006 0x121F00D0 0x02020840 0xF0430301 0xD8420038 0x12000840 + 0x9FFFF400 0x0400D010 0xEBC200C0 0x04000004 0x02010000 0xBB610008 0xE1C20050 0xEBC03020 + 0xCF811045 0xE1C0000C 0xD8410078 0xE3C08000 0x73600B00 0x2C3F1000 0xFFFFFFFF 0x0401D010 + 0xF05A0300 0xB3FFFF94 0x04020804 0x7C19F808 0x0200D0D4 0x040AD010 0x0610D000 0xF05A6390 + 0xBBE00008 0xEBCB0001 0xEBC00400 0x1200D090 0x0200D0D4 0xF5400301 0xB3FF0003 0x1200D0D4 + 0x121FD090 0x06086008 0x040D5004 0xCA888200 0x0200D0DA 0x1200D0DC 0x121F6002 0x041B5000 + 0x0202D0D8 0xEBC10100 0xDC211078 0xB01F0015 0x0400D0E4 0x0401D008 0x12016002 0x0401D00C + 0x02026000 0xCF818043 0xF1C10A08 0xD9C20878 0x12016000 0x0201D0D8 0xF4410B01 0xCA01F840 + 0x71E10D00 0x55280000 0xF05A0300 0xF04A0B00 0xA3FFFF91 0xF04D1300 0x2E3FFFC3 0xFFFFFFFF + 0x02026002 0xF0421201 0x12026002 0x6BFFFD00 0x55280000 0x0202D0D8 0xF4421201 0x1202D0D8 + 0x0202D0DC 0xF4421301 0x1202D0DC 0x0222D0DC 0xBC3F0019 0x0201D0D6 0xF4410B01 0x1201D0D6 + 0x0221D0D6 0xBC3F000A 0xA7FF1642 0xFFFFFFFF 0x1400D0E4 0xF05A0300 0xF04A0B00 0xA3FFFF76 + 0xF04D1300 0x2E3FFFB6 0xFFFFFFFF 0xF04C6310 0x121F6002 0x121F6000 0x06086008 0xA3FF1635 + 0xCA888200 0x1400D0E4 0x0200D0DA 0xB3FF0006 0x1200D0DC 0xD8690A78 0xA3FF162E 0xD8C8FA38 + 0x1400D0E4 0xDC2BFAF8 0xBC3FFFBE 0x281FF800 0xFFFFFFFF 0x7C19F808 0x040DD010 0x0402D008 + 0xF05A0B00 0xF04D0300 0x1202D0D8 0x040E6804 0xF05A8300 0x141CD0E4 0xA3FFFEE6 0xF04E7B0A + 0x1200D0D2 0xF04E0300 0xF04F0B00 0xA3FFFEEC 0xF05A1300 0xDC20F838 0xB43F0005 0xF04E0300 + 0xA3FFFF12 0xF04D0B00 0xB7FF0006 0x020180D2 0xA3FFFEFD 0xF04E0300 0x1200700A 0x12807800 + 0xEBC13000 0xE1C1000C 0x7C00F801 0xDBC0C03D 0xF1C00303 0x73600B00 0xEBC30001 0xF0500300 + 0xF04D0B00 0xF04E1300 0xB3FFFF13 0x120380D4 0x000600A4 0x000300A5 0x02080898 0x06040800 + 0xDC2619B8 0xF0405360 0xB83F003D 0xEBCB0000 0x101F00A4 0xEBCB0001 0x041B0000 0x06061000 + 0xD86741F8 0xD8C6F9B8 0xCA862180 0x0201100A 0xDC280A38 0xBC1F000E 0xDC4140B8 0xF4221340 + 0xB01F0006 0xEBC10040 0x6B3FFD00 0x55065000 0xB3FF002B 0x100100A5 0xF4422301 0x100200A5 + 0x71E42500 0xB3FF0026 0x55065000 0x02011008 0xDC414338 0xF42C6340 0xB01F0006 0xEBC30040 + 0x6B3FFD00 0x55065000 0xB3FF001D 0x100300A5 0x100C00A5 0x06081000 0xDC436078 0xCA01F840 + 0xCA882200 0xDBCC211D 0xDBC4217D 0xF44C2301 0xD84A2978 0x71E42500 0x55065000 0x0222100A + 0xB43F000F 0xDC2208B8 0xB41F0007 0xF4410B01 0xCA01F840 0x71E10D00 0x55082800 0xB3FF0008 + 0x100300A5 0x000100A5 0xF4422301 0xD8411078 0x100100A5 0x71E42500 0x55082800 0xF04B0300 + 0x9FFFF400 0xDC20F838 0xB03F0004 0x06082000 0xB3FF0003 0xEBCA0000 0x040A2094 0x14012094 + 0x0005209A 0x06061008 0xEBCB0100 0xDC4B2AF8 0xCA0BFAC0 0xCA864180 0x02091002 0x041B1800 + 0xDC695A38 0xB17F000C 0xD8412B38 0xF44B1B01 0xCA03F8C0 0x71E31D00 0x55066000 0xD86759F8 + 0xD8C6F9B8 0x16061008 0x12081002 0xB3FF000A 0x101F209A 0xF4491B01 0xCA03F8C0 0x71E31D00 + 0x55066000 0xF0431B01 0x121F1002 0xD84518B8 0x1002209A 0xDC20F838 0xBC3F000C 0xDC2A0AB8 + 0xB43F000A 0xCCAA40A1 0xDBC1401D 0xEBC10388 0xD9C200B8 0xE1C10008 0x7C00F905 0xDBC0603D + 0xD8410038 0x73620300 0x9FFFF400 0x04040808 0xDC20F838 0xF04133A0 0xB03F0013 0xE3C58000 + 0xCCA040E1 0xDBC0401D 0xEBC10388 0xD9C300F8 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 + 0x73630300 0x02011098 0x02002008 0xF0410B10 0xDC210078 0xBC3F0003 0xB3FF0003 0x121F200C + 0x1201200C 0x04813000 0xB7DFFFFF 0x04201090 0xB43F0009 0x14813000 0x7C01F801 0xDBC0C01D + 0x77000001 0x73E52901 0x263F003D 0xB3FF0003 0x77010801 0x14803000 0x9FFFF400 0x7C19F808 + 0x0400D010 0xCCBA4121 0xDBDA409D 0xEBC30388 0xF05A0B00 0xF04033A0 0xD9C41138 0xE1C30008 + 0xE3C58000 0x7C02F905 0xDBC260BD 0xD84310B8 0x73641300 0x7C02F801 0xEBC33000 0xE1C3000C + 0xDBC2C13D 0xD9C4D0B8 0x04873000 0xB7DFFFFF 0xDC27F9F8 0xBC3F0006 0x141FD090 0x14823000 + 0xF1C41303 0xB3FF000C 0x73621B00 0x141FD090 0x14023890 0x14823000 0xEBC00203 0xD9C40038 + 0x73601B00 0x77631B00 0x7800FB00 0x281FF800 0xFFFFFFFF 0x73E52901 0x04020008 0x0203100A + 0x0204100C 0xDC6320F8 0xB43F0003 0x04030000 0xBD030003 0x2E3F000A 0xFFFFFFFF 0xA3FFFF35 + 0x1204D098 0xDC20F838 0xB43F0003 0x2E3F002A 0xFFFFFFFF 0xB7FF0028 0xFFFFFFFF 0x7C19F808 + 0x0401D010 0xEBC90274 0xF05A4300 0xE1C900D0 0x04020808 0x7C03F801 0xEBC03000 0xE1C0000C + 0xDBC3C0FD 0xF1C31A01 0x73630300 0x04000800 0xBD000009 0xF0481300 0xA3FFFF95 0xEBC00000 + 0x161F4000 0xF0484308 0x161F4000 0x2C3F4800 0xFFFFFFFF 0x0200100A 0x0203100C 0xDC601838 + 0xBC3F0003 0x2E3FFFE6 0xFFFFFFFF 0xF0410300 0xF0480B00 0xA3FFFF0F 0x1203D098 0xDC20F838 + 0xB43F0003 0x2E3F0004 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF 0x7C19F808 0x040ED010 0xEBC10380 + 0xE1C10008 0xF04E1360 0x7C00F905 0xDBC0603D 0xD8410038 0x77600300 0x780DFB00 0xBC0D0003 + 0x2E3FFFF5 0xFFFFFFFF 0x000070A4 0xF04D0B00 0xF04E1B00 0xDBC02015 0xDBC0203D 0xD84203F8 + 0x02007802 0xF04F1300 0xF05A2300 0x1400D008 0x101FD09A 0xA3FFFF34 0xEBC00001 0x776D6903 + 0x02207802 0xB43F0013 0xEBD10380 0xE1D10008 0x7C00F905 0xDBC0603D 0xD8510038 0x77600300 + 0x780DFB00 0xBC0D0003 0x2E3F0018 0xFFFFFFFF 0xF04D0B00 0xF04F1300 0xF04E1B00 0xF05A2300 + 0xA3FFFF21 0xEBC00000 0x02207802 0xBC3FFFF1 0x02007800 0xF5400280 0x1200D09C 0x000070A4 + 0xF0400310 0x100070A4 0x02007800 0xBE800005 0xF04D0300 0xF04E0B00 0xA3FFFF45 0xF05A1300 + 0x2E3F0033 0xFFFFFFFF 0x7C19F808 0x040ED010 0xEBD10380 0xE1D10008 0x000070A4 0xF04E0B60 + 0xDBC02015 0xDBC0203D 0xD84103F8 0x0020D09A 0xB43F0009 0x040DD094 0xF04F1300 0xF04E1B00 + 0xF04D0B00 0xF05A2300 0xA3FFFEFF 0xEBC00000 0xB7FF000F 0x7C00F905 0xDBC0603D 0xD8510038 + 0x77600300 0x780DFB00 0xBC0D0003 0x2E3FFFE7 0xFFFFFFFF 0xF04D0B00 0xF04F1300 0xF04E1B00 + 0xF05A2300 0xA3FFFEF0 0xEBC00000 0x02207802 0xBC3FFFE7 0x02007800 0xF5400280 0x1200D09C + 0x000070A4 0xF0400310 0x100070A4 0x02007800 0xBE800005 0xF04D0300 0xF04E0B00 0xA3FFFF14 + 0xF05A1300 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0400D010 0x0208D098 0x0606D000 0x04020008 + 0xF05A0B00 0xEBC900D0 0x06041000 0xD8654178 0xE1C900D0 0xD8C4F938 0xCA843100 0x041B0000 + 0xF0411B9C 0x52241800 0x0203089C 0xBE830004 0x141F080C 0x2C3F4800 0xFFFFFFFF 0x02031008 + 0xF0482310 0xDC241938 0xBC3F0003 0xB3FF0003 0x121F0898 0x12040898 0xA7FFFE7E 0xFFFFFFFF + 0xDC20F838 0xB43F0003 0x2E3F0004 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF 0x0402D010 0x0401D008 + 0x000010A4 0xF0421360 0xF540030F 0xD8420038 0x02000002 0xD8410038 0xB3FFFFA4 0x1400D008 + 0x7C19F808 0xEBC10060 0xA3FF1494 0xEBC0007C 0x7C02F801 0x0400D088 0xF0401B28 0x04841800 + 0xB7DFFFFF 0x0001002C 0xCB02F800 0xDC210078 0xB43F000F 0xEBC10930 0xEBC000FF 0x1000D0ED + 0xE9C10000 0xDBC2C03D 0x241F0800 0x14841800 0xF1C00202 0xC60C3000 0x7360F300 0x777EF300 + 0x7800FB00 0x281FF800 0xFFFFFFFF 0xB3FF0007 0x14841800 0x7C19F808 0xA7FF14CD 0xFFFFFFFF + 0xB7FF0002 0xFFFFFFFF 0x7C19F808 0x0400D0AC 0x0401D088 0x0402D00C 0x04040000 0xF0410328 + 0x04032004 0xB9C20009 0xF0444B30 0xA7FF0494 0xFFFFFFFF 0xA3FF04FF 0x0400D0E4 0xC65000C0 + 0x2C3FF000 0xFFFFFFFF 0x0402D008 0xDBC2E89D 0xF4221304 0xBC3F0013 0xF0431B30 0x04821800 + 0xB7DFFFFF 0xF0421301 0xA3FF0485 0x14821800 0x04804800 0xB7DFFFFF 0xF0400301 0x14804800 + 0xA3FF04EC 0x0400D0E4 0x0400D00C 0xF1C00120 0x1400D00C 0xC600001A 0x2C3FF000 0xFFFFFFFF + 0xB7FF0002 0xFFFFFFFF 0x0602D0A0 0xEBC00040 0xF05A0BA8 0xE3DB2000 0xF4400301 0x71E00500 + 0x5D020800 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0400D0AC 0x0403D0A8 0x0408D088 0x04020000 + 0xF0430304 0xF0484B28 0x04011004 0xF0416334 0xF16308C0 0xB03F001D 0xF0425B30 0x0000D0EC + 0xF4400301 0xCB00F800 0xDC20F838 0xB03F0004 0x1000D0EC 0xB7FFFFE5 0xFFFFFFFF 0xF0490300 + 0xA3FF0457 0xF0480B00 0x04805800 0xB7DFFFFF 0xF0400301 0x14805800 0x04806000 0xB7DFFFFF + 0xF0400301 0x14806000 0xA3FF04BA 0x0400D0E4 0x0400D00C 0xF1C00120 0x1400D00C 0xC600001A + 0x2C3FF000 0xFFFFFFFF 0xEBC10997 0xF0491300 0xF0481B00 0xA3FF0474 0xE9C10000 0xF0490300 + 0xA3FF043F 0xF0480B00 0xB7FF0007 0xFFFFFFFF 0x7C19F808 0xA7FF1466 0xFFFFFFFF 0xB7FF0002 + 0xFFFFFFFF 0x7C19F808 0x0400D0AC 0x0408D0A8 0x04090000 0x02004000 0xF0486B04 0xB2000005 + 0x040A4804 0xF04D0300 0xB3FF03BB 0xEBC10000 0x02004000 0xBE200028 0xF5400240 0x12004000 + 0xF0480310 0x161F4010 0x161F0008 0x0400D008 0xDBC0183D 0xCEE04809 0x1200402C 0x0000D001 + 0x1000402E 0x0400D010 0x14004028 0x0000D015 0x1000402F 0xA3FF144D 0x0000402E 0xF0404B00 + 0xB800000A 0xF0416300 0xF04A0B2C 0x04800800 0xB7DFFFFF 0xF0400301 0x14800800 0xF04D0300 + 0xB3FF039D 0xEBC10000 0x02014000 0xEBC0F000 0xE1C03F00 0xF5410A08 0x12014000 0x0602D000 + 0xF04C0B00 0xD9420038 0xD9C04838 0xB3FF0035 0x16004020 0x00004014 0xF4200310 0xBC3F0009 + 0xF0490B34 0x04800800 0xB7DFFFFF 0xF0400301 0x14800800 0xF04D0300 0xB3FF0387 0xEBC10000 + 0x02004000 0xBE800019 0xA3FF1428 0x0000402E 0xF0404B00 0xB800000A 0xF0416300 0xF04A0B2C + 0x04800800 0xB7DFFFFF 0xF0400301 0x14800800 0xF04D0300 0xB3FF0378 0xEBC10000 0x02004000 + 0xEBC2F000 0xE1C23F00 0xF5400208 0x12004000 0x0600D000 0xF04C1B00 0xD9401038 0xD9C048B8 + 0xB3FF0010 0x16024020 0x0205402C 0x00034014 0x06004020 0xDBC5F915 0xD8612978 0x0402D0E4 + 0xDBC320FD 0xD8C02138 0xF4430301 0xE3DB2000 0x71E00500 0x55041000 0x2E3F0002 0xFFFFFFFF + 0x7C19F808 0x040AD0A8 0x0000D09D 0x0006D03B 0xF55C0BFF 0xF04A7B04 0xF1604308 0xB83F001B + 0xD9C60AF8 0x00005800 0x02015806 0x02025802 0xCF401005 0xCB00F800 0xDBC118FD 0xDC420038 + 0xCA00F840 0xCA03FB00 0xDC2CFB38 0xB83F0005 0x1201D0EA 0x02005018 0xB3FF0026 0xD84200F8 + 0x02005018 0x0022501C 0xB03F0007 0xD84008F8 0x0001501D 0xDBDCC01D 0xD84310B8 0xDC410038 + 0xDC4200F8 0xB7FF001B 0x0005D031 0x02035804 0xEBC0FFF8 0xD9C50878 0x02040802 0xF0431320 + 0xDC453078 0xDC420878 0xCA01F840 0xD9640338 0xB83F0006 0x1201D0EA 0x02005018 0xF4430B08 + 0xB3FF000C 0xD84100F8 0x02005018 0x0022501C 0xB03F0008 0xD84008F8 0x0001501D 0xDBDCC01D + 0xD84310B8 0xDC410038 0xDC420038 0xF4401B28 0xF4231901 0xB41F0004 0xF04F0300 0xB3FF031E + 0xEBC10001 0x0409D0A8 0xDC28FA38 0xB03F0006 0xF0490304 0x04015800 0xDBC1207D 0xB3FF0004 + 0xCFC14041 0x00015801 0xF1410B03 0xF4210B03 0xBC3F0009 0x02014800 0xBEC10003 0xB3FF030E + 0xEBC10001 0x02004800 0xFAB00195 0xB3FF000B 0x12004800 0xDC21F878 0xBC3F0008 0x02014800 + 0xBEA10003 0xB3FF0304 0xEBC10001 0x02004800 0xFAD00153 0x12004800 0x02005000 0xBE400005 + 0xF04C0300 0xF04B0B00 0xB3FF0061 0xF04F1300 0x020E5018 0xDC2E63B8 0xBC3F0043 0xDC2CFB38 + 0xBC3F001C 0xA3FF029F 0xF04B0300 0x0602D000 0x0401D0E4 0xCE820081 0x16020800 0x0403D008 + 0x0002501C 0x04040808 0xCD8300C1 0xDC4310B8 0xDC420038 0xC804003C 0x14000808 0x0400D008 + 0xCEE06001 0x1200080E 0x0000D001 0x1200080C 0x04000808 0xF5400040 0xF5400080 0x14000808 + 0x00005014 0xF0400301 0xB3FF00EC 0x10005014 0xA3FF02BB 0xF04B0300 0x00045014 0x0602D000 + 0x0405D0E4 0xDBC4213D 0xCE820081 0xD8452238 0x16024000 0x0401D008 0x04024008 0xCD810041 + 0xDC410078 0xC802087C 0x14014008 0x0401D008 0xCEE16041 0xD8410038 0x1200400E 0x0000D001 + 0x1200400C 0x04004008 0xF5400040 0xF5400080 0x14004008 0x00005014 0xF0400301 0x10005014 + 0x0000D09D 0xBF400003 0xB7FF00CC 0xFFFFFFFF 0x04004008 0xF5400040 0xF1C00040 0xB3FF00F6 + 0x14004008 0xDC2C7338 0xBC1F0004 0xF04F0300 0xB3FF02B1 0xEBC10001 0x120E501A 0x00005014 + 0xF04B0B00 0xF04C1300 0x10005015 0x00005014 0x10005012 0x00005014 0x10005013 0x00005014 + 0x0403D0E4 0xDBC0203D 0xD8430038 0x0003000C 0xF5431BF0 0xF5431B0F 0x1003000C 0x02035000 + 0xFA501A5B 0xB3FF006E 0x12035000 0x0408D0A8 0xF041A300 0xF0408300 0x0201401A 0xDC200C38 + 0xB81F0005 0xF0429300 0xF0520300 0xB3FF0292 0xEBC10001 0x000C4013 0x040ED0E4 0x000D4014 + 0xDBCC203D 0xD84E02B8 0x02015000 0x04005008 0xDBCD20BD 0xF5419B07 0xD8530038 0x000B4012 + 0x020FD0EA 0xCA00F800 0xDC300438 0xB01F0012 0xD84E1278 0xB7E10004 0xF0520300 0xB3FF027E + 0xEBC10001 0x100D4013 0x0002500C 0xF0490300 0xF0540B00 0xFB0D1108 0x1002500C 0x0003480C + 0xF0501300 0xC80360C8 0xF5431BF0 0xB3FF0044 0x1003480C 0x0000D09D 0xB7400004 0xF0520300 + 0xB3FF026D 0xEBC10001 0xD8507BF8 0xDC2F9BF8 0xB55F0004 0xF0520300 0xB3FF0267 0xEBC10001 + 0xF14D9B0F 0xDC2C5B38 0xBC3F000E 0x100D4012 0x0002500C 0xF0490300 0xF0540B00 0xF542130F + 0xD9C298B8 0x1002500C 0x0003480C 0xF0501300 0xFB0C1908 0xF5431B0F 0xB3FF0029 0x1003480C + 0x0000500C 0xCF800301 0xDBCC203D 0xD84E02B8 0x02005000 0xF5400B07 0xDC2F0BF8 0xB55FFFEA + 0x04005008 0xD8410038 0xCA00F800 0xDC300438 0xB41F0018 0x0002500C 0xF14D1B0F 0xDBC3203D + 0xF5420BF0 0xD9C10038 0x1000500C 0x0000480C 0xCF82E081 0xDBC2213D 0xFB020108 0xF0400B00 + 0xC8016048 0x1001480C 0x0405D0E4 0xF0490300 0xF0540B00 0xD8452178 0x0004280C 0xF0501300 + 0xF544230F 0xD9C418F8 0xB3FF0005 0x1003280C 0xF0520300 0xB3FF0230 0xEBC10001 0x040AD0A8 + 0xF0624300 0xB83F0017 0xF0406300 0xA3FF01D5 0xF0410300 0x0602D000 0xF0432B00 0xCE820101 + 0x16046000 0x02016000 0xF1C10B01 0x12016000 0x0402D008 0x0001501C 0xCD820081 0xDC420878 + 0xDC410038 0x14006008 0x0400D008 0xCEE06001 0x1200600E 0x0000D001 0xB3FF001D 0x1000600D + 0xA3FF01F7 0xF0410300 0x0001D09D 0xB7410004 0x0201D0EA 0xD8480878 0x12015016 0x0602D000 + 0xF0432B00 0xCE820101 0x16046000 0x12086000 0x0001D09D 0xBF410004 0x02016000 0xF1C10B01 + 0x12016000 0x0401D008 0xCD810041 0xDC410078 0x14016008 0x0401D008 0xCEE16041 0xD8410038 + 0x1200600E 0x0000D001 0x1000600D 0x00005014 0xF0400301 0x10005014 0x02015016 0x02005018 + 0xDC210078 0xBC3F0003 0xB7FF0033 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF 0x0000D09D 0x0402D0A8 + 0xBBA00005 0xF05A3B00 0x02001000 0xFAF00111 0x12001000 0x0203102C 0x06001020 0x00021014 + 0xDBC3F995 0x040438E4 0xDBC2217D 0xD86118F8 0xD8C030B8 0xF4450301 0xE3DB2000 0x71E00500 + 0x55222000 0x0000389D 0xB7000003 0xA7FF04E7 0xFFFFFFFF 0x2E3F0002 0xFFFFFFFF 0x7C19F808 + 0x0400D0AC 0x0408D0A8 0x04010000 0xF0480304 0xA3FF0205 0xF0415320 0xA3FF02AE 0x0400D0E4 + 0x04805000 0xB7DFFFFF 0xF0400301 0x14805000 0x0602D0A0 0xEBC00040 0xE3DB2000 0xF4400301 + 0x71E00500 0x5D224000 0xC65000C0 0x2C3FF000 0xFFFFFFFF 0x0408D0A8 0x0000D09D 0xBBA00005 + 0xF0484B04 0x02004000 0xFAF00111 0x12004000 0x0000D09D 0xF1C00310 0xA3FF04C4 0x1000D09D + 0x02014000 0xF0490300 0xF5410A80 0xA3FF01E6 0x12014000 0x121FD0E8 0x06024008 0xF05A03E8 + 0xE3DB2000 0x52220000 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0400D018 0x040CD0A8 0xF1C00004 + 0x1400D018 0x02006000 0xBE400006 0xEBC00E63 0xE9C00000 0xA3FF007C 0x1400D088 0xB7FF000E + 0xEBC00E51 0xE9C00000 0x1400D088 0x0400D0E4 0xEBC20388 0xE1C20008 0xCCA040E1 0xDBC0405D + 0xD9C308F8 0x7C01F905 0xDBC1607D 0xD8420878 0x73630B00 0xDBC040DD 0xCCBA4061 0xEBC20388 + 0x1400D0B8 0xD9C308F8 0xE1C20008 0x7C01F905 0xDBC1607D 0xD8420878 0x73630B00 0xEBC1F000 + 0x0602D000 0xE1C13F00 0x0006D09D 0x0004601C 0xBB860027 0xD9420978 0x04030008 0xF05C0808 + 0xDBC1C25D 0xCC430081 0xD84220B8 0xC80310BC 0x14020008 0x77810903 0x0201000E 0x06020000 + 0xF55C43FF 0xD86309F8 0xDBC1F995 0xD8C231B8 0xF1C73B00 0xEBC20100 0xDC424AB8 0xD9C94238 + 0xD9C628B8 0xF0471B00 0xF4442B01 0xE3C92000 0xF049DB00 0x71E52D00 0x55024000 0xF0443308 + 0xD86731F8 0xDC4A2178 0xD8C2F9B8 0xD8482238 0xF4451301 0xF049DB00 0x71E21500 0x55064000 + 0xF0410B08 0xB3FF002A 0x1201000E 0x04060008 0xDBDCC0DD 0xF55C13FF 0xCC460041 0xD8412078 + 0xC80609BC 0xEBC10100 0xDC4119F8 0x14060008 0xD9C21878 0xE3C82000 0x020A000E 0x06020000 + 0x04060008 0xDBCAFA55 0xD86352B8 0xD8C248B8 0xCC460181 0xDC2731F8 0xD9C228B8 0xB81F0003 + 0xF1CA4B00 0xF0473300 0xF0491B00 0xF4464B01 0xF048DB00 0x71E94D00 0x55020800 0x04020008 + 0xDBC208BD 0xDBE2F89D 0xB03F0003 0xD44731C2 0xEBC70000 0xDC27F9F8 0xB43F0003 0xD8413078 + 0xF0400310 0xDC27F9F8 0xBC3FFFE4 0x06026020 0x1602D000 0x0001602E 0x1001D001 0x0402D008 + 0x0201602C 0x02006018 0xF8611528 0xD8402038 0xC8020028 0xF808073B 0x1400D008 0x2E3F003B + 0xFFFFFFFF 0x0407D0A8 0x0401D0E4 0xCD1C0011 0x000A3815 0x00053813 0xF0402300 0x1400D0E4 + 0x00223815 0xB03F000D 0xEBC90000 0xF0414300 0x06024000 0xF0493301 0xCB06FA40 0x16022000 + 0x06024008 0xDC295278 0xF0484310 0x16022008 0xB01FFFF8 0xF0442310 0x00093812 0xDBC920BD + 0xD84111B8 0x06023000 0xDC292A78 0x16022000 0x06023008 0x16022008 0x121F2000 0x0002200C + 0xF54213F0 0xF542130F 0xB83F0007 0x1002200C 0x04022008 0xF1C21040 0x14022008 0xB3FF0006 + 0xCCA14121 0x0002300C 0xF0442310 0xB3FFFFEC 0xCF82E241 0xDBC1409D 0xEBC30388 0xD9C41138 + 0xE1C30008 0x7C02F905 0xDBC260BD 0xD84310B8 0x73641300 0xF15C10FF 0xD9C11078 0x77610903 + 0xF041E300 0x9FFFF400 0x7C19F808 0x0400D0AC 0x040BD0A8 0x0007D09D 0x04020000 0x0004D033 + 0x0405D0E4 0x04001004 0x0001581D 0xBB87001C 0xF05A3311 0x0408D008 0xDBDCC1DD 0xDC4139F8 + 0xCD880201 0xF0414B08 0xF55C0BFF 0xDC4839F8 0xD9C90878 0xF4473B30 0x12070804 0x02075800 + 0xBEA70006 0x04090800 0xCF096201 0xF1C84303 0xF8884D28 0x14090800 0x00085838 0x00075839 + 0xF55C0BFF 0xF0484308 0xD9C80A38 0xF0440B08 0x10074000 0xB3FF0019 0xCB01F900 0x0407D008 + 0xDBDCC0DD 0xF55C4BFF 0xCD870201 0xDC4119F8 0xD9C148F8 0xDC483878 0x12011802 0x02015800 + 0xBEA10004 0x00011801 0xF1C10B03 0x10011801 0x02011806 0xF5410A20 0x12011806 0x121F180A + 0x00011800 0xCF411045 0xF4410B01 0x73FFFC01 0x6F60FC06 0x40011800 0xF0423B20 0x04813800 + 0xB7DFFFFF 0xF0410B01 0x14813800 0xF0423B1C 0x04813800 0xB7DFFFFF 0xF0410B01 0x14813800 + 0x0001D09D 0xB7810004 0x7801FC01 0xF6410B00 0x1201180A 0x0401D00C 0xF1610810 0xBC3F0008 + 0x00025810 0xF55C1BFF 0xD9C418F8 0xDC4220B9 0x73FFFC01 0x6F60FC06 0x40021800 0x0209582C + 0x06025820 0x00075814 0xDBC9FA15 0xD86348F8 0xDBC721FD 0xD8C240B8 0xF4473B01 0xE3DB2000 + 0x71E73D00 0x55222800 0x77042103 0x121FD022 0x121FD024 0x101FD026 0x101FD021 0xDC21F878 + 0xB83F0008 0x141FD02C 0x7802FC01 0x0201581E 0xD84110B8 0xDBC2805D 0xD84208B8 0x1202D02A + 0x04015828 0x15013000 0x77410904 0x0001582F 0x1001D015 0x02015800 0xBEE10012 0xF0403B38 + 0x04813800 0xB7DFFFFF 0xF0410B01 0x14813800 0x0401D0AC 0x0401080C 0xBC010007 0x15013000 + 0x77410904 0xEBC1001A 0xE9C10000 0xB3FF0005 0x1501D01D 0x0401D00C 0xF1C10910 0x1401D00C + 0xA7FF012E 0xFFFFFFFF 0x0602D0A0 0xEBC00040 0xE3DB2000 0xF4400301 0x71E00500 0x5D225800 + 0x0400D018 0xF1C00020 0x1400D018 0x7C00F907 0xE3C10044 0x1200D09E 0x2C3F0800 0xFFFFFFFF + 0x0401D0A8 0x0002D09D 0x0004D03B 0xF1422B08 0x1004081D 0x02030818 0x0202D0EA 0xD84310B8 + 0x12020818 0x0402D00C 0xB462000E 0x0002D03E 0xF42213FF 0xBC3F0004 0x0002D03F 0xB3FF0003 + 0x10020810 0x10020810 0x0203D02A 0x0202081E 0xD84218F8 0xDBC3809D 0xD84310F8 0x1203081E + 0xDC25F978 0xB43F0016 0x0003D031 0xF55C13FF 0xDC432038 0xF4200328 0xB83F0005 0xD9C310B8 + 0xF0440306 0xB3FF0007 0x10000838 0x0000D021 0xF0400301 0xDBC0183D 0xDC430038 0x10000838 + 0x00021000 0xDBDCC01D 0xDC430038 0x10020839 0x1000081C 0xB3FF0009 0xEBC00008 0x00030000 + 0xDBDCC09D 0xEBC00000 0xCF4310C5 0xD84418F8 0xDC4310B8 0x1002081C 0x9FFFF400 0x0404D0A8 + 0x0201D0EA 0x0003D09D 0x02022018 0x0005D03B 0xD8420878 0x12012018 0x0401D00C 0xB0610008 + 0xF1431308 0x0203D02A 0x0201201E 0xD84118F8 0xDBC3805D 0xD84308F8 0x1203201E 0xDC22F8B8 + 0xB43F0007 0x0001D031 0xDBDCC01D 0xF0410B08 0xDC410038 0xB3FF0007 0xCB00F800 0x00010000 + 0xDBDCC01D 0xCF411045 0xD8450878 0xDC410038 0x9FFFF400 0x0402D0AC 0x040AD0A8 0x0608D0A0 + 0x040D1000 0xEBCE0040 0xF0416300 0xA3FF002E 0xF04D5B30 0xE3DB2000 0xF44E0301 0x71E00500 + 0x5D285000 0x04805800 0xB7DFFFFF 0xF0400301 0x14805800 0xDC2CFB38 0xB43F0006 0xF04D0B28 + 0x04800800 0xB7DFFFFF 0xF0400301 0x14800800 0xA3FF00C8 0x0400D0E4 0x0400D00C 0xF1C00120 + 0x1400D00C 0xC600001A 0x2C3FF000 0xFFFFFFFF 0x7C02F801 0xDBC2C0BD 0xD9C2D0F8 0x04840000 + 0xB7DFFFFF 0xDC24F938 0xB83F0004 0x141FD0E0 0xB3FF000C 0x14830000 0x140320E0 0x241F0800 + 0x14830000 0xF1C20202 0xC60C3000 0x7360F300 0x777EF300 0x7800FB00 0x281FF800 0xFFFFFFFF + 0x9FFFF400 0x04820000 0xB7DFFFFF 0x0421D0E0 0xB43F0008 0x14820000 0x7C02F801 0xDBC1C01D + 0x77000001 0x203FF800 0xB3FF0003 0x77021001 0x14810000 0x9FFFF400 0x7C02F801 0xDBC2C0BD + 0xD9C2D0F8 0x04840000 0xB7DFFFFF 0xDC24F938 0xB83F0004 0x141FD08C 0xB3FF000C 0x14830000 + 0x1403208C 0x241F0800 0x14830000 0xF1C20202 0xC60C3000 0x7360F300 0x777EF300 0x7800FB00 + 0x281FF800 0xFFFFFFFF 0x9FFFF400 0x7C03F801 0xDBC3C0BD 0xD9C2D0B8 0x04840000 0xB7DFFFFF + 0xDC24F938 0xB83F0005 0x141FD08C 0x1003082C 0xB3FF0005 0x14820000 0x101FD0ED 0x1402208C + 0x14820000 0x9FFFF400 0x04820000 0xB7DFFFFF 0x0421D08C 0xB43F0008 0x14820000 0x7C02F801 + 0xDBC1C01D 0x77000001 0x203FF800 0xB3FF0003 0x77021001 0x14810000 0x9FFFF400 0x04840000 + 0xB7DFFFFF 0x0423D08C 0xB43F000B 0x002218ED 0xDBC3C09D 0x1002082C 0xB03F0008 0x14840000 + 0x7C00F801 0x77021001 0x203FF800 0xB3FF0003 0x77000001 0x14830000 0x9FFFF400 0x7C03F801 + 0xDBC3C0FD 0xD9C3D138 0x04860000 0xB7DFFFFF 0xDC26F9B8 0xB83F0004 0x141FD0E0 0xB3FF0019 + 0x14840000 0x140430E0 0x241F0800 0x14840000 0xEBC03000 0xF1C30A02 0xE1C0000C 0x73610300 + 0x77600300 0x7800FB00 0x04811000 0xB7DFFFFF 0x0420D08C 0xB43F0008 0x14811000 0x7C01F801 + 0xDBC0C01D 0x77000001 0x203FF800 0xB3FF0003 0x77010801 0x14801000 0x281FF800 0xFFFFFFFF + 0x9FFFF400 0x7C04F801 0xDBC4C13D 0xD9C4D178 0x04870000 0xB7DFFFFF 0xDC27F9F8 0xB83F0004 + 0x141FD0E0 0xB3FF001C 0x14850000 0x140538E0 0x241F0800 0x14850000 0xEBC03000 0xF1C40A02 + 0xE1C0000C 0x73610300 0x77600300 0x7800FB00 0x04841000 0xB7DFFFFF 0x0421D08C 0xB43F000B + 0x002008ED 0xDBC1C01D 0x1000182C 0xB03F0008 0x14841000 0x7C01F801 0x77000001 0x203FF800 + 0xB3FF0003 0x77010801 0x14811000 0x281FF800 0xFFFFFFFF 0x9FFFF400 0x04020004 0xF0403B1E + 0xF0423201 0x02813800 0xB7DFFFFF 0x0205001C 0xCA01F840 0xF4411B01 0xDBC5087D 0xD84208B8 + 0xCA03F900 0x02031000 0xDBC4087D 0xD8460878 0x12030800 0x0203D09E 0xF0450B01 0xF1410B7F + 0x12031000 0x1201001C 0x12843800 0x9FFFF400 0x0401D0AC 0x04010800 0x04010804 0x05030819 + 0xF0412318 0x04011800 0xDC400838 0xDBC0409D 0x00802000 0xB7DFFFFF 0xCB00F800 0xF4400301 + 0xCB00F840 0xD8430838 0xC900F800 0x10020000 0x10812000 0x9FFFF400 0x0200D09E 0x77600107 + 0xEBC20388 0xCCBA4061 0xDBDA401D 0xD9C100F8 0xE1C20008 0x0400D0B8 0x7C01F905 0xDBC1607D + 0xD8420878 0xA3FFFFE3 0x73630B00 0x041ED094 0x9FFFF400 0xFFFFFFFF 0x281FF800 0xFFFFFFFF + 0x0200D09E 0x77600107 0xEBC10388 0xCCBA40A1 0xDBDA401D 0xD9C200B8 0xE1C10008 0x0403D0B8 + 0x7C00F905 0xDBC0603D 0xD8410038 0x73620300 0xEBC0EFE8 0xF15C10FF 0x0401D00C 0xE1C0077E + 0xD9610038 0xB03F000E 0xD9C31238 0xF55C23FF 0xDBDCC0DD 0xEBC000FF 0xF54813FF 0xDBC8C05D + 0xD9C41938 0xD9C20878 0xDC401838 0x6F60FC06 0x77610C01 0x43002000 0x781FFC00 0xA3FFFFBD + 0xF55C00FF 0x77684103 0x041ED094 0x9FFFF400 0xFFFFFFFF 0x281FF800 0xFFFFFFFF 0x04080000 + 0x1400D0AC 0x0420D094 0xB43F0003 0xB7FFFA85 0xFFFFFFFF 0x101FD09D 0xF0480B24 0x04800800 + 0xB7DFFFFF 0xF0400301 0x14800800 0x000BD03B 0xF55C4BFF 0xD8495BB8 0x00007000 0xCF80E3C1 + 0xF42F7B04 0xB83F000C 0xDBC9C29D 0x02027006 0x020D7002 0xEBC11FFF 0xD9620878 0xB83F0015 + 0xF1420220 0x0001D09D 0xF1C10B02 0xB3FF0011 0x1001D09D 0x000CD031 0x02037004 0xEBC1FFF8 + 0xD8496038 0x02020002 0xF0436B28 0xD9620878 0xB83F0005 0xF1420301 0x0001D09D 0xF1C10B02 + 0x1001D09D 0x0001D09D 0xF1C10B08 0x1001D09D 0xDC20F838 0xB43F0017 0x0000D09D 0xF1C00320 + 0x1000D09D 0x02004018 0xDC2D0378 0xBC1F0003 0xB7FF0167 0xFFFFFFFF 0xF42F7B04 0xBC3F0006 + 0x00007000 0x02017002 0xCF401005 0xB3FF0005 0xDC410038 0x02017004 0xDC4C5838 0xDC410038 + 0xF1600307 0xB43F0003 0xB7FF0159 0xFFFFFFFF 0x0401D008 0xD84D5838 0xDC4050B8 0xC8011028 + 0x1400D008 0x0400D00C 0xF422133C 0xCD810041 0xB81F0019 0xF1400010 0xDC20F838 0xBC3F0016 + 0xDC211078 0xB43F0014 0x00017000 0xD8495038 0xD8420038 0xCF411045 0xDC4D0878 0xBBE10008 + 0xDC4008B8 0xD8420838 0x101F0000 0x73FFFC01 0x6F60FC06 0xB3FF0006 0x40011000 0xF4410301 + 0x73FFFC01 0x6F60FC06 0x40001000 0x7800FC01 0x1200D02A 0x02004002 0x0604D048 0x06024010 + 0xD9450138 0xDBC4103D 0xD8630078 0xD8C2F838 0x1600D0D8 0x02034000 0x06004008 0xEBC20010 + 0xCF8300C1 0xDBC418FC 0xD8611978 0xD8C0F938 0x1604D0D0 0x1002D0EC 0xC6000F05 0xF1DE0180 + 0x2C3F0000 0xFFFFFFFF 0x7C19F808 0x0400D088 0xEBC10F0D 0xE9C10000 0xA3FFFE98 0xF0400324 + 0xB7FF0007 0xFFFFFFFF 0x7C19F808 0xA7FF0EF0 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF 0x0602D0D8 + 0xEBC00010 0xF5432B0F 0xF0422300 0xF05A0BA8 0xE3DB2000 0xF4400301 0x71E00500 0x5D040800 + 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0401D0AC 0x0400D088 0x0403D0A8 0x04020800 0xF0404324 + 0xF16300C0 0x04011004 0xF0425330 0xB03F001D 0xF0415B34 0x0000D0EC 0xF4400301 0xCB00F800 + 0xDC20F838 0xB03F0004 0x1000D0EC 0xB7FFFFE4 0xFFFFFFFF 0xA3FFFE95 0xF0480300 0x04805000 + 0xB7DFFFFF 0xF0400301 0x14805000 0x04805800 0xB7DFFFFF 0xF0400301 0x14805800 0x0400D00C + 0xF1C00120 0x1400D00C 0x0400D018 0xF5400001 0x1400D018 0xC600001A 0x2C3FF000 0xFFFFFFFF + 0x0600D0D8 0xF0481300 0xF141030F 0xEBC10F4E 0xD8630038 0xA3FFFE9A 0xE9C10000 0xA3FFFE7B + 0xF0480300 0xB7FF0007 0xFFFFFFFF 0x7C19F808 0xA7FF0EAF 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF + 0x0400D0AC 0x04000000 0x04000004 0x05010019 0xF0406318 0x04080800 0x00806000 0xB7DFFFFF + 0xCB00FA80 0xD8415038 0xC900F800 0x00090000 0xF4294BFF 0xBC3F0007 0x108A6000 0x0400D0AC + 0x04000000 0x04000004 0xB3FF00E4 0xF0400328 0xF04A0301 0xCB00F800 0x10806000 0xDBC9403D + 0xD8480138 0x1404D0E4 0x0402D0AC 0x0600D0D0 0xEBC30001 0x04021000 0x02021000 0xCF820081 + 0xDBC310BC 0xF4421301 0xE3DB2000 0x71E21500 0x55002000 0x2E3F0002 0xFFFFFFFF 0x0400D0AC + 0x0001D01C 0x0408D0E4 0x040C0000 0xF05A1350 0xF0481B00 0x02006000 0xF4412301 0xCF80C141 + 0xF8041630 0xF8051E30 0x48021800 0xF0410307 0xF5404B07 0x780BFC10 0xDC2B2AF8 0xBC3F0015 + 0xD8484878 0x02200FFE 0xB03F0009 0xF4415302 0xF46B5B01 0xBC3F0003 0xB7FF00AB 0xFFFFFFFF + 0xD84A4AB8 0x02205000 0xBC3FFFFA 0x0600D0D0 0xDC4A48B8 0xF0421302 0xD86110B8 0xD8C0F838 + 0xDC624078 0xF0491300 0xB3FF002C 0xDCC0F838 0xF0481300 0xDC2BFAF8 0xB03F0006 0xF44B5B01 + 0xD84248B8 0xF06B0300 0xB83FFFFE 0xF44B5B01 0xD8424838 0x022B07FE 0xB83F0009 0xF4405302 + 0x0600D0D0 0xD86110F8 0xF0491300 0xD8C0F838 0xDC634078 0xB3FF0019 0xDCC0F838 0xF44A0B02 + 0x0000D09D 0xBBC0000B 0x02010800 0x7C00F907 0xCA00F800 0xDC210078 0xB43F0006 0xD9C10038 + 0xBEE00004 0x0000D09D 0xF1C00304 0x1000D09D 0x77610907 0x04026004 0xDBCB307D 0xDBC1F815 + 0x06021008 0xD8630878 0x120BD09E 0xD8C20038 0xB3FF003F 0x1600D0A0 0x0403D0AC 0xF0404300 + 0xF0417300 0x04001800 0xF0426B00 0x040A0004 0x04005004 0xF04A831E 0xF0400A01 0x02808000 + 0xB7DFFFFF 0xCA00FBC0 0xDBCF083D 0xD8410038 0x022B0000 0xBC3F0003 0xB3FF0069 0x128F8000 + 0xF04F0301 0xCA00F800 0x12808000 0xF05A1350 0xD8426838 0x120B07FE 0x7C03F907 0xF4400B04 + 0xF04E4B00 0xF44D0301 0xE3C42000 0x12030800 0xF044DB00 0x71E00500 0x55281000 0xD86E6838 + 0xD8C8F9B8 0xF4600B02 0xE3C2C800 0xEBC30000 0x1602D0C0 0xF4C60300 0x1600D0C8 0xDBCB317D + 0x06005008 0xD86128F8 0xDBC5F895 0xD8C010B8 0xF05A0BC0 0xEBC0000F 0xF044DB00 0x71E00500 + 0x55220800 0x120BD09E 0x1602D0A0 0x7C00F905 0x10005010 0x0000D09D 0xF1C00380 0xA3FF006B + 0x1000D09D 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0401D088 0xA3FFFDAE 0xF0410328 0x0600D0D8 + 0x0402D0A8 0xF141030F 0xA3FFFD87 0xD8620038 0x0600D0D8 0xF1411B0F 0x0404D0A8 0x0600D0D8 + 0xEBC20004 0xD86418F8 0xE3DB2000 0xF4421301 0x71E21500 0x5D201800 0xEBC00010 0x1000D0EC + 0x0400D018 0xB8400005 0xEBC1001C 0xA3FF0D8B 0xF1C10320 0xB7FF0003 0xA3FF0D88 0xF0410300 + 0xC6500002 0x2C3FF000 0xFFFFFFFF 0x0400D0AC 0x04010000 0xF0411328 0x04801000 0xB7DFFFFF + 0xF0400301 0x14801000 0xF0411330 0x04801000 0xB7DFFFFF 0xF0400301 0x14801000 0x0400D00C + 0xF1C00120 0x1400D00C 0x0400D018 0xF5400001 0x1400D018 0xC600001A 0xF1DE0180 0x2C3F0000 + 0xFFFFFFFF 0xA3FFFE03 0x0400D0E4 0x0400D0AC 0x04000000 0xB3FF0009 0xF040032C 0xA3FFFDFD + 0x0400D0E4 0x0400D0AC 0x04000000 0x04000004 0xB3FF0002 0xF0400324 0x0404D0A8 0x0602D0D8 + 0xF1430B0F 0xF0404B00 0xA3FFFD47 0xD8640838 0x0600D0D8 0xF1411B0F 0x0404D0A8 0x0600D0D8 + 0xEBC20004 0xD86418F8 0xE3DB2000 0xF4421301 0x71E21500 0x5D201800 0x04804800 0xB7DFFFFF + 0xF0400301 0x14804800 0x0400D0AC 0x04000000 0xF0400B30 0x04800800 0xB7DFFFFF 0xF0400301 + 0x14800800 0x0400D00C 0xF1C00120 0x1400D00C 0x0400D018 0xF5400001 0x1400D018 0xC600001A + 0x2C3FF000 0xFFFFFFFF 0x0401D0AC 0x0200D09E 0xEBC43068 0x04010800 0xDBC018FD 0xE1C4000C + 0x04010804 0xF05A2B00 0x05020811 0xD84218F8 0xC903F8C0 0x77642300 0xF0423304 0x04843000 + 0xB7DFFFFF 0xF4242301 0xBC3F000C 0xEBC40000 0x10843000 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0x04873000 0xB7DFFFFF 0xF4273B01 0xB43FFFF7 0xEBC40001 0x14843000 + 0x0004289D 0xB7040028 0x02051802 0xDC250178 0xBC3F0004 0x05000811 0xB3FF0033 0x141F0004 + 0xBF64000D 0x02001800 0xDBC0183D 0xD8420038 0x12050002 0x02001802 0x02031800 0xDBC0183D + 0xD8420038 0x12030000 0x05000811 0xB3FF0026 0x141F0004 0x04040800 0xBC040004 0x05000811 + 0xB3FF0021 0x141F0004 0x02241800 0xBC3F0006 0x7800FB00 0x14001804 0x05000811 0xB3FF001A + 0x141F0004 0xDBC4193D 0xD8422138 0x12052002 0x02041802 0x02051800 0xDBC4193D 0xD8422138 + 0x12052000 0x121F1800 0x02041002 0x12041802 0x02241002 0xBC3F0003 0xB3FF0006 0x12001000 + 0xDBC4193D 0xD8422138 0xC904F900 0x12002000 0x12001002 0x7800FB00 0x14001804 0x05000811 + 0x141F0004 0x9FFFF400 0x050DD0F1 0x0020D0F9 0xEBC20001 0x050ED0F5 0x05006811 0x05016811 + 0xEBC43068 0xD3DF1083 0xE1C4000C 0xF0401B04 0xEBCF0000 0x04801800 0xB7DFFFFF 0xF4200301 + 0xBC3F000C 0xEBC00000 0x10801800 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF + 0x04851800 0xB7DFFFFF 0xF4252B01 0xB43FFFF7 0xEBC80001 0x14881800 0x02200800 0xDBC018FD + 0xD84118F8 0xC903F8C0 0x04031804 0x77642300 0x7805FB00 0xB03F0003 0x04046814 0xEBC80000 + 0xDC28FA38 0xBC3F0006 0xDC4518F8 0xDC241938 0xB41F005E 0xDC22F8B8 0xBC3F005C 0x05006811 + 0xF04E0BF0 0x141F0004 0x04800800 0xB7DFFFFF 0xF4200301 0xBC3F000C 0xEBC00000 0x10800800 + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x04820800 0xB7DFFFFF 0xF4221301 + 0xB43FFFF7 0xEBCB0001 0x148B0800 0xEBCA0384 0xEBC93000 0xEBD10000 0xF04E93F0 0xE1CA0008 + 0xE1C9000C 0xB3FF0022 0xF0516300 0xDBCC203D 0xD84E0078 0x05000805 0xDC206838 0xBC3F001A + 0x00000808 0xF4200301 0xBC3F0003 0xB3FF0016 0x101F0808 0xDC28FA38 0xB43F0010 0x0001D0F0 + 0x040070F4 0xDBC1C07D 0x77600105 0x7C00F905 0xDBC0603D 0xD84A0038 0x737A0300 0xF1C10201 + 0x73604B00 0x77694B00 0x7800FB00 0xF04C8B00 0xB3FF0005 0xF04B7B00 0x100BD0F9 0xB3FFFF9B + 0x141F9000 0xF04C0301 0xCB00FB00 0xDBCC203D 0xD84E0038 0x0001D0F4 0x00000000 0xDC210078 + 0xBC3FFFDB 0xDC2FFBF8 0xB43F0015 0xF44C0301 0xDBC0203D 0xD84E0078 0x04020800 0xDBD1203D + 0xD84E0038 0x14020000 0x04020804 0x14020004 0x04020808 0x14020008 0x0402080C 0x1402000C + 0x0000D0F4 0x10000800 0x7C01F801 0x0000D0F4 0x77000001 0x203FF800 0x77610801 0x141F70F0 + 0x2E1FFF7A 0xFFFFFFFF 0xDBC018BD 0xD84110B8 0xC902F940 0x12002802 0x02042800 0xDBC030FD + 0xDBC3F895 0xDBC4193D 0xD8412138 0xC904F900 0x121F2002 0x02042800 0x12040800 0x05016811 + 0x141F0804 0x1200D09E 0x06006808 0xD86118F8 0xD8C010B8 0x1602D0A0 0x00006810 0x77600105 + 0xCCBA4061 0xDBDA401D 0xD9C10078 0xC6080388 0x7C00F905 0xDBC0603D 0xD85E0038 0x73610300 + 0x2E3F0002 0xFFFFFFFF 0x0602D0A0 0xEBC00040 0xF05A0BA8 0xE3DB2000 0xF4400301 0x71E00500 + 0x5D020800 0x2E3F0002 0xFFFFFFFF 0x7C19F808 0x0400D0A8 0xF0404304 0xF16000C0 0xB43F0003 + 0xB7FFFFF2 0xFFFFFFFF 0xEBC11183 0xF0480300 0xA3FFFC00 0xE9C10000 0xB7FF0002 0xFFFFFFFF + 0x7C19F808 0x040AD0A8 0x050BD0F1 0xEBC80001 0x02015000 0xB2010003 0xF04A0304 0xEBC80000 + 0x02015000 0x060ED0A0 0xF04F8300 0xF5410A80 0x12015000 0xA3FFFC04 0xEBCC0040 0xDC28FA38 + 0xBC3F0006 0xE3DB2000 0xF44C0301 0x71E00500 0xB3FFFF2E 0x5D2E5000 0x04005820 0xF05A13E8 + 0xF0400301 0x14005820 0x121FD0E8 0x06005008 0xE3DB2000 0x52201000 0xA3FFFC88 0xF04B0300 + 0x02005000 0xBE800008 0xF04E0300 0xF0500B00 0xE3DB2000 0xF44C1301 0x71E21500 0xB3FFFF1B + 0x5D205000 0x04005800 0xF56000FF 0xB43F0033 0x00025014 0x06005020 0x0203502C 0xF4421301 + 0xDBC220BD 0xD86118F8 0xD8C0F938 0xDBC2F855 0xD86310B8 0xD8C408F8 0xF0620B08 0xEBC00040 + 0x1000D0F8 0xD8C3F838 0xF05A13F8 0xE3C42000 0xF044DB00 0x51201000 0x06025020 0xEBC60001 + 0xE1C60030 0x1602D000 0x0002502E 0xF04E0300 0xF0500B00 0x1002D001 0x0403D008 0x0202502C + 0xF8621D28 0xF0431300 0xF808173B 0x1406D00C 0xF0421B00 0x02025018 0xC80310A8 0x1402D008 + 0xF044DB00 0xF44C1301 0x71E21500 0x5D205000 0x04025800 0xEBC00010 0xF0400B00 0x1402D010 + 0xA3FF0BCE 0x101FD015 0x04005800 0xE3C10054 0x2C200800 0xFFFFFFFF 0x00025014 0xE3C42000 + 0xF04E0300 0x1002D0EE 0x06025020 0xF0500B00 0x1602D0D0 0x0002502E 0x1002D0EF 0x00055014 + 0x0206502C 0x06025020 0xF4452B01 0xDBC521FD 0xDBC6F955 0xD86331B8 0xD8C228B8 0xDBC7F8D5 + 0xD86731F8 0xD8C311B8 0x1606D0D8 0xF044DB00 0xF44C1301 0x71E21500 0x5D205000 0x0602D0D8 + 0xF05A03C0 0xEBC1000F 0xF044DB00 0x71E10D00 0x55020000 0x2E3F0002 0xFFFFFFFF 0x7C19F808 + 0x0200D0CC 0x0602D0C0 0xEBC8000F 0xA3FF0C2B 0xCB00F800 0x0000D0EE 0xF4400301 0xCB00F800 + 0xDC20F838 0xB03F000E 0x1000D0EE 0x0602D0D8 0xEBC00000 0xF4630B10 0xDCC20038 0x1600D0D8 + 0x0602D0D8 0xF05A03C0 0xE3DB2000 0x71E84500 0x55020000 0x2E3FFFEA 0xFFFFFFFF 0x0602D0D0 + 0xA3FF0C16 0x0000D0EF 0xB7FFFEA8 0xFFFFFFFF 0x7C01F801 0xF05A13F0 0xEBC50000 0xCB01F8C0 + 0x04811000 0xB7DFFFFF 0xF4210B01 0xBC3F000C 0xEBC10000 0x10811000 0xFFFFFFFF 0xFFFFFFFF + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x04841000 0xB7DFFFFF 0xF4242301 0xB43FFFF7 0xEBC10001 + 0x14811000 0xB3FF0010 0x0004D000 0xDBC5207D 0xD85A08B8 0x00211008 0xBC3F0006 0x77042001 + 0x203FF800 0x77031801 0xEBC10001 0x10011008 0xF0450B01 0xCB01F940 0xDBC5207D 0xD85A0878 + 0x00040800 0xDC241938 0xBC3FFFF1 0xDC25F978 0xBC3F0016 0xEBC23058 0xE1C2000C 0x77621300 + 0x7801FB00 0xF5410B80 0x73611300 0x0401D0F4 0x77610905 0xEBC20384 0xE1C20008 0x7C01F905 + 0xDBC1607D 0xD8420878 0x737A0B00 0xDBC3C0BD 0xEBC13000 0xF1C21201 0xE1C1000C 0x73620B00 + 0x77610B00 0x7801FB00 0x141FD0F0 0x281FF800 0xFFFFFFFF 0x7C07F801 0x0020E004 0xBC3F010C + 0xEBC03058 0xE1C0000C 0x77600300 0x780BFB00 0xB70B0077 0xEBC20380 0xE1C20008 0x7C01F905 + 0xDBC1607D 0xD8420878 0x77610B00 0x7803FB00 0xB403006C 0x7C01F905 0xDBC1607D 0xD8420878 + 0x77610B00 0x7804FB00 0xB404005D 0x7801F900 0xBC01004E 0x7802F900 0xBC02003B 0xCB02FB40 + 0x100D1800 0x101F1808 0x0005E008 0xCB01FB00 0x10051804 0x0505E009 0x15051805 0x15041801 + 0x100C1810 0x7C08F905 0xEBC610C5 0xE9C60000 0x140818F4 0x141F18F0 0x1406208C 0x04082018 + 0xDBC1C17D 0xEBC63000 0xF1C84002 0x14082018 0x100D20F0 0x0508E009 0xF1C52A02 0xE1C6000C + 0x150820F1 0x100C20F4 0x150320F5 0x101F20F9 0x73653300 0x77663300 0x7805FB00 0xDBC2C17D + 0xF1C52A02 0x73653300 0x77663300 0x7805FB00 0x77010801 0x73E31904 0x261FFF7E 0x77021001 + 0x73E42104 0x77642103 0x261FFE20 0xE3C23000 0x73E21103 0x77673801 0xEBC23078 0xE1C2000C + 0x77621300 0x7803FB00 0xCB011840 0x73611300 0x0002E008 0xF1CB0B80 0xFB220884 0xB3FF0126 + 0x73610300 0x77010801 0x261F012C 0x203FF800 0x77673801 0xEBC10384 0xE1C10008 0x7C00F905 + 0xDBC0603D 0xD8410038 0x73630300 0x7C00F905 0xDBC0603D 0xD8410038 0x73640300 0xEBC00001 + 0xB3FF0115 0x1000E005 0xEBC10384 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x73630300 + 0x7C00F905 0xDBC0603D 0xD8410038 0x73640300 0xEBC00001 0xB3FF0108 0x1000E005 0xEBC10384 + 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x73630300 0xEBC00002 0xB3FF00FF 0x1000E005 + 0xEBC00002 0xB3FF00FC 0x1000E005 0xEBC03078 0xE1C0000C 0x77600300 0x7801FB00 0xEBC030C0 + 0xE1C0000C 0xF1410BFF 0xDBC1C0BD 0x73620300 0xEBC03080 0xE1C0000C 0x77600300 0x7800FB00 + 0xEBC03084 0xE1C0000C 0x77600300 0x7803FB00 0x0002E008 0xEBC60000 0xCDA3A151 0xCB01F800 + 0xF0461B00 0xB3FF0013 0xEBC80001 0xDBC3213D 0xD8452378 0x050C6805 0x0504E009 0xDC2C2338 + 0xBC3F0004 0x0004E008 0xF0483300 0x10046804 0xDBC3213D 0xD8452138 0x00042004 0xDC2220B8 + 0xBC1F0002 0xF0441300 0xF0431B01 0xCB03F8C0 0xDBC3213D 0xD8452138 0x00042000 0xDC202038 + 0xBC3FFFEB 0xDC26F9B8 0xB43F0007 0xDBC2107D 0xEBC03058 0xCB215844 0xE1C0000C 0xB3FF00C6 + 0x73610300 0xF4231B0E 0xB43F0056 0xEBC60380 0xE1C60008 0x7C04F905 0xDBC4613D 0xD8462138 + 0x77642300 0x7804FB00 0xB404004B 0x7808F900 0xBC080040 0xEBC610C5 0xE9C60000 0x1406208C + 0x040D2018 0xDBC8C33D 0xEBC63000 0xF1CD6802 0x140D2018 0x100820F0 0x050DE009 0xF1CC6202 + 0xE1C6000C 0x150D20F1 0x100020F4 0x150520F5 0x101F20F9 0x736C3300 0x77663300 0x7800FB00 + 0x77084001 0x73E42104 0x261FFD90 0xE3C03000 0x73E00103 0x77673801 0xDBC210BD 0xEBC03058 + 0xCB225884 0xE1C0000C 0x73620300 0xF04513F0 0x04801000 0xB7DFFFFF 0xF4200301 0xBC3F000C + 0xEBC00000 0x10801000 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x04861000 + 0xB7DFFFFF 0xF4263301 0xB43FFFF7 0xEBC00001 0x14801000 0xDBC3203D 0xD84501B8 0x10083000 + 0x101F3008 0x0002E008 0xF0430301 0xDBC0203D 0x10023004 0x0502E009 0xD8450038 0x15023005 + 0x15043001 0x10010000 0xB3FF007B 0x141F28F0 0xEBC10384 0xE1C10008 0x7C00F905 0xDBC0603D + 0xD8410038 0x73640300 0xEBC00001 0xB3FF0072 0x1000E005 0xEBC00002 0xB3FF006F 0x1000E005 + 0xEBC00004 0xB3FF006C 0x1000E005 0xF4200301 0xBC3F0066 0xEBC03058 0xE1C0000C 0x77600300 + 0x780BFB00 0xB70B0004 0xEBC00003 0xB3FF0062 0x1000E005 0xEBC03078 0xE1C0000C 0x77600300 + 0x7801FB00 0xEBC030C0 0xE1C0000C 0xF1410BFF 0xDBC1C0BD 0x73620300 0xEBC03080 0xE1C0000C + 0x77600300 0x7800FB00 0xEBC03084 0xE1C0000C 0x77600300 0x7800FB00 0xEBC60000 0xF0461300 + 0xCDA0A151 0xF0451BF0 0x04801800 0xB7DFFFFF 0xF4200301 0xBC3F000C 0xEBC00000 0x10801800 + 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0xFFFFFFFF 0x048C1800 0xB7DFFFFF 0xF42C6301 + 0xB43FFFF7 0xEBC00001 0x14801800 0xCB01FB00 0xB3FF0012 0xEBC30000 0xDBC3207D 0xD8450BB8 + 0x050D7005 0x0501E009 0xDC2D0B78 0xBC3F0005 0x00087000 0xF0403300 0xB3FF0006 0xF0432300 + 0x00017004 0xDC2208B8 0xBC1F0002 0xF0411300 0xF0430B01 0xCB01F8C0 0xDBC3207D 0xD8450878 + 0x00010800 0xDC2C0B38 0xBC3FFFEC 0xDC26F9B8 0xB43F0019 0xDBC4203D 0xD8450038 0x00000008 + 0xF4200301 0xB03F0003 0xEBC10001 0xEBC10000 0xDC21F878 0xBC3F0004 0x77084001 0x203FF800 + 0x77073801 0xDBC4203D 0xD8450038 0xEBC10002 0xF4231B01 0xB03F000B 0x10010008 0xDBC2107D + 0xEBC03058 0xCB215844 0xE1C0000C 0xB3FF0005 0x73610300 0x0000E005 0xF1C00303 0x1000E005 + 0xB3FF0005 0x141F28F0 0x0000E005 0xF1C00305 0x1000E005 0x0602D000 0xF0632B04 0xF05C0304 + 0xD8C2F938 0xE3DB2000 0x52240000 0xE3C00054 0x2C3F0000 0xFFFFFFFF 0x7C00F801 0xDBC0C03D + 0xF1C00201 0xC60C3000 0x7360F300 0x777EF300 0x7800FB00 0x281FF800 0xFFFFFFFF 0x7C19F808 + 0x0401D00C 0xF5410850 0x1401D00C 0x1400D0D8 0x0400D018 0xBC400027 0x0402D008 0xF55C23FF + 0xDBC4C0DD 0xEBC00100 0xDBC2E85D 0xF4210B04 0xD8441A78 0xB83F0011 0xDC401A38 0xA3FF0985 + 0xF05A0300 0x0204000E 0x06020000 0x0606D000 0xDBC4F855 0xD8632178 0xD8C20938 0xCA843100 + 0x04000008 0xCC400001 0xDC204038 0xBC1F000B 0xB3FF000A 0xF0404300 0x0600D000 0xCEE260C1 + 0xCD820081 0xD8611978 0xD8C0F938 0xDC2240B8 0xBC1F0002 0xF0424300 0xF4484301 0xE3DB2000 + 0x71E84500 0x55244800 0x2E3F0029 0xFFFFFFFF 0xB7FF0027 0xFFFFFFFF 0xF0401314 0xD84008F8 + 0xDC2218B8 0xBC1F0021 0x00201000 0xB43F001F 0x00001000 0xF5600B80 0xB43F0003 0xF4210B01 + 0xBC3F0003 0xB3FF0015 0xF0421301 0xBF000006 0x00001001 0xF4200302 0xB81F0010 0xD0420081 + 0xB7FF0012 0xEBC1030C 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x77600300 0x7802FB00 + 0xF0420330 0x04810000 0xB7DFFFFF 0xF0410301 0xB3FF0006 0x14801030 0xDC2218B8 0xBC1F0003 + 0x00201000 0xBC3FFFE3 0x9FFFF400 0x7C19F808 0x0409D0D8 0x0002D03B 0x0600D000 0xF55C63FF + 0xD84C12B8 0x1600D0C0 0x0600D008 0x1600D0C8 0x00005000 0xCF80E001 0xF4200304 0xB83F0024 + 0xDBCCC35D 0x04014800 0x02005006 0xBA20000C 0xF1410830 0xF4210810 0xB43F0009 0xDC21F878 + 0xBC3F0004 0xC600001E 0x2C3FF000 0xFFFFFFFF 0xC600001A 0x2C3FF000 0xFFFFFFFF 0x00035000 + 0xF04A0306 0xDC4268B8 0x1400D0D4 0x02005002 0xCF431385 0x0401D0C8 0xDC407038 0xC8010028 + 0x1400D0C8 0x04004800 0xB8A00017 0xD84E13F8 0xEBC00014 0xDC207038 0xBC1F0013 0xF04A0300 + 0xA3FFFFAE 0xF04E0B00 0xB7FF000F 0x0005D031 0xD84C2AF8 0xF04B0302 0x1400D0D4 0x02035004 + 0xDC451138 0xF4440328 0x0401D0C8 0xDC430038 0xDC4568B8 0xC8010028 0x1400D0C8 0xF0447308 + 0xF0427B08 0x0400D008 0xEBC1000C 0xE1C10008 0xF808073B 0x1400D008 0x0400D0D0 0x02000008 + 0xDC407038 0xF5401B07 0x7C00F905 0xDBC0603D 0xD8410038 0x77600300 0x7804FB00 0xF15F0301 + 0xEBC10007 0xCEE4A089 0x1002D0FA 0xCF04E089 0x1002D0FB 0xCEE42089 0x1002D0FC 0x140FD0DC + 0x140ED0E0 0x1403D0E4 0x140AD0E8 0x140BD0EC 0x1001D0F8 0x0401D008 0xDBC0F83D 0xCEE16041 + 0xD84D0878 0x1201600E 0x04016008 0xC801787C 0xF5410840 0xF5410880 0xD9C10038 0x14006008 + 0x04804800 0xB7DFFFFF 0xF0400301 0x15804801 0x00005000 0xCF80E001 0xF4200306 0xBC3F0002 + 0xF44F7B08 0x0400D0C8 0xDBC0E85D 0xF4210B04 0xBC3F0019 0xA3FF08CF 0xF05A0300 0x0202000E + 0xEBC10388 0xDBDA40FD 0xD84278B8 0x1202000E 0xDBDA409D 0x04040008 0xC8A310A0 0xE1C10008 + 0xCC4400C1 0xDC4378F8 0xC80418FC 0x14030008 0x1400D0F0 0x7C00F905 0xDBC0603D 0xD8410038 + 0x73620300 0x7C00F911 0xF5400301 0xB3FF000C 0x77600111 0xCEE06001 0xD8407838 0x1400D0CC + 0x0602D0C0 0xF0430B00 0xCE820001 0x16006010 0x04006018 0xF5400080 0x14006018 0x0402D018 + 0xEBC00010 0xF0400B00 0xF5421060 0xA3FF08D3 0x1402D018 0xB7FF0002 0xFFFFFFFF 0x7C19F808 + 0x0400D0C8 0xDBC0E81D 0xF4200304 0xB83F0004 0x040AD0D8 0x0000D0F8 0xB7E00012 0x04005000 + 0xBC800003 0x00005008 0x1000D001 0xA3FF091F 0x0000D001 0xF0404300 0xB8000004 0xF0414B00 + 0xB7FF01B9 0xFFFFFFFF 0x0600D000 0xCA880200 0x1608D000 0x0000D0F8 0xF1C00302 0x1000D0F8 + 0x0602D000 0xF0432B00 0xF55C03FF 0xCE820101 0x16040000 0x0401D0D8 0xF04A1304 0x0001080C + 0x1201000C 0x04811000 0xB7DFFFFF 0xF0410B01 0x14815004 0x0401D0C8 0xDBC1E85D 0xF4210B04 + 0xBC3F0003 0xB7FF002E 0xFFFFFFFF 0xB7FF0002 0xFFFFFFFF 0x0401D0E4 0x0403D0CC 0x1203001E + 0x04030018 0xF5431840 0xF1C31840 0x14030018 0x0403D0C8 0xCD830101 0xDC212078 0xBC1F0011 + 0x04030018 0xC80308FC 0x14030018 0x0406D0D8 0xEBC30001 0x0006300C 0x1206001C 0x0407D0C8 + 0xCD870181 0xDC4609B8 0xC8073128 0x1404D0C8 0x0404D0CC 0xD8440878 0xB3FF0008 0x1401D0CC + 0x04010018 0xEBC30000 0xC801207C 0x14010018 0x0001D0C1 0x1201001C 0x04000018 0x0401D0DC + 0x0404D008 0xCC400001 0xD8410038 0xC8040068 0xF0430300 0xB3FF00B2 0x1401D008 0x040AD0F0 + 0xF0406B00 0xEBCC0000 0xF05A43C8 0xE3CEFFF0 0xE7CFFFF0 0x06025000 0x16426810 0x0200500C + 0x1200680C 0x0200500E 0x1200680E 0x04006808 0xF5400080 0x14006808 0x0401D0C8 0x04005008 + 0xCD810081 0xCC400041 0xDC2208B8 0xBC1F0003 0xC800103C 0x14005008 0x04005008 0x040BD0E4 + 0xCC400041 0xD84C0838 0xDC205838 0xBC1F002B 0x04006808 0xC800083C 0x14006808 0x04005008 + 0xDBC0083D 0xDBE0F81D 0xB43F0011 0x04016808 0xEBC00000 0xF5410840 0xF1C10840 0x14016808 + 0xF0411300 0x0401D0DC 0x0403D008 0xCC420081 0xD8416078 0xD8420878 0xD94370B8 0xD9417878 + 0xD9C20878 0xB3FF007E 0x1401D008 0x04006808 0xF5400040 0x14006808 0x04015008 0xF04A5310 + 0x140AD0F0 0x04024000 0x04006808 0xDBC110FD 0xCD820041 0xCC400001 0xDC410038 0xD9427078 + 0xD9407838 0xD9C10038 0xDBC3105D 0x14004000 0xB3FFFFC1 0xD84C0B38 0xDC2B02F8 0xBC3F003B + 0x04006808 0xE3C2FFF0 0xE7C3FFF0 0xF5400040 0xF1C00840 0x04005008 0xF8400800 0x14016808 + 0x0400D0DC 0x0404D008 0xCC410041 0xD8406038 0xD8410038 0xD9441078 0xD9401838 0xD9C10038 + 0x1400D008 0x04005008 0xDBC0083D 0xDBE0F81D 0xB43F0003 0xB3FF0023 0xEBC00000 0xF04A0B10 + 0x1401D0F0 0x0406D0C8 0x04046808 0xCD860141 0xCC440101 0xDC452138 0xD9461178 0xD94418B8 + 0xD9C510B8 0x1402D0C8 0xDBC260BD 0xDBE2609D 0xB83F0014 0xEBC00001 0x04026808 0xEBC00000 + 0xF5421040 0x14026808 0x04026818 0xF14210C0 0xF5421040 0xF1C21040 0x14026818 0x06020800 + 0x16026810 0x0201501C 0x1201681C 0x0201501E 0x1201681E 0x04016818 0xF5410880 0x14016818 + 0xB7FF002F 0xFFFFFFFF 0x04026808 0xDC4B6038 0xC802003C 0x14006808 0x0403D0D8 0xE7C2FFF0 + 0xEBC00001 0x0003180C 0x1203680C 0x04036808 0x0204500E 0xCC4300C1 0xD84418F8 0x1203500E + 0x04055008 0x04036808 0xCC450101 0xCC4300C1 0xDC4418F8 0xC80518FC 0x14035008 0x04036808 + 0xF5431840 0xF1C31840 0x14036808 0xF0432300 0x0403D0DC 0x0405D008 0xCC440101 0xD84360F8 + 0xD84418F8 0xE145FFF0 0xD94310F8 0xD9C518F8 0x1403D008 0x0405D0C8 0x04036808 0xCD850101 + 0xCC4300C1 0xDC4418F8 0xCC050129 0xD9431078 0xD9C40878 0xB3FF0002 0x1401D0C8 0x0002D0F8 + 0x0403D0E4 0x0406D0D4 0x0401D0E0 0x0408D0E8 0xBBE20004 0xF55C23FF 0xB3FF000D 0x121F3000 + 0x00024000 0xDBC318DD 0xCF82E081 0xF4221306 0xB83F0004 0xCA03F8C0 0xDBC318BD 0xCA02F8C0 + 0x02023000 0xD84218B8 0x12023000 0x00064000 0x0403D0DC 0xCF86E081 0xF4221304 0xB83F0019 + 0xDC4308B8 0xDBC110DD 0xCB03F8C0 0xC80618C8 0xDC20F838 0xB03F0006 0x10034000 0x02034006 + 0xF1C31A20 0xB3FF0005 0x12034006 0x02034006 0xF5431A20 0x12034006 0x0403D008 0xF4413301 + 0xCD830041 0xDC411078 0x12014002 0x121F400A 0x73FFFC01 0x6F60FC06 0xB3FF0028 0x40064000 + 0x0401D0EC 0xDC20F838 0xB03F0006 0x101F0801 0x02030802 0xF1C31B01 0xB3FF0005 0x12030802 + 0x02030802 0xF5431B01 0x12030802 0x0003D0F8 0xBFE30015 0x0403D0D8 0x0506180D 0x04833000 + 0xB7DFFFFF 0x14030804 0xF0431B01 0x14833000 0xDC4140F8 0xF4231B28 0xBC3F0003 0xB3FF0006 + 0xF0483B06 0x0003D021 0xF0431B01 0xDBC318FD 0xDC4119F8 0x00063800 0xEBC3002C 0x10060800 + 0x10033800 0x0401D008 0xCD810041 0xDC411078 0xF4410B28 0x12014004 0x0001D0F8 0xDBC4C19D + 0xF5410B01 0x1001D0F8 0x0401D0DC 0x0407D008 0x0602D000 0xD8460878 0xCEE761C1 0xD86339F8 + 0xD8C2F9B8 0xF4411301 0xE3DB2000 0x00014000 0xCF81E041 0xF4210B04 0xBC3F0004 0x7801FC01 + 0xF6410B00 0x1201400A 0x71E21500 0x55262000 0x0021D0FC 0xB43F0010 0x0401D018 0xBC610003 + 0x0201D098 0x1201D048 0x0007D0FA 0x0602D000 0x0004D0FB 0xDBC7F995 0xD86339F8 0x0001D0FC + 0xD8C231B8 0xD85A20F8 0xF4411301 0x71E21500 0x55261800 0xDC20F838 0xB43F0008 0xEBC014DA + 0xE9C00000 0x1400D08C 0x0400D018 0xF1C00002 0xB3FF0008 0x1400D018 0x0000D0F8 0xF1C00308 + 0x1000D0F8 0x0400D018 0xF5400002 0x1400D018 0x0400D018 0xBC000013 0x0401D00C 0xEBC00004 + 0x1401D0B4 0x0401D0E8 0x0002D09C 0x00010800 0xCF81E041 0xF4210B04 0xB83F0006 0xDBC280BD + 0xE1C08000 0xD9C20038 0xB3FF0006 0x1400D00C 0xEBC00029 0xE1C08000 0xD9C20038 0x1400D00C + 0xB7FF0002 0xFFFFFFFF 0x7C19F808 0x0000D0F8 0xBF800015 0xEBC00010 0xA3FF0720 0xEBC10000 + 0x0400D0C8 0xDBC0E81D 0xF4200304 0xBC3F000E 0x0400D0F0 0xDBDA40BD 0xEBC10388 0xDBC0401D + 0xC8A200A0 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x73620300 0x7C00F911 0xF1C00301 + 0x77600111 0x0000D0F8 0xBF800004 0xE3C000D4 0x2C3F0000 0xFFFFFFFF 0xE3C00054 0x2C3F0000 + 0xFFFFFFFF 0x0000D0F8 0xBFC0000B 0xF5400302 0x1000D0F8 0x0400D0D8 0xF0400B0A 0x00800800 + 0xB7DFFFFF 0xCB00F800 0xF0400301 0xCB00F800 0x10800800 0x2E3FFE2A 0xFFFFFFFF 0x04020804 + 0x04030808 0xEBC6000F 0xF042230C 0x04822000 0xB7DFFFFF 0x14020808 0xD9C218B8 0x14822000 + 0x041B0800 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 + 0x04020008 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 0x55220800 0xE3C00054 + 0x2C3F0000 0xFFFFFFFF 0x04030808 0xB603001B 0xEBC20200 0xCF0310C5 0xE1C2000C 0xD84310B8 + 0x77621300 0x7804FB00 0xB4040005 0xEBC20200 0xE1C2000C 0x77621300 0x7804FB00 0x04060804 + 0xCF848081 0xCB02F8C0 0xEBC200FF 0xDBC218FC 0xCB04F940 0xCB03F900 0xCF068081 0xCB02F880 + 0xD94428F8 0xDD4220B8 0xD9C310B8 0xCB02F880 0xF9023420 0x14060804 0x04040804 0xEBC20090 + 0xB8240020 0xE1C2000C 0xEBC3008C 0xE1C3000C 0x73641B00 0xEBC40000 0x77621300 0x7805FB00 + 0xDBC410FD 0xD84118F8 0xF0442301 0x14051810 0xF4242310 0xB17FFFF9 0xF0421304 0xEBC6004F + 0x041B0800 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 + 0x04020008 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 0xB3FF002B 0x55220800 + 0xEBC3FFFF 0xEBC6008C 0xD9641978 0xE1C6000C 0xB03F0011 0xEBC70000 0xDB5F293D 0xEBC3001F + 0xDC4320F8 0xCB03F8C0 0xDB451978 0xDBC710FD 0xD84118F8 0xF4442310 0xDBC4113D 0x04031810 + 0xD8422138 0x73632300 0xDC25F978 0xB83FFFF3 0xF0473B01 0x04020804 0x73623300 0x04020808 + 0xB6020011 0xEBC60007 0x041B0800 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 + 0xD9C218B8 0x14020008 0x04020008 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 + 0x55220800 0x9FFFF400 0x04040804 0xEBC31100 0xF1441003 0xDBE2C09D 0xB83F0068 0xE1C3000C + 0xBC240035 0xEBC211FC 0xE1C2000C 0x73641300 0x77621300 0x7802FB00 0xBC420014 0xF1C41020 + 0x14020804 0xEBC60007 0x041B0800 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 + 0xD9C218B8 0x14020008 0x04020008 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 + 0xB3FF00BD 0x55220800 0xEBC20000 0x77631B00 0x7805FB00 0xDBC2113D 0xD8412138 0xF0421301 + 0x14052010 0xF4221317 0xB17FFFF9 0xF0431B04 0xEBC60063 0x041B0800 0xF4263307 0xB43F0006 + 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 0x04020008 0x06040000 0xCEE26001 + 0xD86500F8 0xD8C4F8B8 0x71E63500 0xB3FF00A2 0x55220800 0xEBC211FC 0xF1C41840 0xE1C2000C + 0x73631300 0x04260808 0xB03F0012 0xEBC20000 0xDB5F317D 0xEBC3001F 0xDC4328F8 0xCB03F8C0 + 0xDB4619B8 0xDBC210FD 0xD8411938 0xEBC31100 0x04042010 0xDBC5117D 0xE1C3000C 0xD84518F8 + 0x73641B00 0xDC26F9B8 0xB83FFFF2 0xF0421301 0x04030804 0xEBC211FC 0xE1C2000C 0x73631300 + 0x77621300 0x7802FB00 0xBC420083 0xF1C31020 0x14020804 0xEBC60007 0x041B0800 0xF4263307 + 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 0x04020008 0x06040000 + 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 0xB3FF0071 0x55220800 0xF4221301 0xBC3F0037 + 0xBC24001F 0xEBC211FC 0xE1C2000C 0x73641300 0xEBC20000 0x77631B00 0x7805FB00 0xDBC2113D + 0xD8412138 0xF0421301 0x14052010 0xF4221308 0xB17FFFF9 0xF0431B04 0xEBC6002F 0x041B0800 + 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 0x04020008 + 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 0xB3FF0050 0x55220800 0xEBC511FC + 0xF16422FF 0xE1C5000C 0xB03F0011 0xEBC60000 0xDB5F20BD 0xEBC0001F 0xDC401038 0xCB00F800 + 0xDB440138 0xDBC6103D 0xD8410038 0xF4421310 0xDBC210BD 0x04000010 0xD84310B8 0x73601300 + 0xDC24F938 0xB83FFFF3 0xF0463301 0x04000804 0xB3FF0039 0x73602B00 0xF4221302 0xBC3F0036 + 0xBC24001F 0xEBC211FC 0xE1C2000C 0x73641300 0xEBC20000 0x77631B00 0x7805FB00 0xDBC2113D + 0xD8412138 0xF0421301 0x14052010 0xF4221302 0xB17FFFF9 0xF0431B04 0xEBC60017 0x041B0800 + 0xF4263307 0xB43F0006 0x04040008 0xF0461B01 0xCC0400A9 0xD9C218B8 0x14020008 0x04020008 + 0x06040000 0xCEE26001 0xD86500F8 0xD8C4F8B8 0x71E63500 0xB3FF0018 0x55220800 0xEBC511FC + 0xF16422FF 0xE1C5000C 0xB03F0011 0xEBC60000 0xDB5F20BD 0xEBC0001F 0xDC401038 0xCB00F800 + 0xDB440138 0xDBC6103D 0xD8410038 0xF4421310 0xDBC210BD 0x04000010 0xD84310B8 0x73601300 + 0xDC24F938 0xB83FFFF3 0xF0463301 0x04000804 0x73602B00 0x9FFFF400 0xE3C00054 0x2C3F0000 + 0xFFFFFFFF 0xEBC00001 0x70E00101 0x2E3FFFFB 0xFFFFFFFF 0xEBC00001 0x70E00101 0x2E3F0002 + 0xFFFFFFFF 0x0401E004 0x0400E008 0x0401080C 0xF040130C 0x04801000 0xB7DFFFFF 0xD9410038 + 0x14801000 0xE3C00054 0x2C3F0000 0xFFFFFFFF 0x0401E004 0x0400E008 0x06020808 0x16020008 + 0x06020800 0xB3FFFFE8 0x16020000 0x0401E008 0x0400E004 0x0402080C 0xF14118C0 0xF4231840 + 0xB83F000D 0xF0413300 0xDBC1C19D 0xEBC40001 0xEBC30020 0xDBC4313C 0xF4442301 0xDC4330F8 + 0xDBC4193C 0xDBC2097D 0xD94220F8 0xDD4520B8 0xD9C310B8 0xF14618C0 0xF4231880 0xBC3F0010 + 0x04040804 0xEBC50001 0xEBC3001F 0xDBC4C21D 0xEBC40020 0xDC4341B8 0xDBC209DD 0xDBC5417C + 0xF4452B01 0xDC4440F8 0xDBC5193C 0xDAC731B8 0xD94220F8 0xDD4620B8 0xD9C310B8 0xF0401B0C + 0x04841800 0xB7DFFFFF 0xD94220B8 0x14821800 0x06020008 0x16020808 0x06020000 0xB3FFFFBE + 0x16020800 0x04020008 0x04010004 0xEBC00001 0x14011000 0x70E00101 0x2E3FFFC6 0xFFFFFFFF + 0x04020008 0x04010004 0xEBC00001 0x14011000 0x70E00101 0x2E3FFFC6 0xFFFFFFFF 0x7C19F808 + 0x0002E003 0xF05A0300 0xF4221304 0xB95F000F 0xF05C0B00 0xDC22F8B8 0xB57F0025 0x97420001 + 0xB7FF0013 0xFFFFFFFF 0xB7FF0014 0xFFFFFFFF 0xB7FFFF9D 0xFFFFFFFF 0xB3FF0013 0xF0410300 + 0xB7FF0014 0xFFFFFFFF 0xF4221313 0xBD5F0018 0xF4221310 0xB57F0016 0xF4221310 0xB43F0010 + 0xF4221313 0xB43F0010 0xB7FF0011 0xA7FFFE47 0xFFFFFFFF 0xB7FF000E 0xA7FFFEAC 0xFFFFFFFF + 0xB7FF000B 0xA7FFFFD0 0xFFFFFFFF 0xB7FF0008 0xA7FFFE23 0xFFFFFFFF 0xB7FF0005 0xB7FFF9CE + 0xFFFFFFFF 0xA3FFFFCF 0xF0410300 0xE3C00054 0x2C3F0000 0xFFFFFFFF 0x141FD0C0 0x040A0004 + 0xF0409B00 0xFB1CE200 0x00005000 0x00015001 0xEBC60014 0xDC2601B8 0xB01F047F 0xF1419380 + 0x97800001 0xB7FF047C 0xFFFFFFFF 0xB3FF0028 0x00025002 0xB3FF0037 0x00005002 0xB3FF005D + 0x00005002 0xB7FF0474 0xFFFFFFFF 0xB3FF007A 0x00005003 0xB3FF0089 0x00005003 0xB7FF046E + 0xFFFFFFFF 0xB3FF008F 0xF141130F 0xB3FF00E7 0x00025004 0xB7FF0468 0xFFFFFFFF 0xB3FF011C + 0xDBC1E83D 0xB3FF0156 0xF55C0BFF 0xB7FF0462 0xFFFFFFFF 0xB3FF01E8 0x0000D026 0xB7FF045E + 0xFFFFFFFF 0xB3FF0237 0xF55C0BFF 0xB7FF045A 0xFFFFFFFF 0xB3FF02BC 0xDBC1F03D 0xB7FF0456 + 0xFFFFFFFF 0xB3FF041F 0x0402D008 0x00215003 0xF05A0300 0xB03F000A 0xD05C1702 0x6FE0FC06 + 0xF4412301 0xD85C20F8 0xD8431078 0x77610C01 0x43041800 0xD85C1738 0x781FFC00 0x040100C0 + 0xF04A5304 0xDC411078 0xB3FF0443 0x140100C0 0x00245003 0xB83F000B 0xF05A1300 0x6F60FC06 + 0xDC5C00F8 0xF043E300 0xF04A0B04 0x77631C01 0xF4402B01 0x43050800 0xB3FF0012 0x781FFC00 + 0x6F60FC06 0xDC5C00F8 0xF05C0B00 0x77631C01 0xF4442B01 0x43050800 0x781FFC00 0x6F60FC06 + 0xDC440078 0xD85C0938 0xF04A0B04 0x77642401 0xF4402B01 0x43050800 0xF043E300 0x781FFC00 + 0xF1600B03 0xBC3F0003 0xB3FF0005 0xF0401B04 0xF0400B04 0xF5410B03 0xF0411B04 0x040110C0 + 0xD84A1AB8 0xD8410038 0xB3FF041B 0x140010C0 0x00235003 0xB83F000B 0xF05A1300 0x6F60FC06 + 0x05015005 0xDC5C00F8 0xF043E300 0x77631C01 0xF4402B01 0x43050800 0xB3FF0012 0x781FFC00 + 0x6F60FC06 0xDC5C0138 0xF05C0B00 0x77642401 0xF4432B01 0x43050800 0x781FFC00 0x6F60FC06 + 0xDC4300F8 0x05015005 0xD85C18F8 0x77631C01 0xF4402B01 0x43050800 0xF044E300 0x781FFC00 + 0x040110C0 0xF04A5308 0xD8410038 0xB3FF03FA 0x140010C0 0x00015002 0x6F60FC06 0xD85C0038 + 0xF04A1304 0x77600401 0xF4410301 0x43001000 0x781FFC00 0xF1610303 0xBC3F0003 0xB3FF0005 + 0xF0410304 0xF0410304 0xF5400303 0xF0400304 0xB3FF03E9 0xD84A02B8 0x00015002 0x6F60FC06 + 0x05025005 0xD85C0038 0x77600401 0xF4410301 0x43001000 0x781FFC00 0xB3FF03DF 0xF04A5308 + 0xEBC00003 0xDC201038 0xB01F0056 0xF05A0B00 0x97220001 0xB3FF0008 0xF1550BFF 0xB3FF000E + 0xCF158001 0xB3FF0020 0xCF168001 0xB3FF002C 0xCF168001 0x0400D0C0 0xF0411302 0xF15C0BFF + 0xDC420878 0xDC400838 0x1400D0C0 0xB3FF0045 0xD85C0F38 0xF42003FF 0xB43F0042 0xF15C13FF + 0xDC4010F8 0xCF15C081 0xF4431B02 0xF0421304 0xDC4200B8 0x6FE0FC06 0xF4432301 0xD85C20F8 + 0xD8431038 0x77600401 0x43041800 0x040008C0 0xD85C1738 0xDC401038 0x140008C0 0xB3FF0031 + 0x781FFC00 0xF42003FF 0xB43F0004 0xCF16C001 0xB3FF0004 0xF0401B04 0xF15503FF 0xF0401B02 + 0x040008C0 0xF15C13FF 0xDC4310B8 0xDC401038 0x140008C0 0xB3FF0023 0xD85C1738 0xF42003FF + 0xB43F0020 0xF55C1BFF 0xF15603FF 0xD9C30038 0x00020000 0xF15503FF 0xCF82E081 0xF4221304 + 0xB83F0005 0xD9C30038 0xEBC20800 0xB3FF0004 0x12020000 0xEBC286DD 0x12020000 0xCF1680C1 + 0xF15C13FF 0xCF16C001 0xF0400304 0xDC431138 0xDC4018B8 0x6FE0FC06 0xF4442301 0xD85C20F8 + 0xD8431038 0x77600401 0x43041800 0x040008C0 0xD85C1738 0xDC401038 0x140008C0 0x781FFC00 + 0xB3FF0385 0xF04A5304 0xF05A1B00 0xC81CA810 0x6F60FC06 0xF4422302 0xDC5C2178 0xF05C4B00 + 0x77652C01 0xDC40E1B9 0x43064800 0x781FFC00 0x6F60FC06 0x05095005 0xDC402138 0x77642401 + 0xF4423301 0x43064800 0xF045E300 0xF1410B0F 0x781FFC00 0xF4210B01 0xBC3F001F 0xCF168041 + 0xF4210BFF 0xBC3F0019 0x040507FE 0xF55C23FF 0xF1560BFF 0xFAF02911 0xF4210BFF 0x140507FE + 0xD9C40878 0xB03F0014 0xF4400302 0x00010800 0xCF81E041 0xF4210B04 0xBC3F0005 0x04040000 + 0xCE840041 0xB3FF000C 0x14010000 0xF4210B06 0xBC3F0009 0x04040000 0xCE840041 0xF1C10A20 + 0xB3FF0005 0x14010000 0x040107FE 0xF5410A01 0x140107FE 0x040118C0 0xF4420302 0xF04A5308 + 0xD8410038 0xB3FF034C 0x140018C0 0xCF158041 0xF4210BFF 0xB03F0034 0xDBC0E89D 0xF55C1BFF + 0xDC22F8B8 0xB03F0005 0xD9C30878 0xF15603FF 0xF42003FF 0xBC3F0008 0x00005003 0x02030800 + 0xCFA00001 0xCA00F800 0xFA001B5A 0xB3FF0026 0x12030800 0xD9C300F8 0x00041800 0xCF84E101 + 0xF4242304 0xB83F0011 0x04005004 0x00041801 0xDBC410D5 0xDBC41915 0xB3E30005 0xD8402038 + 0x00000000 0xB3FF0004 0xDBC02015 0x00000000 0xF140030F 0x02030800 0xCA00F800 0xFA001B5A + 0xB3FF0011 0x12030800 0x04031800 0xCF036101 0xDBC410DD 0xDBC4191D 0xB3E30005 0xD8402038 + 0x00000000 0xB3FF0004 0xDBC02015 0x00000000 0xF140030F 0x02030800 0xCA00F800 0xFA001B5A + 0x12030800 0xDC22F8B8 0xB03F0003 0xEBC00004 0xEBC00008 0xB3FF0310 0xD84A02B8 0xF15603FF + 0xF42003FF 0xD9C100F8 0xB03F0088 0xEBC20004 0x00001800 0xCF80E001 0xF4200304 0xBC3F0083 + 0x00005003 0xBFE00005 0x00201808 0xB43F0003 0xF4400301 0x10001808 0x00005003 0xF1600306 + 0xB43F0003 0x00005002 0x10001801 0x00005003 0xBF00000C 0x04005004 0xF0421304 0x02810000 + 0xB7DFFFFF 0xCA01F900 0xF0440B01 0x12041804 0xCA01F840 0x12810000 0xB3FF0003 0xEBC10001 + 0xEBC10000 0x00005003 0xBF20000F 0x0204180E 0x0200180C 0xF0421304 0xF043830C 0xD84021F8 + 0xDBC7801D 0xD84701F8 0xDC21F878 0xBC3F0003 0xB3FF0003 0x04005004 0x04005008 0x1400180C + 0xF0410B01 0x00005003 0xBF400012 0x02041812 0x02001810 0xF0421304 0xF0438B10 0xD8402238 + 0xDBC8801D 0xD8480238 0xDC21F878 0xBC3F0003 0xB3FF0007 0x04005004 0xF4210B01 0xBC3F0003 + 0xB3FF0003 0x04005008 0x0400500C 0x14001810 0x121F180A 0x00001800 0xCF401005 0xF4400301 + 0x73FFFC01 0x6F60FC06 0x40001800 0x00005003 0xBF200008 0x02018000 0x02008002 0xDDDF3938 + 0xCA04F900 0xD8410038 0xB3FF0003 0xD8402138 0xEBC40000 0x00005003 0xBF400008 0x02018800 + 0x02008802 0xDDDF4178 0xCA05F940 0xD8410038 0xD8440038 0xD8450138 0x7800FC01 0xDC24F938 + 0xF6400300 0xB03F0032 0x1200180A 0xCF17C001 0xF42003FF 0xB43F002E 0x00011809 0xF4210B11 + 0xBC3F0012 0xF55C0BFF 0xD9C10078 0x02200806 0xB43F0027 0xDDDF0038 0xCA00F800 0xD84400F8 + 0xDBC3801D 0xE943FFFF 0xD84300F8 0xDBC3801D 0xD84300F8 0xEC23FFFF 0xB43F0002 0xDDDF18F8 + 0xB3FF001B 0x12030806 0xF4210B06 0xBC3F0018 0xF55C0BFF 0xD9C10038 0x02010010 0xDDDF0878 + 0xCA01F840 0xD84408F8 0xDBC3805D 0xE943FFFF 0xD84308F8 0xDBC3805D 0xD84308F8 0xDDDF1878 + 0xB3FF000B 0x12010010 0x00005003 0xBF000002 0xF0421304 0x00005003 0xBF200002 0xF0421304 + 0x00005003 0xBF400002 0xF0421304 0xB3FF027A 0xD84A12B8 0xF14003F0 0xF4200340 0xBC3F0029 + 0x02015002 0xF05C0300 0xCFE18841 0xF4210B01 0xB83F0009 0xFB170600 0x02010000 0x02025004 + 0xDDDF0878 0xCA01F840 0x12020000 0xB3FF0003 0xD8420878 0xEBC10000 0x02025002 0xCFE29081 + 0xF4221301 0xBC3F0008 0x02030002 0x02025006 0xDDDF18F8 0xCA03F8C0 0xD8411078 0x12020002 + 0xD8430878 0x02220006 0xB43F0034 0xDDDF10B8 0xCA02F880 0xD84110B8 0xDBC2805D 0xE942FFFF + 0xD84208B8 0xDBC2805D 0xD84208B8 0xEC22FFFF 0xB43F0002 0xDDDF10B8 0xB3FF0028 0x12020006 + 0xF4200320 0xBC3F0025 0x02015002 0xF05C0300 0xCFE18841 0xF4210B01 0xB83F0009 0xFB170600 + 0x02010000 0x02025004 0xDDDF0878 0xCA01F840 0x12020000 0xB3FF0003 0xD8420878 0xEBC10000 + 0x02025002 0xCFE29081 0xF4221301 0xBC3F0008 0x02030002 0x02025006 0xDDDF18F8 0xCA03F8C0 + 0xD8411078 0x12020002 0xD8430878 0x02020010 0xDDDF10B8 0xCA02F880 0xD84110B8 0xDBC2805D + 0xE942FFFF 0xD84208B8 0xDBC2805D 0xD84208B8 0xDDDF1078 0x12010010 0xB3FF0227 0xF04A5308 + 0xF15603FF 0xF05A4B00 0xF42003FF 0xB03F0079 0xD9C10178 0x04002800 0xDBC0E01D 0xF4200306 + 0xBC3F0074 0x00015003 0xCFE1C801 0xF4200301 0xB83F0020 0xEBC30000 0xCFE1D001 0xF4200301 + 0xBC3F000F 0xEBC2001F 0x73FFFC01 0x6F60FC06 0xF0450B08 0x40022808 0xEBC60024 0x7804FC01 + 0x6F60FC06 0xF04A0304 0x77610C01 0x73FFFC01 0x43020000 0xB3FF0021 0x7803FC01 0xEBC2000F + 0x73FFFC01 0x6F60FC06 0xF0450B08 0x40022808 0x7804FC01 0x6F60FC06 0xF04A0304 0x77610C01 + 0x73FFFC01 0x43020000 0xB3FF0014 0x7803FC01 0xCFE1D001 0xF4200301 0xBC3F000E 0xEBC2000F + 0x73FFFC01 0x6F60FC06 0xF0450B18 0x40022818 0x7804FC01 0x6F60FC06 0xF04A0304 0x77610C01 + 0x73FFFC01 0x43020000 0xB3FF0004 0x7803FC01 0xF5DF2300 0xEBC60004 0x00005003 0xCFE00001 + 0xF4200301 0xBC3F0005 0x00202807 0xB43F0003 0xF4400301 0x10002807 0x00005003 0xDBC0E83D + 0xDBE0F01D 0xB43F0005 0x04022800 0x00015002 0xF8811528 0x14022800 0xDC23F8F8 0xB43F0038 + 0x00004826 0xF14003F0 0xF4200340 0xBC3F0016 0xF05C0B00 0xFB170E00 0x02200806 0xB43F0030 + 0xDDDF20B8 0xCA02F880 0xDDDF0038 0xD84310B8 0xCA00F800 0xD84200B8 0xDBC2801D 0xE942FFFF + 0xD84200B8 0xDBC2801D 0xD84200B8 0xCA02F800 0xEC20FFFF 0xB43F0002 0xDDDF10B8 0xB3FF0020 + 0x12020806 0xF4200320 0xBC3F001D 0xF05C0300 0xFB170600 0x02010010 0xDDDF20B8 0xCA02F880 + 0xDDDF0878 0xD84310B8 0xCA01F840 0xD84208B8 0xDBC2805D 0xE942FFFF 0xD84208B8 0xDBC2805D + 0xD84208B8 0xDDDF1078 0xB3FF000D 0x12010010 0x00005003 0xDBC0C03D 0xDBE0F81D 0xB03F0003 + 0xEBC60004 0xF0463310 0x00005003 0xDBC0C83D 0xDBE0F81D 0xB43F0002 0xF0463310 0xB3FF019E + 0xD84A32B8 0xDBE0F01D 0xB83F00A5 0xF05A4B00 0xF55C03FF 0xF1560BFF 0xF4210BFF 0xB03F015F + 0xD9C009B8 0xCF17C041 0xF4210BFF 0xB43F015B 0x00013000 0xCF81E041 0xF4210B04 0xBC3F0157 + 0xF15513FF 0xCF168041 0xF4210BFF 0xB83F0005 0xD9C01078 0xEBC086DD 0xB3FF0006 0x12000800 + 0x040137FC 0xCE810001 0xF1C00220 0x140037FC 0x00005004 0xCF17C081 0xF1560BFF 0xDC4208B8 + 0x02053002 0x00043008 0x00033009 0x040E300C 0xDC2200B8 0xB81F0018 0x04013010 0xDC401378 + 0xDC66E038 0xB43F000E 0x6F60FC06 0xDC5C6AF8 0xF05C6300 0x776B5C01 0xF4400301 0x43006000 + 0x040048C0 0xF04BE300 0xDC4669B8 0xD8406838 0x140048C0 0xB3FF001F 0x781FFC00 0x040048C0 + 0xDC4669B8 0xDC5C6F38 0xD8406838 0xB3FF0019 0x140048C0 0xDC201038 0xBC1F0016 0xDC420378 + 0xDC66E038 0xB43F000E 0x6FE0FC06 0xF4466301 0xF4400301 0xD84C6AF8 0x776B5C01 0x43006000 + 0x040048C0 0xD84669B8 0xD85C6F38 0xDC406838 0x140048C0 0xB3FF0007 0x781FFC00 0x040048C0 + 0xD84669B8 0xD85C6F38 0xDC406838 0x140048C0 0x6F60FC06 0x05095005 0x77663401 0x00005004 + 0xF4400301 0x43004800 0x781FFC00 0x00005001 0xCFE0D801 0xF4200301 0xBC3F0007 0xDC24F938 + 0xB43F0004 0xF4440301 0xB3FF0003 0x10003007 0x10043007 0x10033006 0x00035004 0xDC4510B8 + 0xEBC0001F 0xD84310B8 0xF4421328 0x12023004 0x73FFFC01 0x6F60FC06 0x40003008 0xEBC0FFFF + 0xD9410138 0xD94E00F8 0xDBCE809D 0xD84310B8 0xD84410B8 0xDBC1805D 0xD84208F8 0xDBC3805D + 0xE943FFFF 0xD84308F8 0xDBC3805D 0xD84308F8 0x7801FC01 0x00023006 0xF4221311 0xBC3F0015 + 0xF05C1300 0xFB171600 0x02241006 0xB43F00E3 0xDDDF18F8 0xCA03F8C0 0xDDDF2138 0xD8411878 + 0xCA04F8C0 0xD84118F8 0xDBC3805D 0xE943FFFF 0xD84308F8 0xDBC3805D 0xD84308F8 0xDC2300F8 + 0xB43F0002 0xDDDF18F8 0xB3FF00D4 0x12031006 0xF4221306 0xBC3F00D1 0xF05C0300 0xFB170600 + 0x02020010 0xDDDF18F8 0xCA03F8C0 0xDDDF10B8 0xD8411878 0xCA02F880 0xD84110B8 0xDBC2805D + 0xE942FFFF 0xD84208B8 0xDBC2805D 0xD84208B8 0xDDDF1078 0xB3FF00C1 0x12010010 0xF4200301 + 0xBC3F00BE 0xF55C03FF 0xF1560BFF 0xF4210BFF 0xB03F00BA 0xD9C009B8 0xCF17C041 0xF4210BFF + 0xB43F00B6 0x04013000 0xDBC1E05D 0xF4210B06 0xBC3F00B2 0xF15513FF 0xCF168041 0xF4210BFF + 0xB83F0005 0xD9C01078 0xEBC00800 0xB3FF0005 0x12000800 0x040137FC 0xCE810001 0x140037FC + 0xEBC0001F 0x020D3004 0x00043007 0x00023006 0x73FFFC01 0x6F60FC06 0x40003008 0x7801FC01 + 0x00005004 0xCF17C141 0xF1561BFF 0xDC4518F8 0xDC2300F8 0xBC1F0017 0xDC401978 0xDC66E038 + 0xB43F000E 0x6F60FC06 0xDC5C2AF8 0xF05C6300 0x776B5C01 0xF4400301 0x43006000 0x040048C0 + 0xF04BE300 0xDC4629B8 0xD8402838 0x140048C0 0xB3FF001F 0x781FFC00 0x040048C0 0xDC4629B8 + 0xDC5C2F38 0xD8402838 0xB3FF0019 0x140048C0 0xDC201838 0xBC1F0016 0xDC430178 0xDC66E038 + 0xB43F000E 0x6FE0FC06 0xF4466301 0xD84C2AF8 0x776B5C01 0xF4400301 0x43006000 0x040048C0 + 0xD84629B8 0xD85C2F38 0xDC402838 0x140048C0 0xB3FF0007 0x781FFC00 0x040048C0 0xD84629B8 + 0xD85C2F38 0xDC402838 0x140048C0 0x6F60FC06 0x05095005 0x77663401 0x00005004 0xF4400301 + 0x73FFFC01 0x43004800 0x7800FC01 0x00055001 0xCFE5D941 0xF4252B01 0xBC3F000A 0xDC24F938 + 0xB43F0006 0xF4442B01 0xDBC5413D 0x10053008 0xB3FF0004 0xD8402038 0x10043008 0xD8402038 + 0x10023009 0x00045004 0xDC4D18F8 0xF0431B28 0xD84418F8 0xCA03F900 0x12043002 0x00035001 + 0xD8401038 0xCFE3D081 0xF4221301 0xB83F000B 0xD8402038 0x04035008 0x02821800 0xB7DFFFFF + 0xCA02F880 0xF0422301 0x12023004 0xCA04F900 0xD8401038 0x12841800 0xEBC3FFFF 0xD94018B8 + 0xDBC0801D 0xD8420038 0xDDDF00B8 0xCF17C001 0xF42003FF 0xB03F0039 0x1202300A 0x00023009 + 0xF4221311 0xBC3F001C 0xF55C13FF 0xD9C200B8 0x02201006 0xB43F0031 0x0205300C 0x0204300E + 0x02093010 0x02063012 0xD8452138 0xD8492138 0xDDDF0878 0xD8462138 0xCA01F840 0xDDDF0038 + 0xD8440878 0xCA00F800 0xD8410078 0xDBC1801D 0xE941FFFF 0xD8410078 0xDBC1801D 0xD8410078 + 0xDC211878 0xB43F0002 0xDDDF0878 0xB3FF001B 0x12011006 0xF4221306 0xBC3F0018 0xF55C23FF + 0x0203300C 0x0202300E 0xD9C40138 0x02003010 0xD84310B8 0x02033012 0xD8401038 0x02022010 + 0xDDDF0878 0xD8430038 0xCA01F8C0 0xDDDF1078 0xD8401838 0xCA01F840 0xD8400878 0xDBC1801D + 0xE941FFFF 0xD8410078 0xDBC1801D 0xD8410078 0xDDDF0838 0x12002010 0xB3FF0037 0xF04A530C + 0xEBC02400 0xCD820081 0xDC201038 0xB01F0031 0xF05A0B00 0x0202D024 0xEBC0024C 0xD9620038 + 0xBC3F002C 0x0000D026 0xF14003F0 0xF4200320 0xBC3F0012 0x0000D03E 0xF55C1BFF 0x0202D02A + 0xD8430038 0x02030010 0xDDDF18F8 0xCA03F8C0 0xD84218F8 0xDBC3809D 0xD84310F8 0xCA03F880 + 0xDDDF10B8 0x12020010 0x0400080C 0xF5400010 0xB3FF0018 0x1400080C 0xF4200340 0xBC3F0015 + 0x0000D03E 0xF55C1BFF 0x0202D02A 0xD8430038 0x02030006 0xDDDF18F8 0xCA03F8C0 0xD84218F8 + 0xDBC3809D 0xD84310F8 0xCA03F880 0xEC22FFFF 0xBC3F0003 0xB3FF0004 0x12030006 0xDDDF10B8 + 0x12020006 0x0400080C 0xF5400010 0x1400080C 0xF04A5304 0xDC32FCB8 0xB43FFB7C 0x0428D0C0 + 0xB43F0023 0x0403D008 0xCD830081 0xD84240B8 0xC8031028 0x1400D008 0x7800F907 0xB7200003 + 0x7C00F907 0xB6E0001A 0x0402D008 0xDBC2E81D 0xF4200304 0xBC3F0011 0xA3FF004E 0xF05A0300 + 0xDC20D038 0xB43F0012 0x04020008 0xCC420041 0xD8414078 0xC802087C 0x14010008 0x0201000E + 0xDC414078 0x1201000E 0x0400D018 0xF1C00040 0xB3FF0007 0x1400D018 0xCEE26001 0xDC404078 + 0xF0420300 0xF8610528 0x1400D008 0x0400D018 0xF81CE630 0xF1C00020 0x1400D018 0x00009801 + 0xDBC0C83D 0xDBE0F81D 0xB83F0007 0x02019808 0x779CE103 0xB158E740 0xDBC1203D 0x283FF800 + 0xFFFFFFFF 0x777CE103 0x1401D0C4 0x0402D00C 0xEFC00000 0xF0400B00 0xF1C21010 0x1402D00C + 0x121FD022 0x121FD024 0x101FD026 0x121FD028 0x141FD02C 0x101FD021 0x1600D030 0x1600D038 + 0x0500D01D 0x1400D0C8 0x7802F906 0xB1580003 0xC2000007 0xC2000011 0x1402D090 0x151ED01D + 0xE3C00044 0x2C3F0000 0xFFFFFFFF 0x0400D0C8 0x1500D01D 0x0400D0C4 0x0402D090 0x0614D030 + 0x0616D038 0x73E21106 0xB3FFE71B 0xDBC0203D 0x283FF800 0xFFFFFFFF 0x0400D0C8 0x1500D01D + 0x0402D090 0x73E21106 0x283FF800 0xFFFFFFFF 0xEBC2038C 0xDBC040FD 0xE1C20008 0x7C01F905 + 0xDBC1607D 0xD8420878 0x73630B00 0x7C01F905 0xDBC1607D 0xD8420878 0x77610B00 0x7805FB00 + 0xDBC0405D 0xDBC5801D 0xDC200838 0xB43F0019 0xEBC40060 0xE1C40008 0xEBC60000 0x7800F800 + 0xF0400301 0xDBC0E17D 0x73652300 0x77642300 0x7800FB00 0xDC202838 0xBC3FFFFC 0x7C00F905 + 0xDBC0603D 0xD8420038 0x73630300 0x7C00F905 0xDBC0603D 0xD8420038 0x77600300 0x7805FB00 + 0xDBC5801D 0x73662300 0xDC200838 0xBC3FFFEC 0xCDA54011 0x9FFFF400 0x7802F907 0xDD420038 + 0xD9C00838 0x73E00107 0x9FFFF400 0x7C19F808 0x0400D018 0xB4800002 0xBC000003 0x0400D0B4 + 0x1400D00C 0xDBFCC15D 0xB43F003B 0x0700D030 0xEC2000FF 0xD040280F 0x1000D031 0xDBC0401D + 0xEC2000FF 0xD040280F 0x1000D030 0xEC2100FF 0xD041284F 0x1001D033 0xDBC1405D 0xEC2100FF + 0xD041284F 0x1001D032 0xEC2200FF 0xD042288F 0x1002D035 0xDBC2409D 0xEC2200FF 0xD042288F + 0x1002D034 0xEC2300FF 0xD04328CF 0x1003D037 0xDBC340DD 0xEC2300FF 0xD04328CF 0x1003D036 + 0x0700D038 0xEC2000FF 0xD040280F 0x1000D039 0xDBC0401D 0xEC2000FF 0xD040280F 0x1000D038 + 0xEC2100FF 0xD041284F 0x1001D03B 0xDBC1405D 0xEC2100FF 0xD041284F 0x1001D03A 0xEC2200FF + 0xD042288F 0x1002D03D 0xDBC2409D 0xEC2200FF 0xD042288F 0x1002D03C 0xEC2300FF 0xD04328CF + 0x1003D03F 0xDBC340DD 0xEC2300FF 0xD04328CF 0x1003D03E 0x0400D018 0xBCC00003 0x0400D08C + 0x9FFF0400 0xBCE00007 0xEBC00001 0x1400D094 0x0400D018 0xF5400001 0xB3FFE42F 0x1400D018 + 0xC65000C0 0x2C3FF000 0xFFFFFFFF 0x7C01F801 0xEBC03000 0xE1C0000C 0xDBC1C07D 0xF1C10A01 + 0x73610300 0x9FFFF400 0x7801F800 0xEBC20060 0xE1C20008 0xF0410B01 0xDBC1E0FD 0x73631300 + 0x77621300 0x7801FB00 0xDC211878 0xBC3FFFFC 0xDBC0807D 0xEBC00064 0xF1C10801 0xE1C00008 + 0x73610300 0xEBC00070 0xE1C00008 0xEBC1FFFF 0x77600300 0x7802FB00 0xBC020004 0xF0611B00 + 0xB83FFFFC 0xF4410B01 0xBC020004 0xE3C08000 0xB3FF000E 0xEBC10000 0xF1420003 0xF4200002 + 0xB43F0004 0xE3C08000 0xB3FF0008 0xEBC10000 0xEBC10074 0xE1C10008 0xCE020001 0x77610B00 + 0x7801FB00 0xF1C10B00 0xEBC20060 0xE1C20008 0x737F1300 0x9FFFF400 0x7801F800 0xEBC40060 + 0xE1C40008 0xF0410B01 0xDBC1E17D 0x73652300 0x77642300 0x7801FB00 0xDC212878 0xBC3FFFFC + 0xEBC10070 0xE1C10008 0x73620B00 0xEBC10074 0xE1C10008 0x73630B00 0xDBC0803D 0xEBC40064 + 0xF1C00002 0xE1C40008 0x73602300 0xEBC0FFFF 0x77642300 0x7801FB00 0xBC010004 0xF0601300 + 0xB83FFFFC 0xF4400301 0xEBC00060 0xE1C00008 0xB8010004 0x737F0300 0xB3FF0003 0xEFC00000 + 0xEBC00000 0x9FFFF400 0x7C19F808 0x0407D018 0xF05A5348 0xB8A70009 0xEBC80000 0xF5473804 + 0x1407D018 0x0407D088 0xF05A5B94 0xEBC80001 0x9BFF3800 0x141E5800 0x0400D018 0xBC600003 + 0x0200D098 0x12005000 0x0402D00C 0xEBC0EFE8 0xE1C0077E 0xD9620038 0xB43F0042 0xEBC1030C + 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x77600300 0x7801FB00 0x7C00F907 0xBEE00026 + 0x04000844 0xD9620038 0xB43F0036 0x04000840 0x77600107 0x7800F907 0xBF200032 0x0401D018 + 0xEBC01EAE 0xE9C00000 0xF1C10802 0x1401D018 0x1400D08C 0x0002D0B2 0xEBC00070 0xEBC10010 + 0xF1C21302 0x1002D0B2 0x0602D000 0x1602D0C0 0x0602D008 0xA3FFFF21 0x1602D0C8 0xDC28FA38 + 0xB43F0020 0x0401D008 0xDBDCC09D 0xEBC00100 0xDC4010B8 0xCD810001 0xDC2200B8 0xB41F0002 + 0xF0401300 0x0400D008 0xC8001028 0xB3FF0015 0x1400D008 0x04000848 0xD9620038 0xB43F0011 + 0x7800F907 0xB7200003 0x04000840 0xBC00000D 0x0401D018 0xEBC01EAE 0xE9C00000 0xF1C10802 + 0x1401D018 0x1400D08C 0x0002D0B2 0xEBC00010 0xF0400B00 0xF5421302 0xA3FFFF00 0x1002D0B2 + 0x0400D090 0x2C3F0000 0xFFFFFFFF 0x7C19F808 0x0000D0B2 0xBBC00004 0xF05A2B00 0xB3FF0003 + 0xF04523C0 0xF0452300 0x04012008 0xDBC1603D 0xDBE0601D 0xB43F0015 0xDBC1E81D 0xF4200304 + 0xBC3F000F 0x06022000 0xCEE16001 0xD86301F8 0xD8C2F9B8 0xF04503D0 0xEBC1000F 0xE3DB2000 + 0x71E10D00 0x55060000 0xF0673B10 0xD8C6F9B8 0x160628E0 0x2E3F000B 0xFFFFFFFF 0x06022000 + 0xA3FFFF66 0x00002001 0xEBC00010 0xA3FFFEDB 0xEBC10000 0xC65000C0 0x2C3FF000 0xFFFFFFFF + 0x7C19F808 0x0000D0B2 0xF05A43D0 0xBBC00004 0xEBCA000F 0xB3FF0003 0xF05A4BC0 0xF05A4B00 + 0x0200400C 0x06024000 0xA3FFFF54 0xCB00F800 0x04004008 0xDBC0083D 0xDBE0F81D 0xBC3F000B + 0x0602D0E0 0xF05A03D0 0xE3DB2000 0x71EA5500 0x55020000 0xF0631B10 0xD8C2F8B8 0x1602D0E0 + 0x2E3FFFE8 0xFFFFFFFF 0x06024800 0xA3FFFF43 0x00004801 0xEBC00010 0xA3FFFEB8 0xEBC10000 + 0xC65000C0 0x2C3FF000 0xFFFFFFFF 0x7C19F808 0xDC20F838 0xBC3F0005 0xEBC00002 0xE1C00050 + 0xB3FF0008 0x1400D090 0xEBC000C1 0xE1C00050 0x1400D090 0x0400D00C 0xF1C00102 0x1400D00C + 0x0402D00C 0xEBC0EFE8 0xE1C0077E 0xD9620038 0xB43F001B 0xEBC1030C 0xE1C10008 0x7C00F905 + 0xDBC0603D 0xD8410038 0x77600300 0x7801FB00 0x7C00F907 0xBEE00007 0x04000844 0xD9620038 + 0xB43F000F 0x04000840 0xB3FF000D 0x77600107 0x04000848 0xD9620038 0xB43F0009 0x04000840 + 0xBC000007 0x0002D0B2 0xEBC00010 0xF0400B00 0xF5421302 0xA3FFFE89 0x1002D0B2 0x0400D090 + 0x2C3F0000 0xFFFFFFFF 0x7C19F808 0x0401D018 0xBCE1001B 0xDC20F838 0xB43F0004 0xF5410801 + 0xB3FF0017 0x1401D018 0xEBC1030C 0xE1C10008 0x7C00F905 0xDBC0603D 0xD8410038 0x77600300 + 0x7802FB00 0x0000D03B 0xF55C0BFF 0xD8410038 0x00000000 0xCF80E001 0xF4200304 0xB83F0004 + 0x141FD094 0xB3FF0003 0x04001010 0x04001014 0x1402D088 0x2C3F0000 0xFFFFFFFF 0xDC20F838 + 0xBC3F0005 0xEBC10002 0xE1C10050 0xB3FF0008 0x1401D090 0xEBC100C1 0xE1C10050 0x1401D090 + 0x0401D00C 0xF1C10902 0x1401D00C 0x0401D018 0xBC410048 0x7801F907 0xBF410046 0x0402D008 + 0xDBDCC15D 0xF55C23FF 0xEBC10100 0xDBC2E8DD 0xF4231B04 0xDC412AB8 0xB83F0024 0xD9C42AF8 + 0x0608D000 0xA3FFFE23 0xF05A0300 0xF0400B00 0x0205000E 0x06020000 0xDBC5F915 0xD8632978 + 0xD8C220B8 0xCA824080 0x04040008 0xCC440181 0xDC2A32B8 0xBC1F0002 0xF04A3300 0xF0451B00 + 0xF4462301 0xE3DB2000 0x71E42500 0x55225800 0x04020008 0xDBC208BD 0xDBE2F89D 0xB03F0003 + 0xD44A3282 0xEBCA0000 0xDC2AFAB8 0xB43F0003 0xD84B32F8 0xF0400310 0xDC2AFAB8 0xBC3FFFE5 + 0xB3FF000F 0xF0410300 0xCD820041 0xDC2A0AB8 0xB41F0002 0xF0415300 0x0404D008 0x0602D000 + 0xF44A0B01 0xCEE46101 0xD8632178 0xD8C2F938 0xE3DB2000 0x71E10D00 0x55245800 0x0401D018 + 0xBC21000C 0x0402D008 0x0604D000 0xEBC1000F 0xCEE26081 0xD86510F8 0xD8C4F8B8 0xE3DB2000 + 0x71E10D00 0x55220000 0x2E3FFEC0 0xFFFFFFFF 0xB7FFFEBE 0xFFFFFFFF 0x44160637 + >; +}; diff --git a/configs/arm64/dts/inmate-ls1043a-rdb.dts b/configs/arm64/dts/inmate-ls1043a-rdb.dts new file mode 100644 index 0000000000000000000000000000000000000000..eb8bc172a7492051d4922a34b00e6295a1dff1ba --- /dev/null +++ b/configs/arm64/dts/inmate-ls1043a-rdb.dts @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP ls1043a RDB platform + * + * Copyright 2020 NXP + * + * hongbo.wang + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls1043a-rdb", "fsl,ls1043a"; + model = "LS1043A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + aliases { + serial0 = &duart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + l2: l2-cache { + compatible = "cache"; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + idle-states { + entry-method = "psci"; + + CPU_PH20: cpu-ph20 { + compatible = "arm,idle-state"; + idle-state-name = "PH20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <1000>; + exit-latency-us = <1000>; + min-residency-us = <3000>; + }; + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + reboot { + compatible ="syscon-reboot"; + regmap = <&dcfg>; + offset = <0xb0>; + mask = <0x02>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 0xf08>, /* Physical Secure PPI */ + <1 14 0xf08>, /* Physical Non-Secure PPI */ + <1 11 0xf08>, /* Virtual PPI */ + <1 10 0xf08>; /* Hypervisor PPI */ + }; + + gic: interrupt-controller@1410000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x1410000 0 0x10000>, /* GICD */ + <0x0 0x142f000 0 0x1000>, /* GICC */ + <0x0 0x1440000 0 0x20000>, /* GICH */ + <0x0 0x146f000 0 0x1000>; /* GICV */ + interrupts = <1 9 0xf08>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>; + dma-coherent; + + + ddr: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = <0 144 0x4>; + big-endian; + }; + + scfg: scfg@1570000 { + compatible = "fsl,ls1043a-scfg", "syscon"; + reg = <0x0 0x1570000 0x0 0x10000>; + big-endian; + }; + + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1043a-dcfg", "syscon"; + reg = <0x0 0x1ee0000 0x0 0x1000>; + big-endian; + }; + + clockgen: clocking@1ee1000 { + compatible = "fsl,ls1043a-clockgen"; + reg = <0x0 0x1ee1000 0x0 0x1000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 0>; + status = "okay"; + }; + + }; + + pci@c0700000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xc0700000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + +}; diff --git a/configs/arm64/dts/inmate-ls1046a-rdb.dts b/configs/arm64/dts/inmate-ls1046a-rdb.dts new file mode 100644 index 0000000000000000000000000000000000000000..f5fa9751aadf30599b3df6212ccc8b11d37bedda --- /dev/null +++ b/configs/arm64/dts/inmate-ls1046a-rdb.dts @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP ls1046a RDB platform + * + * Copyright 2020 NXP + * + * Jiafei Pan + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls1046a-rdb", "fsl,ls1046a"; + model = "LS1046A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &duart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x2>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x3>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + l2: l2-cache { + compatible = "cache"; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + idle-states { + entry-method = "psci"; + + CPU_PH20: cpu-ph20 { + compatible = "arm,idle-state"; + idle-state-name = "PH20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <1000>; + exit-latency-us = <1000>; + min-residency-us = <3000>; + }; + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + reboot { + compatible ="syscon-reboot"; + regmap = <&dcfg>; + offset = <0xb0>; + mask = <0x02>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@1410000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x1410000 0 0x10000>, /* GICD */ + <0x0 0x142f000 0 0x1000>, /* GICC */ + <0x0 0x1440000 0 0x20000>, /* GICH */ + <0x0 0x146f000 0 0x1000>; /* GICV */ + interrupts = ; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>; + dma-coherent; + + + ddr: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = ; + big-endian; + }; + + scfg: scfg@1570000 { + compatible = "fsl,ls1046a-scfg", "syscon"; + reg = <0x0 0x1570000 0x0 0x10000>; + big-endian; + }; + + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1046a-dcfg", "syscon"; + reg = <0x0 0x1ee0000 0x0 0x1000>; + big-endian; + }; + + clockgen: clocking@1ee1000 { + compatible = "fsl,ls1046a-clockgen"; + reg = <0x0 0x1ee1000 0x0 0x1000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 1>; + status = "okay"; + }; + + }; + + pci@fb500000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfb500000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + +}; diff --git a/configs/arm64/dts/inmate-ls1088a-rdb.dts b/configs/arm64/dts/inmate-ls1088a-rdb.dts new file mode 100644 index 0000000000000000000000000000000000000000..91fac3f7774c0285da7f5d29c4f0b6a8b3056f96 --- /dev/null +++ b/configs/arm64/dts/inmate-ls1088a-rdb.dts @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP LS1088ARDB platform + * + * Copyright 2021 NXP + * + * Anda-Alexandra Dorneanu + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls1088a"; + model = "LS1088A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &duart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + clocks = <&clockgen 1 0>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + clocks = <&clockgen 1 0>; + cpu-idle-states = <&CPU_PH20>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + }; + + idle-states { + entry-method = "psci"; + + CPU_PH20: cpu-ph20 { + compatible = "arm,idle-state"; + idle-state-name = "PH20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <1000>; + exit-latency-us = <1000>; + min-residency-us = <3000>; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>, + <1 14 IRQ_TYPE_LEVEL_LOW>, + <1 11 IRQ_TYPE_LEVEL_LOW>, + <1 10 IRQ_TYPE_LEVEL_LOW>; + }; + + gic: interrupt-controller@6000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ + <0x0 0x06100000 0 0x100000>, /* GICR(RD_base+SGI_base)*/ + <0x0 0x0c0c0000 0 0x2000>, /* GICC */ + <0x0 0x0c0d0000 0 0x1000>, /* GICH */ + <0x0 0x0c0e0000 0 0x20000>; /* GICV */ + interrupts = <1 9 IRQ_TYPE_LEVEL_HIGH>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clockgen: clocking@1300000 { + compatible = "fsl,ls1088a-clockgen"; + reg = <0x0 0x1300000 0x0 0xa0000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart1: serial@21c0600 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0600 0x0 0x100>; + clocks = <&clockgen 4 1>; + status = "okay"; + }; + }; + + pci@13000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 49 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 50 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 51 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 56 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x13000000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; +}; diff --git a/configs/arm64/dts/inmate-ls2088a-rdb.dts b/configs/arm64/dts/inmate-ls2088a-rdb.dts new file mode 100644 index 0000000000000000000000000000000000000000..8aa36f545ba0e397d819a8c6ae85a1aeece8b5d8 --- /dev/null +++ b/configs/arm64/dts/inmate-ls2088a-rdb.dts @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree for inmate cell on NXP LS2088ARDB platform + * + * Copyright 2021 NXP + * + * Anda-Alexandra Dorneanu + */ + +/dts-v1/; + +#include + +/ { + compatible = "fsl,ls2080a"; + model = "LS2088A RDB Board"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &duart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1>; + clocks = <&clockgen 1 0>; + cpu-idle-states = <&CPU_PW20>; + next-level-cache = <&cluster0_l2>; + #cooling-cells = <2>; + enable-method = "psci"; + }; + + cluster0_l2: l2-cache0 { + compatible = "cache"; + }; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + idle-states { + entry-method = "psci"; + + CPU_PW20: cpu-pw20 { + compatible = "arm,idle-state"; + idle-state-name = "PW20"; + arm,psci-suspend-param = <0x0>; + entry-latency-us = <2000>; + exit-latency-us = <2000>; + min-residency-us = <6000>; + }; + + }; + + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sysclk"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 4>, + <1 14 4>, + <1 11 4>, + <1 10 4>; + }; + + gic: interrupt-controller@6000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ + <0x0 0x06100000 0 0x100000>, /* GICR(RD_base+SGI_base)*/ + <0x0 0x0c0c0000 0 0x2000>, /* GICC */ + <0x0 0x0c0d0000 0 0x1000>, /* GICH */ + <0x0 0x0c0e0000 0 0x20000>; /* GICV */ + interrupts = <1 9 0x4>; + }; + + soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ddr1: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = <0 17 0x4>; + little-endian; + }; + + clockgen: clocking@1300000 { + compatible = "fsl,ls2080a-clockgen"; + reg = <0x0 0x1300000 0x0 0xa0000>; + #clock-cells = <2>; + clocks = <&sysclk>; + }; + + duart1: serial@21c0500 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0500 0x0 0x100>; + clocks = <&clockgen 4 3>; + status = "okay"; + }; + }; + + pci@13000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 53 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 54 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 55 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 56 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x13000000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; +}; diff --git a/configs/arm64/dts/inmate-macchiatobin.dts b/configs/arm64/dts/inmate-macchiatobin.dts new file mode 100644 index 0000000000000000000000000000000000000000..51f07da140622cc4900949a638fd5f3b11bf47a0 --- /dev/null +++ b/configs/arm64/dts/inmate-macchiatobin.dts @@ -0,0 +1,106 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on MACCHIATObin, + * corresponds to configs/arm64/macchiatobin-linux-demo.c + * + * Copyright (c) Siemens AG, 2016-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on MACCHIATObin"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@100 { + compatible = "arm,cortex-a72", "arm,armv8"; + device_type = "cpu"; + reg = <0x100>; + enable-method = "psci"; + }; + cpu@101 { + compatible = "arm,cortex-a72", "arm,armv8"; + device_type = "cpu"; + reg = <0x101>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f0210000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0xf0210000 0x0 0x10000>, /* GICD */ + <0x0 0xf022f000 0x0 0x20000>; /* GICC */ + }; + + ap_syscon: system-controller@f06f4000 { + compatible = "syscon", "simple-mfd"; + reg = <0 0xf06f4000 0 0x2000>; + + ap_clk: clock { + compatible = "marvell,ap806-clock"; + #clock-cells = <1>; + }; + }; + + uart0: serial@f0512000 { + compatible = "snps,dw-apb-uart"; + reg = <0 0xf0512000 0 0x100>; + reg-shift = <2>; + interrupts = ; + reg-io-width = <1>; + clocks = <&ap_clk 3>; + }; + + pci@fc000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 80 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 81 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 82 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 83 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfc000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-miriac-sbc-ls1046a.dts b/configs/arm64/dts/inmate-miriac-sbc-ls1046a.dts new file mode 100644 index 0000000000000000000000000000000000000000..05c3220cf20d0e33a75efc4c5a7c46243127f2ad --- /dev/null +++ b/configs/arm64/dts/inmate-miriac-sbc-ls1046a.dts @@ -0,0 +1,106 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate on Microsys miriac-LS1046a-SBC, + * corresponds to configs/arm64/miriac-sbc-ls1046a-linux-demo.c + * + * Copyright (c) Linutronix GmbH, 2018 + * + * Authors: + * Andreas Messerschmid + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on Microsys Miriac-LS1046a-SBC"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a72", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a72", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@1410000 { + compatible = "arm,gic-400"; + reg = <0x0 0x1410000 0x0 0x1000>, + <0x0 0x142f000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uartclk: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + }; + + uart: serial@21c0500 { + compatible = "fsl,ns16550", "ns16550a"; + reg = <0x00 0x21c0500 0x0 0x100>; + interrupts = ; + clocks = <&uartclk>, <&uartclk>; + clock-names = "uart_clk", "pclk"; + }; + + pci@13000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 74 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 75 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 76 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 77 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x13000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-pine64-plus.dts b/configs/arm64/dts/inmate-pine64-plus.dts new file mode 100644 index 0000000000000000000000000000000000000000..6d0a12d3cd412d280c9f77daf845adf9470e7aa0 --- /dev/null +++ b/configs/arm64/dts/inmate-pine64-plus.dts @@ -0,0 +1,114 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Pine64+ board, + * corresponds to configs/arm64/pine64-plus-linux-demo.c + * + * Copyright (c) Vijai Kumar K, 2019-2020 + * + * Authors: + * Vijai Kumar K + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on Pine64+"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: clk24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + }; + + gic: interrupt-controller@1c81000 { + compatible = "arm,gic-400"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uart: serial@1c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <24000000>; + }; + + pci@2000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 123 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 124 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 125 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 126 IRQ_TYPE_EDGE_RISING>; + reg = <0x02000000 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-qemu-arm64.dts b/configs/arm64/dts/inmate-qemu-arm64.dts new file mode 100644 index 0000000000000000000000000000000000000000..6f6df6820d797f6b3f8144e0fa37bc0085061aa8 --- /dev/null +++ b/configs/arm64/dts/inmate-qemu-arm64.dts @@ -0,0 +1,103 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on QEMU ARM64 target, + * corresponds to configs/arm64/qemu-arm64-linux-demo.c + * + * Copyright (c) Siemens AG, 2016-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on QEMU ARM64"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a57", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a57", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@d1d00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x08000000 0x0 0x10000>, /* GICD */ + <0x0 0x080a0000 0x0 0xf60000>; /* GICR */ + }; + + apb_pclk: clk24mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clk24mhz"; + }; + + uart0: serial@9000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0x09000000 0x0 0x1000>; + interrupts = ; + clocks = <&apb_pclk>, <&apb_pclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + pci@7000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 109 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 111 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0x08e00000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-rpi4.dts b/configs/arm64/dts/inmate-rpi4.dts new file mode 100644 index 0000000000000000000000000000000000000000..305ac22fdd2c1558dd7174116b1a5e6572f5b60c --- /dev/null +++ b/configs/arm64/dts/inmate-rpi4.dts @@ -0,0 +1,103 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on Raspberry Pi 4, + * corresponds to configs/arm64/rpi4-linux-demo.c + * + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on Raspberry Pi 4"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@ff841000 { + compatible = "arm,gic-400"; + reg = <0x0 0xff841000 0x0 0x1000>, + <0x0 0xff842000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + fixed: clk500mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <500000000>; + clock-output-names = "clk500mhz"; + }; + + uart1: serial@fe215040 { + compatible = "brcm,bcm2835-aux-uart"; + reg = <0x0 0xfe215040 0x0 0x40>; + interrupts = ; + clocks = <&fixed>; + status = "okay"; + }; + + pci@e0000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 153 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 155 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 156 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xff900000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x20000000 0x0 0x20000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-zynqmp-zcu102-2.dts b/configs/arm64/dts/inmate-zynqmp-zcu102-2.dts new file mode 100644 index 0000000000000000000000000000000000000000..de70284666bfcca5bedf76118b508bff8b56b219 --- /dev/null +++ b/configs/arm64/dts/inmate-zynqmp-zcu102-2.dts @@ -0,0 +1,85 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for 2nd Linux inmate test on ZynqMP ZCU102 board, + * corresponds to configs/arm64/zynqmp-zcu102-linux-demo-2.c + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on ZynqMP ZCU102"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@1 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f6801000 { + compatible = "arm,gic-400"; + reg = <0x0 0xf9010000 0x0 0x1000>, + <0x0 0xf902f000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + pci@fc000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 112 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 114 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 115 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfc000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/dts/inmate-zynqmp.dts b/configs/arm64/dts/inmate-zynqmp.dts new file mode 100644 index 0000000000000000000000000000000000000000..e608f0adc82cf6478e9eb14591e88bc124c7513b --- /dev/null +++ b/configs/arm64/dts/inmate-zynqmp.dts @@ -0,0 +1,107 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Device tree for Linux inmate test on ZynqMP ZCU102 and Ultra96 boards, + * corresponds to configs/arm64/zynqmp-zcu102-linux-demo.c and + * configs/arm64/ultra96-linux-demo.c. + * + * Copyright (c) Siemens AG, 2016-2019 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/dts-v1/; + +/ { + model = "Jailhouse cell on ZynqMP"; + + #address-cells = <2>; + #size-cells = <2>; + + interrupt-parent = <&gic>; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@2 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f6801000 { + compatible = "arm,gic-400"; + reg = <0x0 0xf9010000 0x0 0x1000>, + <0x0 0xf902f000 0x0 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + uartclk: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + uart: serial@ff010000 { + compatible = "cdns,uart-r1p12", "xlnx,xuartps"; + reg = <0x0 0xff010000 0x0 0x1000>; + interrupts = ; + clocks = <&uartclk>, <&uartclk>; + clock-names = "uart_clk", "pclk"; + }; + + pci@fc000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_EDGE_RISING>, + <0 0 0 2 &gic GIC_SPI 109 IRQ_TYPE_EDGE_RISING>, + <0 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_EDGE_RISING>, + <0 0 0 4 &gic GIC_SPI 111 IRQ_TYPE_EDGE_RISING>; + reg = <0x0 0xfc000000 0x0 0x100000>; + ranges = + <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>; + }; +}; diff --git a/configs/arm64/espressobin-inmate-demo.c b/configs/arm64/espressobin-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..921b93b0786c3bf8f9edcb5ade842da7bb9ed15f --- /dev/null +++ b/configs/arm64/espressobin-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Marvell ESPRESSObin board: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0xd0012000, + .type = JAILHOUSE_CON_TYPE_MVEBU, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0xd0012000, + .virt_start = 0xd0012000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x3faf0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/espressobin-linux-demo.c b/configs/arm64/espressobin-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..c326b6d563723d5dfa1ea4305a3d392a70e5a71a --- /dev/null +++ b/configs/arm64/espressobin-linux-demo.c @@ -0,0 +1,108 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on ESPRESSObin: + * 1 CPU, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "ESPRESSObin-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + + .console = { + .address = 0xd0012000, + .type = JAILHOUSE_CON_TYPE_MVEBU, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x3fb00000, 1), + /* UART */ { + .phys_start = 0xd0012000, + .virt_start = 0xd0012000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x3fa00000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x37000000, + .virt_start = 0x37000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xd1d00000, + .pin_base = 32, + .pin_bitmap = { + (1 << (43 - 32)) | (1 << (44 - 32)) | (1 << (45 - 32)), + 0, + 0, + (1 << (141 - 128)) + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/espressobin.c b/configs/arm64/espressobin.c new file mode 100644 index 0000000000000000000000000000000000000000..1b75f6d7a0542e703216568819e0911827aeb393 --- /dev/null +++ b/configs/arm64/espressobin.c @@ -0,0 +1,118 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Marvell ESPRESSObin board + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation 0x30000000..0x3fffffff via cmdline: mem=768M + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x3fc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0xd0012000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_MVEBU, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xfc000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 3, + .gicd_base = 0xd1d00000, + .gicr_base = 0xd1d40000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ESPRESSObin", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 128-32, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x3fb00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0xd0000000, + .virt_start = 0xd0000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMIO (PCIe) */ { + .phys_start = 0xe8000000, + .virt_start = 0xe8000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x3fb00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xd1d00000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/foundation-v8-inmate-demo.c b/configs/arm64/foundation-v8-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..2dda3adf2eafc5940e1589128ddb89f15ef969cb --- /dev/null +++ b/configs/arm64/foundation-v8-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Foundation Model v8: + * 1 CPU, 64K RAM, serial port 1 + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0x1c090000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* UART 1 */ { + .phys_start = 0x1c0a0000, + .virt_start = 0x1c090000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xfbfe0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, +}; diff --git a/configs/arm64/foundation-v8-linux-demo.c b/configs/arm64/foundation-v8-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..842afe9f77d840b3157baf480093a9904a3e1b48 --- /dev/null +++ b/configs/arm64/foundation-v8-linux-demo.c @@ -0,0 +1,88 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on Foundation Model v8: + * 2 CPUs, ~256MB RAM, serial port 3 + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Dmitry Voytik + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; + struct jailhouse_irqchip irqchips[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 1, + .num_pci_devices = 0, + + .console = { + .address = 0x1c090000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, /* 2nd and 3rd CPUs */ + }, + + /* Physical memory map: + * 0x0_0000_0000 - 0x0_7fff_ffff (2048 MiB) Devices + * 0x0_8000_0000 - 0x0_bbdf_ffff ( 958 MiB) Ram, root cell Kernel + * 0x0_bbe0_0000 - 0x0_fbff_ffff (1026 MiB) Ram, nothing + * 0x0_fc00_0000 - 0x1_0000_0000 ( 64 MiB) Ram, hypervisor + * ... ( 30 GiB) + * 0x8_8000_0000 - 0x9_0000_0000 (2048 MiB) Ram, nonroot cells + */ + .mem_regions = { + /* uart3 */ { + .phys_start = 0x1c0c0000, + .virt_start = 0x1c090000, /* inmate lib uses */ + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM load */ { + .phys_start = 0x880000000, + .virt_start = 0x0, + .size = 0x10000000, /* 256 MiB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC v2 */ { + .address = 0x2c001000, /* GIC v3: 0x2f000000 */ + .pin_base = 32, + .pin_bitmap = { + (1 << 8) /* uart3 */ + }, + }, + } +}; diff --git a/configs/arm64/foundation-v8.c b/configs/arm64/foundation-v8.c new file mode 100644 index 0000000000000000000000000000000000000000..7a6324913aaedc2ccd1066c8237cf0aad5453837 --- /dev/null +++ b/configs/arm64/foundation-v8.c @@ -0,0 +1,155 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Foundation Model v8 board + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[9]; + struct jailhouse_irqchip irqchips[3]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfc000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0x1c090000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info.arm = { +#ifdef CONFIG_ARM_GIC_V3 + .gic_version = 3, + .gicd_base = 0x2f000000, + .gicr_base = 0x2f100000, +#else /* GICv2 */ + .gic_version = 2, + .gicd_base = 0x2c001000, + .gicc_base = 0x2c002000, + .gich_base = 0x2c004000, + .gicv_base = 0x2c006000, +#endif + .maintenance_irq = 25, + }, + .root_cell = { + .name = "foundation-v8", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* ethernet */ { + .phys_start = 0x1a000000, + .virt_start = 0x1a000000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sysreg */ { + .phys_start = 0x1c010000, + .virt_start = 0x1c010000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* uart0 */ { + .phys_start = 0x1c090000, + .virt_start = 0x1c090000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* uart1 */ { + .phys_start = 0x1c0a0000, + .virt_start = 0x1c0a0000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* uart2 */ { + .phys_start = 0x1c0b0000, + .virt_start = 0x1c0b0000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* uart3 */ { + .phys_start = 0x1c0c0000, + .virt_start = 0x1c0c0000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* virtio_block */ { + .phys_start = 0x1c130000, + .virt_start = 0x1c130000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x7c000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + .irqchips = { + /* GIC v2 */ { + .address = 0x2c001000, /* GIC v3: 0x2f000000 */ + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC v2 */ { + .address = 0x2c001000, /* GIC v3: 0x2f000000 */ + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC v2 */ { + .address = 0x2c001000, /* GIC v3: 0x2f000000 */ + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + +}; diff --git a/configs/arm64/hikey-inmate-demo.c b/configs/arm64/hikey-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..ce5eb91b4b333dd4a56fd080877a6dec7bb8821d --- /dev/null +++ b/configs/arm64/hikey-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on LeMaker HiKey board, 2GiB: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0xf7113000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x10, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0xf7113000, + .virt_start = 0xf7113000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7bfe0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/hikey-linux-demo.c b/configs/arm64/hikey-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..cb6e101c2fba0c515903090c48012a76be9e08ea --- /dev/null +++ b/configs/arm64/hikey-linux-demo.c @@ -0,0 +1,105 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on HiKey: + * 1 CPU, 128M RAM, serial port 3 + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "hikey-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 143-32, + + .console = { + .address = 0xf7113000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc0, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 1), + /* UART 3 */ { + .phys_start = 0xf7113000, + .virt_start = 0xf7113000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x74000000, + .virt_start = 0x74000000, + .size = 0x7ef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf6801000, + .pin_base = 32, + .pin_bitmap = { + 0, 1 << (71 - 64), 0, 1 << (144 - 128) + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/hikey.c b/configs/arm64/hikey.c new file mode 100644 index 0000000000000000000000000000000000000000..4aadfaae154128f787edd2905c259b008ad4a8bb --- /dev/null +++ b/configs/arm64/hikey.c @@ -0,0 +1,124 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for LeMaker HiKey board, 2 GB + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7c000000, + .size = 0x04000000, + }, + .debug_console = { + .address = 0xf7113000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xf6000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0xf6801000, + .gicc_base = 0xf6802000, + .gich_base = 0xf6804000, + .gicv_base = 0xf6806000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "HiKey", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 136-32, + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7bf00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0xf4100000, + .virt_start = 0xf4100000, + .size = 0x00008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMIO (permissive) */ { + .phys_start = 0xf7000000, + .virt_start = 0xf7000000, + .size = 0x01100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM + mailbox? (permissive) */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x7bf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SRAM */ { + .phys_start = 0xfff80000, + .virt_start = 0xfff80000, + .size = 0x12000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf6801000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8dxl-inmate-demo-aarch32.c b/configs/arm64/imx8dxl-inmate-demo-aarch32.c new file mode 100644 index 0000000000000000000000000000000000000000..f18d40a1110b44fad232634747734b446fffe655 --- /dev/null +++ b/configs/arm64/imx8dxl-inmate-demo-aarch32.c @@ -0,0 +1,14 @@ +/* + * iMX8DXL target - gic-demo + * + * Copyright 2020 NXP + * + * Authors: + * Alice Guo + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define USE_AARCH32 +#include "imx8dxl-inmate-demo.c" diff --git a/configs/arm64/imx8dxl-inmate-demo.c b/configs/arm64/imx8dxl-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..089a0b8d5fa41a7de5b9caf3f2fc6d4f4b421309 --- /dev/null +++ b/configs/arm64/imx8dxl-inmate-demo.c @@ -0,0 +1,68 @@ +/* + * iMX8DXL target - gic-demo + * + * Copyright 2020 NXP + * + * Authors: + * Alice Guo + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "gic-demo", +#ifdef USE_AARCH32 + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | JAILHOUSE_CELL_AARCH32, +#else + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, +#endif + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + .console = { + .address = 0x5a060000, + .type = JAILHOUSE_CON_TYPE_IMX_LPUART, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* UART1 */ { + .phys_start = 0x5a060000, + .virt_start = 0x5a060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xa1700000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/imx8dxl.c b/configs/arm64/imx8dxl.c new file mode 100644 index 0000000000000000000000000000000000000000..f70826b16d94a3ef013ac1dccc646b1f4450ea1f --- /dev/null +++ b/configs/arm64/imx8dxl.c @@ -0,0 +1,172 @@ +/* + * i.MX8DXL Target + * + * Copyright 2020 NXP + * + * Authors: + * Alice Guo + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[15]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xbfc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x5a060000, + .size = 0x1000, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + .type = JAILHOUSE_CON_TYPE_IMX_LPUART, + }, + .platform_info = { + .pci_mmconfig_base = 0xbf700000, + .pci_mmconfig_end_bus = 0x0, + .pci_is_virtual = 1, + .pci_domain = 0, + .arm = { + .gic_version = 3, + .gicd_base = 0x51a00000, + .gicr_base = 0x51b00000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "imx8dxl", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 2, /* Not include 32 base */ + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xbf900000, + .virt_start = 0xbf900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbf901000, + .virt_start = 0xbf901000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbf90a000, + .virt_start = 0xbf90a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbf90c000, + .virt_start = 0xbf90c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbf90e000, + .virt_start = 0xbf90e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbfa00000, 0), + /* MMIO (permissive): TODO: refine the map */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x80200000, + .virt_start = 0x80200000, + .size = 0x21d00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */{ + .phys_start = 0xa1700000, + .virt_start = 0xa1700000, + .size = 0x1e000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Loader */{ + .phys_start = 0xbfb00000, + .virt_start = 0xbfb00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x51a00000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x51a00000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x51a00000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mm-inmate-demo.c b/configs/arm64/imx8mm-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..5791b945c0904f419ab0a3104893851be55f6002 --- /dev/null +++ b/configs/arm64/imx8mm-inmate-demo.c @@ -0,0 +1,125 @@ +/* + * iMX8MM target - gic-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 76, + + .console = { + .address = 0x30890000, + .type = JAILHOUSE_CON_TYPE_IMX, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART2 */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: start from the bottom of inmate memory */ { + .phys_start = 0xb3c00000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 96, + .pin_bitmap = { + 0x1 << (76 + 32 - 96) /* SPI 76 */ + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/imx8mm-linux-demo.c b/configs/arm64/imx8mm-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..49272607955ec7ca448b6043c6305f8d336fae0a --- /dev/null +++ b/configs/arm64/imx8mm-linux-demo.c @@ -0,0 +1,167 @@ +/* + * iMX8MM target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* + * Boot 2nd Linux cmdline: + * export PATH=$PATH:/usr/share/jailhouse/tools/ + * jailhouse cell linux imx8mm-linux-demo.cell Image -d fsl-imx8mm-evk-inmate.dtb -c "clk_ignore_unused console=ttymxc3,115200 earlycon=ec_imx6q,0x30890000,115200 root=/dev/mmcblk2p2 rootwait rw" + */ +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[15]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 74, /* Not include 32 base */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 */ { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbb00000, 1), + /* UART2 earlycon */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART4 */ { + .phys_start = 0x30a60000, + .virt_start = 0x30a60000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC1 */ { + .phys_start = 0x30b60000, + .virt_start = 0x30b60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xbb700000, + .virt_start = 0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + /* + * We could not use 0x80000000 which conflicts with + * COMM_REGION_BASE + */ + .phys_start = 0x93c00000, + .virt_start = 0x93c00000, + .size = 0x24000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* uart2/sdhc1 */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + (1 << (24 + 32 - 32)) | (1 << (29 + 32 - 32)) + }, + }, + /* IVSHMEM */ { + .address = 0x38800000, + .pin_base = 96, + .pin_bitmap = { + 0xf << (74 + 32 - 96) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mm.c b/configs/arm64/imx8mm.c new file mode 100644 index 0000000000000000000000000000000000000000..2556ac318e9cdae0904a63bf8ffd14b6fe9ddb5b --- /dev/null +++ b/configs/arm64/imx8mm.c @@ -0,0 +1,202 @@ +/* + * i.MX8MM Target + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: reg = <0x0 0xffaf0000 0x0 0x510000> + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xb7c00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + .type = JAILHOUSE_CON_TYPE_IMX, + }, + .platform_info = { + /* + * .pci_mmconfig_base is fixed; if you change it, + * update the value in mach.h + * (PCI_CFG_BASE) and regenerate the inmate library + */ + .pci_mmconfig_base = 0xbb800000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + + .arm = { + .gic_version = 3, + .gicd_base = 0x38800000, + .gicr_base = 0x38880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "imx8mm", + + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 51, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 */ { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ , + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbb00000, 0), + /* IO */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x38800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM 00*/ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x73c00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */{ + .phys_start = 0xb3c00000, + .virt_start = 0xb3c00000, + .size = 0x04000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM 01 */ { + .phys_start = 0xb8000000, + .virt_start = 0xb8000000, + .size = 0x03700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Loader */{ + .phys_start = 0xbb700000, + .virt_start = 0xbb700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM 02 */ { + .phys_start = 0xbbc00000, + .virt_start = 0xbbc00000, + .size = 0x02400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* OP-TEE reserved memory */{ + .phys_start = 0xbe000000, + .virt_start = 0xbe000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mn-inmate-demo.c b/configs/arm64/imx8mn-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6f04a5b300eab4813a3b8495bae400b3ca50ba87 --- /dev/null +++ b/configs/arm64/imx8mn-inmate-demo.c @@ -0,0 +1,126 @@ +/* + * iMX8MN target - inmate-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + /* IVSHMEM_IRQ - 32 */ + .vpci_irq_base = 124, /* Not include 32 base */ + + .console = { + .address = 0x30890000, + .type = JAILHOUSE_CON_TYPE_IMX, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART2 */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: start from the bottom of inmate memory */ { + .phys_start = 0xb3c00000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 128, + .pin_bitmap = { + 0x1 << (124 + 32 - 128) /* SPI 124 */ + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/imx8mn-linux-demo.c b/configs/arm64/imx8mn-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..3644b6d1fc49a6584da44f61dc9a35d8c8e80d51 --- /dev/null +++ b/configs/arm64/imx8mn-linux-demo.c @@ -0,0 +1,167 @@ +/* + * iMX8MN target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* + * Boot 2nd Linux cmdline: + * export PATH=$PATH:/usr/share/jailhouse/tools/ + * jailhouse cell linux imx8mn-linux-demo.cell Image -d imx8mn-ddr4-evk-inmate.dtb -c "clk_ignore_unused console=ttymxc3,115200 earlycon=ec_imx6q,0x30890000,115200 root=/dev/mmcblk2p2 rootwait rw" + */ +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[15]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 74, /* Not include 32 base */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbb00000, 1), + /* UART2 earlycon */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART4 */ { + .phys_start = 0x30a60000, + .virt_start = 0x30a60000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC1 */ { + .phys_start = 0x30b60000, + .virt_start = 0x30b60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xbb700000, + .virt_start = 0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + /* + * We could not use 0x80000000 which conflicts with + * COMM_REGION_BASE + */ + .phys_start = 0x93c00000, + .virt_start = 0x93c00000, + .size = 0x24000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* uart4/sdhc1 */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + (1 << (24 + 32 - 32)) | (1 << (29 + 32 - 32)) + }, + }, + /* IVSHMEM */ { + .address = 0x38800000, + .pin_base = 96, + .pin_bitmap = { + 0xf << (74 + 32 - 96) /* SPI 74-77 */ + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mn.c b/configs/arm64/imx8mn.c new file mode 100644 index 0000000000000000000000000000000000000000..91d088ae03ef552c4a20b0471d43b7bd14a255b7 --- /dev/null +++ b/configs/arm64/imx8mn.c @@ -0,0 +1,197 @@ +/* + * i.MX8MN Target + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: reg = <0x0 0xffaf0000 0x0 0x510000> + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xb7c00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + .type = JAILHOUSE_CON_TYPE_IMX, + }, + .platform_info = { + .pci_mmconfig_base = 0xbb800000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 0, + + .arm = { + .gic_version = 3, + .gicd_base = 0x38800000, + .gicr_base = 0x38880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "imx8mm", + + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 123, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xbba00000, + .virt_start = 0xbba00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbba01000, + .virt_start = 0xbba01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbba0a000, + .virt_start = 0xbba0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbba0c000, + .virt_start = 0xbba0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbba0e000, + .virt_start = 0xbba0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbb00000, 0), + /* IO */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x38800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM 00*/ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x73c00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */{ + .phys_start = 0xb3c00000, + .virt_start = 0xb3c00000, + .size = 0x04000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM 01 */ { + .phys_start = 0xb8000000, + .virt_start = 0xb8000000, + .size = 0x03700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Loader */{ + .phys_start = 0xbb700000, + .virt_start = 0xbb700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM 02 */ { + .phys_start = 0xbbc00000, + .virt_start = 0xbbc00000, + .size = 0x02400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* OP-TEE reserved memory */{ + .phys_start = 0xbe000000, + .virt_start = 0xbe000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mp-inmate-demo.c b/configs/arm64/imx8mp-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..127392df26f65b986ff3b39f1e759ad63a1e49ba --- /dev/null +++ b/configs/arm64/imx8mp-inmate-demo.c @@ -0,0 +1,126 @@ +/* + * iMX8MM target - inmate-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + /* IVSHMEM_IRQ - 32 */ + .vpci_irq_base = 76, /* Not include 32 base */ + + .console = { + .address = 0x30890000, + .type = JAILHOUSE_CON_TYPE_IMX, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90a000, + .virt_start = 0xfd90a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90c000, + .virt_start = 0xfd90c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90e000, + .virt_start = 0xfd90e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART2 */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: start from the bottom of inmate memory */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 96, + .pin_bitmap = { + 0x1 << (76 + 32 - 96) /* SPI 76 */ + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/imx8mp-linux-demo.c b/configs/arm64/imx8mp-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..22793c2a01af8077a13545b25165209cedcaacb1 --- /dev/null +++ b/configs/arm64/imx8mp-linux-demo.c @@ -0,0 +1,222 @@ +/* + * iMX8MM target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* + * Boot 2nd Linux cmdline: + * export PATH=$PATH:/usr/share/jailhouse/tools/ + * jailhouse cell linux imx8mp-linux-demo.cell Image -d imx8mp-evk-inmate.dtb -c "clk_ignore_unused console=ttymxc3,115200 earlycon=ec_imx6q,0x30890000,115200 root=/dev/mmcblk2p2 rootwait rw" + */ +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[23]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[4]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 154, /* Not include 32 base */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region (virtio-blk front) */ + { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0xdf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory region (virtio-con front) */ + { + .phys_start = 0xfd9e0000, + .virt_start = 0xfd9e0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd9e1000, + .virt_start = 0xfd9e1000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { 0 }, + { 0 }, + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ + { + .phys_start = 0xfd9f0000, + .virt_start = 0xfd9f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd9f1000, + .virt_start = 0xfd9f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd9fa000, + .virt_start = 0xfd9fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd9fc000, + .virt_start = 0xfd9fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd9fe000, + .virt_start = 0xfd9fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfda00000, 1), + /* UART2 earlycon */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART4 */ { + .phys_start = 0x30a60000, + .virt_start = 0x30a60000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC3 */ { + .phys_start = 0x30b60000, + .virt_start = 0x30b60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xfdb00000, + .virt_start = 0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + /* + * We could not use 0x80000000 which conflicts with + * COMM_REGION_BASE + */ + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3d700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* uart2/sdhc1 */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + (1 << (24 + 32 - 32)) | (1 << (29 + 32 - 32)) + }, + }, + /* IVSHMEM */ { + .address = 0x38800000, + .pin_base = 160, + .pin_bitmap = { + 0xf << (154 + 32 - 160) /* SPI 154-157 */ + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 2 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT + + VIRTIO_DEV_BLOCK, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 3 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT + + VIRTIO_DEV_CONSOLE, + }, + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 8, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 13, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mp.c b/configs/arm64/imx8mp.c new file mode 100644 index 0000000000000000000000000000000000000000..7fbf6ef76c0280945d2e07fdee1efc35c804a703 --- /dev/null +++ b/configs/arm64/imx8mp.c @@ -0,0 +1,242 @@ +/* + * i.MX8MP Target + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: reg = <0x0 0xffaf0000 0x0 0x510000> + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[23]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[4]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfdc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + .type = JAILHOUSE_CON_TYPE_IMX, + }, + .platform_info = { + .pci_mmconfig_base = 0xfd700000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 2, + + .arm = { + .gic_version = 3, + .gicd_base = 0x38800000, + .gicr_base = 0x38880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "imx8mp", + + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* gpt5/4/3/2 not used by root cell */ + .vpci_irq_base = 51, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region (virtio-blk back-end) */ + { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0xdf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory region (virtio-con back-end) */ + { + .phys_start = 0xfd9e0000, + .virt_start = 0xfd9e0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd9e1000, + .virt_start = 0xfd9e1000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { 0 }, + { 0 }, + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xfd9f0000, + .virt_start = 0xfd9f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd9f1000, + .virt_start = 0xfd9f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xfd9fa000, + .virt_start = 0xfd9fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xfd9fc000, + .virt_start = 0xfd9fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd9fe000, + .virt_start = 0xfd9fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfda00000, 0), + /* IO */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x38800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM 00*/ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */{ + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3d700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Loader */{ + .phys_start = 0xfdb00000, + .virt_start = 0xfdb00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* OP-TEE reserved memory?? */{ + .phys_start = 0xfe000000, + .virt_start = 0xfe000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* RAM04 */{ + .phys_start = 0x100000000, + .virt_start = 0x100000000, + .size = 0xC0000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 2 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK + + VIRTIO_DEV_BLOCK, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 3 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK + + VIRTIO_DEV_CONSOLE, + }, + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 8, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 13, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mq-inmate-demo.c b/configs/arm64/imx8mq-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..d1d518df6e528aad2af4b920a1828d57979d46b7 --- /dev/null +++ b/configs/arm64/imx8mq-inmate-demo.c @@ -0,0 +1,124 @@ +/* + * iMX8MQ target - inmate demo + * + * Copyright 2018-2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 108, + + .console = { + .address = 0x30860000, + .type = JAILHOUSE_CON_TYPE_IMX, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 */ { + .phys_start = 0xbfd00000, + .virt_start = 0xbfd00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd01000, + .virt_start = 0xbfd01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0a000, + .virt_start = 0xbfd0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0c000, + .virt_start = 0xbfd0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0e000, + .virt_start = 0xbfd0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART1 */ { + .phys_start = 0x30860000, + .virt_start = 0x30860000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 128, + .pin_bitmap = { + 0x1 << (108 + 32 - 128) /* SPI 109 */ + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/imx8mq-linux-demo.c b/configs/arm64/imx8mq-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..03e67a940563010b996f481a6c2ed47c49af2529 --- /dev/null +++ b/configs/arm64/imx8mq-linux-demo.c @@ -0,0 +1,158 @@ +/* + * iMX8MQ target - linux-demo + * + * Copyright 2018-2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[15]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 108, /* Not include 32 base */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 */ { + .phys_start = 0xbfd00000, + .virt_start = 0xbfd00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd01000, + .virt_start = 0xbfd01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0a000, + .virt_start = 0xbfd0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0c000, + .virt_start = 0xbfd0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xbfd0e000, + .virt_start = 0xbfd0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbfe00000, 1), + /* UART1 earlycon */ { + .phys_start = 0x30860000, + .virt_start = 0x30860000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART2 */ { + .phys_start = 0x30890000, + .virt_start = 0x30890000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC1 */ { + .phys_start = 0x30b40000, + .virt_start = 0x30b40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xbff00000, + .virt_start = 0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3dc00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* uart2/sdhc1 */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + (1 << (27 + 32 - 32)) | (1 << (22 + 32 - 32)) + }, + }, + /* IVSHMEM */ { + .address = 0x38800000, + .pin_base = 128, + .pin_bitmap = { + 0x1 << (108 + 32 - 128) /* SPI 109 */ + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8mq.c b/configs/arm64/imx8mq.c new file mode 100644 index 0000000000000000000000000000000000000000..e853e5f26d7a8109f19832e587803d74c852a960 --- /dev/null +++ b/configs/arm64/imx8mq.c @@ -0,0 +1,183 @@ +/* + * i.MX8MQ Target + * + * Copyright 2017-2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: reg = <0x0 0xffaf0000 0x0 0x510000> + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[14]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfdc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x30860000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_IMX, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xbfb00000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 2, + + .arm = { + .gic_version = 3, + .gicd_base = 0x38800000, + .gicr_base = 0x38880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "imx8mq", + + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 51, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 */ { + .phys_start = 0xbfd00000, + .virt_start = 0xbfd00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ , + }, + { + .phys_start = 0xbfd01000, + .virt_start = 0xbfd01000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbfd0a000, + .virt_start = 0xbfd0a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xbfd0c000, + .virt_start = 0xbfd0c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xbfd0e000, + .virt_start = 0xbfd0e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbfe00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x38800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x7fb00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Linux Loader */{ + .phys_start = 0xbff00000, + .virt_start = 0xbff00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */{ + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3dc00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* OP-TEE reserved memory */{ + .phys_start = 0xfe000000, + .virt_start = 0xfe000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x38800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x38800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 2, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/imx8qm-inmate-demo.c b/configs/arm64/imx8qm-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..1170a35fcb5a30e232425c9b53d61527548895c6 --- /dev/null +++ b/configs/arm64/imx8qm-inmate-demo.c @@ -0,0 +1,124 @@ +/* + * iMX8QM target - ivshmem-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 90, /* Not include 32 base */ + + .console = { + .address = 0x5a060000, + .type = JAILHOUSE_CON_TYPE_IMX_LPUART, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90a000, + .virt_start = 0xfd90a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90c000, + .virt_start = 0xfd90c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90e000, + .virt_start = 0xfd90e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART1 */ { + .phys_start = 0x5a060000, + .virt_start = 0x5a060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: from Inmate memory of imx8qm.c */ { + .phys_start = 0xdf700000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x51a00000, + .pin_base = 96, + .pin_bitmap = { + 0x1 << (90 + 32 - 96) /* irq 122 */ + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/imx8qm-linux-demo.c b/configs/arm64/imx8qm-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..0d2d91c908b0e32daaa09014b75f5a568f5bdc01 --- /dev/null +++ b/configs/arm64/imx8qm-linux-demo.c @@ -0,0 +1,202 @@ +/* + * iMX8QM target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[18]; + struct jailhouse_irqchip irqchips[4]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "imx8qm-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 124, /* Not include 32 base */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90a000, + .virt_start = 0xfd90a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90c000, + .virt_start = 0xfd90c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfd90e000, + .virt_start = 0xfd90e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfda00000, 1), + /* UART0 earlycon */ { + .phys_start = 0x5a060000, + .virt_start = 0x5a060000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART2*/ { + .phys_start = 0x5a080000, + .virt_start = 0x5a080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* UART2_LPCG*/ { + .phys_start = 0x5a480000, + .virt_start = 0x5a480000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC0 */ { + .phys_start = 0x5b010000, + .virt_start = 0x5b010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SHDC0_LPCG */ { + .phys_start = 0x5b200000, + .virt_start = 0x5b200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MU2 */ { + .phys_start = 0x5d1d0000, + .virt_start = 0x5d1d0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM: Top at 4GB Space */ { + .phys_start = 0xdf700000, + .virt_start = 0xdf700000, + .size = 0x1e000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM: Bottom at 4GB Space */ { + .phys_start = 0xfdb00000, + .virt_start = 0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* IVSHMEM */ { + .address = 0x51a00000, + .pin_base = 128, + .pin_bitmap = { + 0xf << (124 + 32 - 128) + }, + }, + /* MU2_A */ { + .address = 0x51a00000, + .pin_base = 192, + .pin_bitmap = { + (1 << (178 + 32 - 192)) + }, + }, + /* sdhc1 */ { + .address = 0x51a00000, + .pin_base = 256, + .pin_bitmap = { + (1 << (232 + 32 - 256)) + }, + }, + /* lpuart2 */ { + .address = 0x51a00000, + .pin_base = 352, + .pin_bitmap = { + (1 << (347 + 32 - 352)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + { + .mmu500.id = 0x10, + .mmu500.mask_out = 0x7f8, + }, + }, +}; diff --git a/configs/arm64/imx8qm.c b/configs/arm64/imx8qm.c new file mode 100644 index 0000000000000000000000000000000000000000..052a58d4d98f76ad77d806ee8c20a318e95c19cc --- /dev/null +++ b/configs/arm64/imx8qm.c @@ -0,0 +1,223 @@ +/* + * i.MX8QM Target + * + * Copyright 2020 NXP + * + * Authors: + * Peng Fan + * Alice Guo + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[15]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[3]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfdc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x5a060000, + .size = 0x1000, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + .type = JAILHOUSE_CON_TYPE_IMX_LPUART, + }, + .platform_info = { + /* + * .pci_mmconfig_base is fixed; if you change it, + * update the value in mach.h + * (PCI_CFG_BASE) and regenerate the inmate library + */ + .pci_mmconfig_base = 0xfd700000, + .pci_mmconfig_end_bus = 0x0, + .pci_is_virtual = 1, + .pci_domain = 0, + + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_ARM_MMU500, + .base = 0x51400000, + .size = 0x40000, + }, + }, + + .arm = { + .gic_version = 3, + .gicd_base = 0x51a00000, + .gicr_base = 0x51b00000, + .maintenance_irq = 25, + }, + }, + + .root_cell = { + .name = "imx8qm", + + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .num_irqchips = ARRAY_SIZE(config.irqchips), + /* + * vpci_irq_base not include base 32 + */ + .vpci_irq_base = 53, + }, + }, + + .cpus = { + 0x3f, + }, + + .mem_regions = { + /* IVHSMEM shared memory region for 00:00.0 (demo )*/ { + .phys_start = 0xfd900000, + .virt_start = 0xfd900000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd901000, + .virt_start = 0xfd901000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xfd90a000, + .virt_start = 0xfd90a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0xfd90c000, + .virt_start = 0xfd90c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfd90e000, + .virt_start = 0xfd90e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfda00000, 0), + /* MMIO (permissive): TODO: refine the map */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + + /* RAM */ { + .phys_start = 0x80200000, + .virt_start = 0x80200000, + .size = 0x5f500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate memory */ { + .phys_start = 0xdf700000, + .virt_start = 0xdf700000, + .size = 0x1e000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Loader */{ + .phys_start = 0xfdb00000, + .virt_start = 0xfdb00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* OP-TEE reserved memory */{ + .phys_start = 0xfe000000, + .virt_start = 0xfe000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* RAM2 */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x51a00000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x51a00000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x51a00000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + { + .mmu500.id = 0x11, + .mmu500.mask_out = 0x7f8, + }, + { + .mmu500.id = 0x12, + .mmu500.mask_out = 0x7f8, + }, + { + .mmu500.id = 0x13, + .mmu500.mask_out = 0x7f8, + }, + }, +}; diff --git a/configs/arm64/jetson-tx1-inmate-demo.c b/configs/arm64/jetson-tx1-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..1cfbe7f7e7221617d7f670b0355a6935ec6f6b33 --- /dev/null +++ b/configs/arm64/jetson-tx1-inmate-demo.c @@ -0,0 +1,67 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Nvidia Jetson TX1: + * 1 CPU, 64K RAM, serial port 0 + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "jetson-tx1-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0x70006000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x17bef0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, +}; diff --git a/configs/arm64/jetson-tx1-linux-demo.c b/configs/arm64/jetson-tx1-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..c5f2d8113b716d1302c7c3fad125b2c692ecaab2 --- /dev/null +++ b/configs/arm64/jetson-tx1-linux-demo.c @@ -0,0 +1,122 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Jetson TX1: + * 2 CPUs, 428M RAM, serial port D + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Note: the root Linux should be started with "mem=3584M" + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "jetson-tx1-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 152, + + .cpu_reset_address = CONFIG_INMATE_BASE, + + .console = { + .address = 0x70006000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x17bf00000, 1), + /* UART */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x17bef0000, + .virt_start = CONFIG_INMATE_BASE, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x161200000, + .virt_start = 0xe8000000, + .size = 0x1acf0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x50041000, + .pin_base = 32, + .pin_bitmap = { + 0, (1 << (36 % 32)), 0, 0 + }, + }, + /* GIC */ { + .address = 0x50041000, + .pin_base = 160, + .pin_bitmap = { + 1 << (153+32 - 160), + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/jetson-tx1.c b/configs/arm64/jetson-tx1.c new file mode 100644 index 0000000000000000000000000000000000000000..c9dbec870d85c3d6522018dd28f0d362e4be4913 --- /dev/null +++ b/configs/arm64/jetson-tx1.c @@ -0,0 +1,401 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Jailhouse Jetson TX1 board + * + * Copyright (C) 2016 Evidence Srl + * + * Authors: + * Claudio Scordino + * Bruno Morelli + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=3968M" to the kernel command line. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[46]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x17c000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0x70006000, + .size = 0x0040, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x48000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 2, + .gicd_base = 0x50041000, + .gicc_base = 0x50042000, + .gich_base = 0x50044000, + .gicv_base = 0x50046000, + .maintenance_irq = 25, + } + }, + .root_cell = { + .name = "Jetson-TX1", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 148, + }, + }, + + .cpus = { + 0xf, + }, + + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x17bf00000, 0), + /* APE 1 */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x00D00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCIE */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x3F000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Data memory */ { + .phys_start = 0x040000000, + .virt_start = 0x040000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* host1x */ { + .phys_start = 0x50000000, + .virt_start = 0x50000000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Graphics Host */ { + .phys_start = 0x54000000, + .virt_start = 0x54000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPU */ { + .phys_start = 0x57000000, + .virt_start = 0x57000000, + .size = 0x9000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Semaphores */ { + .phys_start = 0x60000000, + .virt_start = 0x60000000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Legacy Interrupt Controller (ICTRL) */ { + .phys_start = 0x60004000, + .virt_start = 0x60004000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* TMR */ { + .phys_start = 0x60005000, + .virt_start = 0x60005000, + .size = 0x01000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Clock and Reset */ { + .phys_start = 0x60006000, + .virt_start = 0x60006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Flow Controller */ { + .phys_start = 0x60007000, + .virt_start = 0x60007000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* AHB-DMA */ { + .phys_start = 0x60008000, + .virt_start = 0x60008000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* System registers, secure boot, activity monitor */ { + .phys_start = 0x6000c000, + .virt_start = 0x6000c000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPIOs + exception vectors */ { + .phys_start = 0x6000d000, + .virt_start = 0x6000d000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IPATCH */ { + .phys_start = 0x60010000, + .virt_start = 0x60010000, + .size = 0x0010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* APB-DMA + VGPIO */ { + .phys_start = 0x60020000, + .virt_start = 0x60020000, + .size = 0x5000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MISC stuff (see datasheet) */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* UARTs */ { + .phys_start = 0x70006000, + .virt_start = 0x70006000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PWM Controller */ { + .phys_start = 0x7000a000, + .virt_start = 0x7000a000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* I2C + SPI*/ { + .phys_start = 0x7000c000, + .virt_start = 0x7000c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RTC + PMC + FUSE + KFUSE */ { + .phys_start = 0x7000e000, + .virt_start = 0x7000e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Sensors */ { + .phys_start = 0x70010000, + .virt_start = 0x70010000, + .size = 0x0008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MC */ { + .phys_start = 0x70019000, + .virt_start = 0x70019000, + .size = 0x7000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SATA */ { + .phys_start = 0x70020000, + .virt_start = 0x70020000, + .size = 0x0010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HDA */ { + .phys_start = 0x70030000, + .virt_start = 0x70030000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CLUSTER CLOCK */ { + .phys_start = 0x70040000, + .virt_start = 0x70040000, + .size = 0x0040000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* XUSB */ { + .phys_start = 0x70090000, + .virt_start = 0x70090000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DDS */ { + .phys_start = 0x700a0000, + .virt_start = 0x700a0000, + .size = 0x0002000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SDMMCs */ { + .phys_start = 0x700b0000, + .virt_start = 0x700b0000, + .size = 0x5000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SPEEDO */ { + .phys_start = 0x700c0000, + .virt_start = 0x700c0000, + .size = 0x0008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DP2 + APB2JTAG */ { + .phys_start = 0x700e0000, + .virt_start = 0x700e0000, + .size = 0x0002000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SOC_THERM */ { + .phys_start = 0x700e2000, + .virt_start = 0x700e2000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MIPI_CAL */ { + .phys_start = 0x700e3000, + .virt_start = 0x700e3000, + .size = 0x100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SYSCTR0 */ { + .phys_start = 0x700f0000, + .virt_start = 0x700f0000, + .size = 0x0010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SYSCTR1 */ { + .phys_start = 0x70100000, + .virt_start = 0x70100000, + .size = 0x0010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DVFS */ { + .phys_start = 0x70110000, + .virt_start = 0x70110000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* APE 2 */ { + .phys_start = 0x702c0000, + .virt_start = 0x702c0000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* QSPI */ { + .phys_start = 0x70410000, + .virt_start = 0x70410000, + .size = 0x0001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* STM + CSITE */ { + .phys_start = 0x71000000, + .virt_start = 0x71000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* AHB_A1 */ { + .phys_start = 0x78000000, + .virt_start = 0x78000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* AHB_A2 or USB */ { + .phys_start = 0x7c000000, + .virt_start = 0x7c000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* System RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0xfc000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + .irqchips = { + /* GIC */ { + .address = 0x50041000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x50041000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/jetson-tx2-inmate-demo.c b/configs/arm64/jetson-tx2-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..ed1a7d970da0c99afaa9e3c8f14bf201b6a0ab3e --- /dev/null +++ b/configs/arm64/jetson-tx2-inmate-demo.c @@ -0,0 +1,62 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Nvidia Jetson TX2: + * 1 CPU, 64 MB RAM, serial port 0 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "jetson-tx2-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + + .console = { + .address = 0x3100000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x1, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0x3100000, + .virt_start = 0x3100000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x270000000, + .virt_start = 0, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, +}; diff --git a/configs/arm64/jetson-tx2.c b/configs/arm64/jetson-tx2.c new file mode 100644 index 0000000000000000000000000000000000000000..58f7d4886d1fa4eaadd190a949bbec03ea729119 --- /dev/null +++ b/configs/arm64/jetson-tx2.c @@ -0,0 +1,525 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Jailhouse Jetson TX2 board + * + * Copyright (C) 2018 Evidence Srl + * + * Authors: + * Claudio Scordino + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=7808M" to the kernel command line. + * + * 2:7000:0000 inmate (size: 100:0000 = 16 MB) + * 2:7100:0000 hypervisor (size: 400:0000 = 64 MB) + * + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[61]; + struct jailhouse_irqchip irqchips[3]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x271000000, + .size = 0x4000000, + }, + .debug_console = { + .address = 0x3100000, + .size = 0x10000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + + .arm = { + .gicd_base = 0x03881000, + .gicc_base = 0x03882000, + .gich_base = 0x03884000, + .gicv_base = 0x03886000, + .gic_version = 2, + .maintenance_irq = 25, + } + }, + .root_cell = { + .name = "Jetson-TX2", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + }, + }, + + .cpus = { + 0x39, + }, + + + .mem_regions = { + /* BPMP_ATCM */ { + .phys_start = 0x00000000, + .virt_start = 0x00000000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + + /* MISC */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + + /* AXIP2P */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* GPIO_CTL */ { + .phys_start = 0x02200000, + .virt_start = 0x02200000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TSA */ { + .phys_start = 0x2400000, + .virt_start = 0x2400000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PADCTL_A (PINMUX) */ { + .phys_start = 0x02430000, + .virt_start = 0x02430000, + .size = 0x15000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* UFSHC */ { + .phys_start = 0x02450000, + .virt_start = 0x02450000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* ETHER_QOS */ { + .phys_start = 0x02490000, + .virt_start = 0x02490000, + .size = 0x50000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* GPCDMA */ { + .phys_start = 0x02600000, + .virt_start = 0x02600000, + .size = 0x210000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* APE */ { + .phys_start = 0x02900000, + .virt_start = 0x02900000, + .size = 0x200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* MSS */ { + .phys_start = 0x02c00000, + .virt_start = 0x02c00000, + .size = 0xb0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* LIC */ { + .phys_start = 0x03000000, + .virt_start = 0x03000000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TOP_TKE */ { + .phys_start = 0x03010000, + .virt_start = 0x03010000, + .size = 0xe0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TIMER */ { + .phys_start = 0x03020000, + .virt_start = 0x03020000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* UARTA */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* UART-B */ { + .phys_start = 0x03110000, + .virt_start = 0x03110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* I2C */ { + .phys_start = 0x03160000, + .virt_start = 0x03160000, + .size = 0x90000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PWM1 + PWM2 */ { + .phys_start = 0x03280000, + .virt_start = 0x03280000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PWM3 - PWM8 */ { + .phys_start = 0x032a0000, + .virt_start = 0x032a0000, + .size = 0x60000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SDMMC */ { + .phys_start = 0x3400000, + .virt_start = 0x3400000, + .size = 0x80000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SATA */ { + .phys_start = 0x3500000, + .virt_start = 0x3500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* HDA */ { + .phys_start = 0x3510000, + .virt_start = 0x3510000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* XUSB_PADCTL + XUSB_HOST */ { + .phys_start = 0x3520000, + .virt_start = 0x3520000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* XUSB */ { + .phys_start = 0x03540000, + .virt_start = 0x03540000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* FUSE + KFUSE */ { + .phys_start = 0x03820000, + .virt_start = 0x03820000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* MIPICAL */ { + .phys_start = 0x03990000, + .virt_start = 0x03990000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TACH_0 */ { + .phys_start = 0x039c0000, + .virt_start = 0x039c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SE0 */ { + .phys_start = 0x03ac0000, + .virt_start = 0x03ac0000, + .size = 0x30000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TOP0_HSP */{ + .phys_start = 0x03c00000, + .virt_start = 0x03c00000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* VIC CAR */{ + .phys_start = 0x05560000, + .virt_start = 0x05560000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* CSITE */ { + .phys_start = 0x08000000, + .virt_start = 0x08000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SCE VIC registers */ { + .phys_start = 0x0b020000, + .virt_start = 0x0b020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SCE_PM */ { + .phys_start = 0x0b1f0000, + .virt_start = 0x0b1f0000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SCE_CFG */ { + .phys_start = 0x0b230000, + .virt_start = 0x0b230000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* AON VIC registers */ { + .phys_start = 0x0c020000, + .virt_start = 0x0c020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* More I2C + SPI */ { + .phys_start = 0x0c230000, + .virt_start = 0x0c230000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* UARTC, UARTG, RTC, TSC */ { + .phys_start = 0x0c280000, + .virt_start = 0x0c280000, + .size = 0x70000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* AON_GPIO_0 */ { + .phys_start = 0x0c2f0000, + .virt_start = 0x0c2f0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* AON_PADCTL_0 (PINMUX) */ { + .phys_start = 0x0c300000, + .virt_start = 0x0c300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PMC */ { + .phys_start = 0x0c360000, + .virt_start = 0x0c360000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* BPMP VIC registers */ { + .phys_start = 0x0d020000, + .virt_start = 0x0d020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* ACTMON + SIMON + SOC_THERM */ { + .phys_start = 0x0d230000, + .virt_start = 0x0d230000, + .size = 0x70000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /*CCPLEX CLUSTER*/{ + .phys_start = 0x0e000000, + .virt_start = 0x0e000000, + .size = 0x400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PCIE0 */ { + .phys_start = 0x10000000, + .virt_start = 0x10000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SMMU0 */ { + .phys_start = 0x12000000, + .virt_start = 0x12000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* HOST1X */ { + .phys_start = 0x13e00000, + .virt_start = 0x13e00000, + .size = 0x90000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* HOST1X_ACTMON */ { + .phys_start = 0x13ec0000, + .virt_start = 0x13ec0000, + .size = 0x50000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DPAUX1 */ { + .phys_start = 0x15040000, + .virt_start = 0x15040000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* NVCSI */ { + .phys_start = 0x150c0000, + .virt_start = 0x150c0000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* TSECB */ { + .phys_start = 0x15100000, + .virt_start = 0x15100000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* NVDISPLAY */ { + .phys_start = 0x15200000, + .virt_start = 0x15200000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* VIC */ { + .phys_start = 0x15340000, + .virt_start = 0x15340000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* NVJPG */ { + .phys_start = 0x15380000, + .virt_start = 0x15380000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* NVDEC + NVENC + TSEC + ISP + SOR */ { + .phys_start = 0x15480000, + .virt_start = 0x15480000, + .size = 0x1c0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* NI */ { + .phys_start = 0x15700000, + .virt_start = 0x15700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SE1-SE4 */ { + .phys_start = 0x15810000, + .virt_start = 0x15810000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* GPU */ { + .phys_start = 0x17000000, + .virt_start = 0x17000000, + .size = 0x9000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* SYSRAM_0 */{ + .phys_start = 0x30000000, + .virt_start = 0x30000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + + /* System RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x1F0000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Inmate */ { + .phys_start = 0x270000000, + .virt_start = 0x270000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Persistent RAM */ { + .phys_start = 0x277080000, + .virt_start = 0x277080000, + .size = 0x200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + .irqchips = { + /* GIC */ { + .address = 0x03881000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x03881000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x03881000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, + }, + }, + }, + +}; diff --git a/configs/arm64/k3-am625-sk-inmate-demo.c b/configs/arm64/k3-am625-sk-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..49edd62d1811f1e6190902dd05feacfd22c8004e --- /dev/null +++ b/configs/arm64/k3-am625-sk-inmate-demo.c @@ -0,0 +1,72 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on K3 based platforms. + * 1CPU, 64K RAM, 1 serial port(MAIN UART 1). + * + * Copyright (c) 2019, 2022 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * Matt Ranostay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0x02810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* MAIN UART1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xe0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/k3-am625-sk-linux-demo.c b/configs/arm64/k3-am625-sk-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..a3385efc4df82cf2e823a8e7b64b22a612ce856b --- /dev/null +++ b/configs/arm64/k3-am625-sk-linux-demo.c @@ -0,0 +1,220 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on AM625 based platforms + * 3 CPUs, 512MB RAM, 1 serial port (MAIN UART1) + * + * Copyright (c) 2022 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Matt Ranostay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0000000 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[18]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "k3-am625-sk-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_reset_address = 0x0, + .vpci_irq_base = 189 - 32, + + .console = { + .address = 0x02810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xe, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0xdfa00000, + .virt_start = 0xdfa00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xdfa10000, + .virt_start = 0xdfa10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 0 */ { + .phys_start = 0xdfa20000, + .virt_start = 0xdfa20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 1 */ { + .phys_start = 0xdfa30000, + .virt_start = 0xdfa30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 2 */ { + .phys_start = 0xdfa40000, + .virt_start = 0xdfa40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xdfb00000, 1), + /* RAM load */ { + .phys_start = 0xffff0000, + .virt_start = 0x0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM load */ { + .phys_start = 0xe0000000, + .virt_start = 0xe0000000, + .size = 0x1fff0000, /* (512MB - 64KB) */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* MAIN UART1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, +#ifdef CONFIG_ENABLE_AM625_INMATE_CELL_EMMC + /* sdhci0 */ { + .phys_start = 0x0fa10000, + .virt_start = 0x0fa10000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sdhci0 */ { + .phys_start = 0x0fa18000, + .virt_start = 0x0fa18000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, +#endif + /* main sproxy target_data host_id=A53_3 */ { + .phys_start = 0x4d00e000, + .virt_start = 0x4d00e000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy rt host_id=A53_3 */ { + .phys_start = 0x4a60e000, + .virt_start = 0x4a60e000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy scfg host_id=A53_3 */ { + .phys_start = 0x4a40e000, + .virt_start = 0x4a40e000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* + * offset = (SPI_NR + 32 - base) / 32 + * bit = (SPI_NR + 32 - base) % 32 + */ + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0, + /* sproxy rx_014 */ + 1 << (67 - 64), + 0, 0 + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { +#ifdef CONFIG_ENABLE_AM625_INMATE_CELL_EMMC + /* sdhc */ + 1 << (165 - 160) | +#endif + /* vpci */ + 1 << (189 - 160) | + 1 << (190 - 160), + /* uart */ + 1 << (211 - 192), + 0, 0, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0, 0, 0, 0, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/k3-am625-sk.c b/configs/arm64/k3-am625-sk.c new file mode 100644 index 0000000000000000000000000000000000000000..2e5c3aefe535feadf5831e1e6d24c2835a66a3be --- /dev/null +++ b/configs/arm64/k3-am625-sk.c @@ -0,0 +1,317 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2022 Texas Instruments Incorporated - http://www.ti.com/ + * + * Configuration for K3 based AM625 EVM + * + * Authors: + * Matt Ranostay + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[31]; + struct jailhouse_irqchip irqchips[5]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xdfc00000, + .size = 0x400000, + }, + .debug_console = { + .address = 0x02800000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x76000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 3, + .gicd_base = 0x01800000, + .gicr_base = 0x01880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "k3-am625-sk", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 180 - 32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0xdfa00000, + .virt_start = 0xdfa00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xdfa10000, + .virt_start = 0xdfa10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Peer 0 */ { + .phys_start = 0xdfa20000, + .virt_start = 0xdfa20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Peer 1 */ { + .phys_start = 0xdfa30000, + .virt_start = 0xdfa30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* Peer 2 */ { + .phys_start = 0xdfa40000, + .virt_start = 0xdfa40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xdfb00000, 0), + { + .phys_start = 0x01810000, + .virt_start = 0x01810000, + .size = 0x00070000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + { + .phys_start = 0x018a0000, + .virt_start = 0x018a0000, + .size = 0x00060000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x5fa00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM. Reserved for inmates */ { + .phys_start = 0xe0000000, + .virt_start = 0xe0000000, + .size = 0x20000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* ctrl mmr */ { + .phys_start = 0x000f0000, + .virt_start = 0x000f0000, + .size = 0x00030000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPIO */ { + .phys_start = 0x00600000, + .virt_start = 0x00600000, + .size = 0x00002000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPU */ { + .phys_start = 0x0fd00000, + .virt_start = 0x0fd00000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* TimeSync Router */ { + .phys_start = 0x00a40000, + .virt_start = 0x00a40000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* First peripheral window, 1 of 2 */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* First peripheral window, 2 of 2 */ { + .phys_start = 0x01900000, + .virt_start = 0x01900000, + .size = 0x01229000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Second peripheral window */ { + .phys_start = 0x0e000000, + .virt_start = 0x0e000000, + .size = 0x01d00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Third peripheral window */ { + .phys_start = 0x20000000, + .virt_start = 0x20000000, + .size = 0x0a008000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* OCSRAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DSS */ { + .phys_start = 0x30200000, + .virt_start = 0x30200000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DMSS */ { + .phys_start = 0x48000000, + .virt_start = 0x48000000, + .size = 0x06400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PRUSS-M */ { + .phys_start = 0x30040000, + .virt_start = 0x30040000, + .size = 0x00080000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x31000000, + .virt_start = 0x31000000, + .size = 0x00050000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x31100000, + .virt_start = 0x31100000, + .size = 0x00050000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* CPSW */ { + .phys_start = 0x08000000, + .virt_start = 0x08000000, + .size = 0x00200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* First Wake Up Domain */ { + .phys_start = 0x2b000000, + .virt_start = 0x2b000000, + .size = 0x00301000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Second Wake Up Domain */ { + .phys_start = 0x43000000, + .virt_start = 0x43000000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU Domain Range */ { + .phys_start = 0x04000000, + .virt_start = 0x04000000, + .size = 0x01ff2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/k3-am654-idk-linux-demo.c b/configs/arm64/k3-am654-idk-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..3937dff37f48985081fc50fca4e148d54d14eb5f --- /dev/null +++ b/configs/arm64/k3-am654-idk-linux-demo.c @@ -0,0 +1,211 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on AM654 based platforms + * 2 CPUs, 512MB RAM, 1 serial port(MCU UART) + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0000000 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[19]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "k3-am654-idk-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_reset_address = 0x0, + .vpci_irq_base = 189 - 32, + + .console = { + .address = 0x40a00000, + .divider = 0x35, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x8dfa00000, + .virt_start = 0x8dfa00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x8dfa10000, + .virt_start = 0x8dfa10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 0 */ { + .phys_start = 0x8dfa20000, + .virt_start = 0x8dfa20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 1 */ { + .phys_start = 0x8dfa30000, + .virt_start = 0x8dfa30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Peer 2 */ { + .phys_start = 0x8dfa40000, + .virt_start = 0x8dfa40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x8dfb00000, 1), + /* RAM load */ { + .phys_start = 0x8FFFF0000, + .virt_start = 0x0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM load */ { + .phys_start = 0x8e0000000, + .virt_start = 0x8e0000000, + .size = 0x1fff0000, /* (512MB - 64KB) */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* MCU UART0 */ { + .phys_start = 0x40a00000, + .virt_start = 0x40a00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, +#ifdef CONFIG_AM654_INMATE_CELL_EMMC + /* sdhci0 */ { + .phys_start = 0x4f80000, + .virt_start = 0x4f80000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sdhci0 */ { + .phys_start = 0x4f90000, + .virt_start = 0x4f90000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, +#endif + /* main sproxy target_data host_id=A53_3 */ { + .phys_start = 0x3240f000, + .virt_start = 0x3240f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy rt host_id=A53_3 */ { + .phys_start = 0x3280f000, + .virt_start = 0x3280f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy scfg host_id=A53_3 */ { + .phys_start = 0x32c0f000, + .virt_start = 0x32c0f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0x0, 0x80, 0x00, 0, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { +#ifdef CONFIG_AM654_INMATE_CELL_EMMC + /* sdhc */ + 1 << (168 - 160) | +#endif + /* vpci */ + 1 << (189 - 160) | + 1 << (190 - 160), + 0x00, 0x00, 0, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0, 0x200000, 0, 0, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/k3-am654-idk.c b/configs/arm64/k3-am654-idk.c new file mode 100644 index 0000000000000000000000000000000000000000..48b8f8670db0f4f56a450af036763bf5a8cc919e --- /dev/null +++ b/configs/arm64/k3-am654-idk.c @@ -0,0 +1,275 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Configuration for K3 based AM654 IDK + * + * Authors: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[25]; + struct jailhouse_irqchip irqchips[5]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x8dfc00000, + .size = 0x400000, + }, + .debug_console = { + .address = 0x02800000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x76000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 3, + .gicd_base = 0x01800000, + .gicr_base = 0x01880000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "k3-am654-idk", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 170 - 32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x8dfa00000, + .virt_start = 0x8dfa00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x8dfa10000, + .virt_start = 0x8dfa10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Peer 0 */ { + .phys_start = 0x8dfa20000, + .virt_start = 0x8dfa20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Peer 1 */ { + .phys_start = 0x8dfa30000, + .virt_start = 0x8dfa30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* Peer 2 */ { + .phys_start = 0x8dfa40000, + .virt_start = 0x8dfa40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x8dfb00000, 0), + /* RAM */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x5fa00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM. Reserved for inmates */ { + .phys_start = 0x8E0000000, + .virt_start = 0x8E0000000, + .size = 0x20000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* ctrl mmr */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPIO */ { + .phys_start = 0x00600000, + .virt_start = 0x00600000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serdes */ { + .phys_start = 0x00900000, + .virt_start = 0x00900000, + .size = 0x00012000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Most MAIN domain peripherals */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + { + .phys_start = 0x01810000, + .virt_start = 0x01810000, + .size = 0x00070000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + { + .phys_start = 0x018a0000, + .virt_start = 0x018a0000, + .size = 0xa664000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MAIN NAVSS */ { + .phys_start = 0x30800000, + .virt_start = 0x30800000, + .size = 0x0bc00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x28380000, + .virt_start = 0x28380000, + .size = 0x03880000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x40200000, + .virt_start = 0x40200000, + .size = 0x00901000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x42040000, + .virt_start = 0x42040000, + .size = 0x030c0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x45100000, + .virt_start = 0x45100000, + .size = 0x00c24000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x46000000, + .virt_start = 0x46000000, + .size = 0x00200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCUSS */ { + .phys_start = 0x47000000, + .virt_start = 0x47000000, + .size = 0x00069000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/k3-am654-inmate-demo.c b/configs/arm64/k3-am654-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..003674710625a5581f352365d1db796a0426e848 --- /dev/null +++ b/configs/arm64/k3-am654-inmate-demo.c @@ -0,0 +1,71 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on K3 based platforms. + * 1CPU, 64K RAM, 1 serial port(MCU UART 0). + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0x40a00000, + .divider = 0x35, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* MCU UART0 */ { + .phys_start = 0x40a00000, + .virt_start = 0x40a00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x8e0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/k3-j7200-evm-inmate-demo.c b/configs/arm64/k3-j7200-evm-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..c916b439185588074615e530297d524799b3577d --- /dev/null +++ b/configs/arm64/k3-j7200-evm-inmate-demo.c @@ -0,0 +1,128 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on K3 J7200 based platforms. + * 1CPU, 64K RAM, 1 serial port. + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "k3-j7200 inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 1, + .num_pci_devices = 1, + .vpci_irq_base = 195 - 32, + + .console = { + .address = 0x02810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_MDR_QUIRK | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE, + }, + /* main_uart1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x89ff40000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + { + .address = 0x01800000, + .pin_base = 160, + /* + * virtual PCI SPI_163 => idx 1 bit [3] + */ + .pin_bitmap = { + 0x00000000, 0x00000008, 0x00000000, 0x00000000, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/k3-j7200-evm-linux-demo.c b/configs/arm64/k3-j7200-evm-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..1fc98bf87942193b2460ab96aeea3590191e523b --- /dev/null +++ b/configs/arm64/k3-j7200-evm-linux-demo.c @@ -0,0 +1,238 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on J7200 based platforms + * 1 CPUs, 512MB RAM, 1 serial port + * + * Copyright (c) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0000000 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[19]; + struct jailhouse_irqchip irqchips[3]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "k3-j7200-evm-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .cpu_reset_address = 0x0, + .vpci_irq_base = 195 - 32, + .console = { + .address = 0x2810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x89fe40000, 1), + /* ctrl mmr */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Main.uart1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sdhci0 */ { + .phys_start = 0x4f80000, + .virt_start = 0x4f80000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sdhci0 */ { + .phys_start = 0x4f88000, + .virt_start = 0x4f88000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main_gpio2 */ { + .phys_start = 0x00610000, + .virt_start = 0x00610000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy rt host_id=A72_3 */ { + .phys_start = 0x3240f000, + .virt_start = 0x3240f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy scfg host_id=A72_3 */ { + .phys_start = 0x3280f000, + .virt_start = 0x3280f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy target_data host_id=A72_3 */ { + .phys_start = 0x32c0f000, + .virt_start = 0x32c0f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* linux-loader space */ { + .phys_start = 0x89ff40000, + .virt_start = 0x0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM. */ { + .phys_start = 0x8a0000000, + .virt_start = 0x8a0000000, + .size = 0x60000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* + * offset = (SPI_NR + 32 - base) / 32 + * bit = (SPI_NR + 32 - base) % 32 + */ + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + /* sdhci0 */ + (1 << (35 - 32)), + /* sproxy_rx_016 */ + (1 << (71 - 64)), + 0x00000000, + 0x00000000, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { + 0x00000000, + /* virtual PCI */ + (1 << (195 - 192)), + /* main_uart1 */ + (1 << (225 - 224)), + 0x00000000, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + .pin_bitmap = { + /* + * main_gpio_intr slot SPI 392 to 416 + * this should match with SYSFW rm-cfg.c + */ + 0xffffff00, + 0x00000000, + 0x00000000, + 0x00000000, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + /* Non PCIe peripherals */ + {0x0003}, + }, +}; diff --git a/configs/arm64/k3-j7200-evm.c b/configs/arm64/k3-j7200-evm.c new file mode 100644 index 0000000000000000000000000000000000000000..cc45215729af782e814490eefaf29da781589055 --- /dev/null +++ b/configs/arm64/k3-j7200-evm.c @@ -0,0 +1,359 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * + * Configuration for K3 based J7200-EVM + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[32]; + struct jailhouse_irqchip irqchips[6]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x89fa00000, + .size = 0x400000, + }, + .debug_console = { + .address = 0x02800000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_MDR_QUIRK | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x76000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 4, + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_PVU, + .base = 0x30f80000, + .size = 0x1000, + .tipvu.tlb_base = 0x36000000, + .tipvu.tlb_size = 0x40000, + }, + { + .type = JAILHOUSE_IOMMU_PVU, + .base = 0x30f81000, + .size = 0x1000, + .tipvu.tlb_base = 0x36040000, + .tipvu.tlb_size = 0x40000, + }, + }, + .arm = { + .gic_version = 3, + .gicd_base = 0x01800000, + .gicr_base = 0x01900000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "k3-j7200-evm", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .vpci_irq_base = 191 - 32, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x89fe40000, 0), + /* ctrl mmr */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio */ { + .phys_start = 0x00600000, + .virt_start = 0x00600000, + .size = 0x00032000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serdes */ { + .phys_start = 0x00900000, + .virt_start = 0x00900000, + .size = 0x00012000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* timesync router */ { + .phys_start = 0x00A40000, + .virt_start = 0x00A40000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Most peripherals */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x0d000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MAIN NAVSS */ { + .phys_start = 0x30000000, + .virt_start = 0x30000000, + .size = 0x0c400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MSMC SRAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCIe Core */ { + .phys_start = 0x18000000, + .virt_start = 0x18000000, + .size = 0x08000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCIe DAT */ { + .phys_start = 0x4100000000, + .virt_start = 0x4100000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* C71 */ { + .phys_start = 0x64800000, + .virt_start = 0x64800000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + + /* MCU NAVSS */ { + .phys_start = 0x28380000, + .virt_start = 0x28380000, + .size = 0x03880000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU First peripheral window */ { + .phys_start = 0x40200000, + .virt_start = 0x40200000, + .size = 0x00999000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU CTRL_MMR0 */ { + .phys_start = 0x40f00000, + .virt_start = 0x40f00000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU R5F Core0 */ { + .phys_start = 0x41000000, + .virt_start = 0x41000000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU R5F Core1 */ { + .phys_start = 0x41400000, + .virt_start = 0x41400000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU SRAM */ { + .phys_start = 0x41c00000, + .virt_start = 0x41c00000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* MCU WKUP peripheral window */ { + .phys_start = 0x42040000, + .virt_start = 0x42040000, + .size = 0x03ce4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU CPSW */ { + .phys_start = 0x46000000, + .virt_start = 0x46000000, + .size = 0x00200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU OSPI register space */ { + .phys_start = 0x47000000, + .virt_start = 0x47000000, + .size = 0x00069000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU FSS OSPI0/1 data region 0 */ { + .phys_start = 0x50000000, + .virt_start = 0x50000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + + /* RAM - first bank*/ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - second bank */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x1fa00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - reserved for baremetal apps */ { + .phys_start = 0x89ff40000, + .virt_start = 0x89ff40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - reserved for inmate */ { + .phys_start = 0x8a0000000, + .virt_start = 0x8a0000000, + .size = 0x60000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + }, + .irqchips = { + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 800, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + /* Non PCIe peripherals */ + {0x0002}, + }, +}; diff --git a/configs/arm64/k3-j721e-evm-inmate-demo.c b/configs/arm64/k3-j721e-evm-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..45a9202f45aeefd759939555267769b4171c9809 --- /dev/null +++ b/configs/arm64/k3-j721e-evm-inmate-demo.c @@ -0,0 +1,128 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on K3 based platforms. + * 1CPU, 64K RAM, 1 serial port. + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 1, + .num_pci_devices = 1, + .vpci_irq_base = 195 -32, + + .console = { + .address = 0x02810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_MDR_QUIRK | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE , + }, + /* main_uart1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x89ff40000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + { + .address = 0x01800000, + .pin_base = 160, + /* + * virtual PCI SPI_163 => idx 1 bit [3] + */ + .pin_bitmap = { + 0x00000000, 0x00000008, 0x00000000, 0x00000000, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/k3-j721e-evm-linux-demo.c b/configs/arm64/k3-j721e-evm-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..af6a5a2fbcec3956c16eaca9211e7954be183233 --- /dev/null +++ b/configs/arm64/k3-j721e-evm-linux-demo.c @@ -0,0 +1,266 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate on J721E based platforms + * 1 CPUs, 512MB RAM, 1 serial port + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0000000 +#endif + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[22]; + struct jailhouse_irqchip irqchips[4]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "k3-j721e-evm-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .cpu_reset_address = 0x0, + .vpci_irq_base = 195 - 32, + .console = { + .address = 0x2810000, + .divider = 0x1b, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE , + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | + JAILHOUSE_MEM_WRITE , + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x89fe40000, 1), + /* ctrl mmr */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Main.uart1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sdhci0 */ { + .phys_start = 0x4f80000, + .virt_start = 0x4f80000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* sdhci0 */ { + .phys_start = 0x4f88000, + .virt_start = 0x4f88000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* usbss1 */ { + .phys_start = 0x04114000, + .virt_start = 0x04114000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usbss1 */ { + .phys_start = 0x06400000, + .virt_start = 0x06400000, + .size = 0x00030000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main_gpio2 */ { + .phys_start = 0x00610000, + .virt_start = 0x00610000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main_gpio3 */ { + .phys_start = 0x00611000, + .virt_start = 0x00611000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy target_data host_id=A72_3 */ { + .phys_start = 0x3240f000, + .virt_start = 0x3240f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy rt host_id=A72_3 */ { + .phys_start = 0x3280f000, + .virt_start = 0x3280f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* main sproxy scfg host_id=A72_3 */ { + .phys_start = 0x32c0f000, + .virt_start = 0x32c0f000, + .size = 0x05000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* linux-loader space */ { + .phys_start = 0x89ff40000, + .virt_start = 0x0, + .size = 0x10000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM. */ { + .phys_start = 0x8a0000000, + .virt_start = 0x8a0000000, + .size = 0x60000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* + * offset = (SPI_NR + 32 - base) / 32 + * bit = (SPI_NR + 32 - base) % 32 + */ + { + .address = 0x01800000, + .pin_base = 32, + /* + * sdhci0 SPI_3 => idx 0 bit 3 + * sproxy_rx_016 SPI_71 => idx 1 bit 7 + * usb1.host SPI_104 => idx 3 bit 8 + * usb1.peripheral SPI_110 => idx 3 bit 14 + * usb1.otg SPI_121 => idx 3 bit 25 + */ + .pin_bitmap = { + 0x00000008, 0x00000080, 0x00000000, 0x02004100, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + /* + * virtual PCI SPI_163 to 166 => idx 1 bit [6:3] + * main_uart1 SPI_193 to 166 => idx 2 bit 1 + */ + .pin_bitmap = { + 0x00000000, 0x00000078, 0x00000002, 0x00000000, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + /* + * main_gpio_intr SPI_392 to 416 => idx 0 bit [31:8] + * ^^^^THIS^^^^ should match with SYSFW rm-cfg.c + */ + /* GPIO INTR */ + .pin_bitmap = { + 0xffffff00, 0x00000000, 0x00000000, 0x00000000, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + /* Non PCIe peripherals */ + {0x0003}, {0xf003}, + }, +}; diff --git a/configs/arm64/k3-j721e-evm.c b/configs/arm64/k3-j721e-evm.c new file mode 100644 index 0000000000000000000000000000000000000000..19f9d9679fba4a2f82f883518789168fd8c5c223 --- /dev/null +++ b/configs/arm64/k3-j721e-evm.c @@ -0,0 +1,416 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Configuration for K3 based J721E-EVM + * + * Authors: + * Nikhil Devshatwar + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[40]; + struct jailhouse_irqchip irqchips[6]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[30]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x89fa00000, + .size = 0x400000, + }, + .debug_console = { + .address = 0x02800000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_MDR_QUIRK | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x76000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 4, + .iommu_units= { + { + .type = JAILHOUSE_IOMMU_SMMUV3, + .base = 0x36600000, + .size = 0x100000, + }, + { + .type = JAILHOUSE_IOMMU_PVU, + .base = 0x30f80000, + .size = 0x1000, + .tipvu.tlb_base = 0x36000000, + .tipvu.tlb_size = 0x40000, + }, + { + .type = JAILHOUSE_IOMMU_PVU, + .base = 0x30f81000, + .size = 0x1000, + .tipvu.tlb_base = 0x36040000, + .tipvu.tlb_size = 0x40000, + }, + { + .type = JAILHOUSE_IOMMU_PVU, + .base = 0x30f83000, + .size = 0x1000, + .tipvu.tlb_base = 0x360c0000, + .tipvu.tlb_size = 0x40000, + }, + }, + .arm = { + .gic_version = 3, + .gicd_base = 0x01800000, + .gicr_base = 0x01900000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "k3-j721e-evm", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + .vpci_irq_base = 191 - 32, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x89fe00000, + .virt_start = 0x89fe00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x89fe10000, + .virt_start = 0x89fe10000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe20000, + .virt_start = 0x89fe20000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x89fe30000, + .virt_start = 0x89fe30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x89fe40000, 0), + /* ctrl mmr */ { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio */ { + .phys_start = 0x00600000, + .virt_start = 0x00600000, + .size = 0x00032000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serdes */ { + .phys_start = 0x00900000, + .virt_start = 0x00900000, + .size = 0x00012000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* timesync router */ { + .phys_start = 0x00A40000, + .virt_start = 0x00A40000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Most peripherals */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x0af03000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MAIN NAVSS */ { + .phys_start = 0x30800000, + .virt_start = 0x30800000, + .size = 0x0bc00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCIe Core */ { + .phys_start = 0x0d000000, + .virt_start = 0x0d000000, + .size = 0x01000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCIe DAT */ { + .phys_start = 0x10000000, + .virt_start = 0x10000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* C71 */ { + .phys_start = 0x64800000, + .virt_start = 0x64800000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* C66_0 */ { + .phys_start = 0x4D80800000, + .virt_start = 0x4D80800000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* C66_1 */ { + .phys_start = 0x4D81800000, + .virt_start = 0x4D81800000, + .size = 0x00800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPU */ { + .phys_start = 0x4E20000000, + .virt_start = 0x4E20000000, + .size = 0x00080000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + + /* MCU NAVSS */ { + .phys_start = 0x28380000, + .virt_start = 0x28380000, + .size = 0x03880000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU First peripheral window */ { + .phys_start = 0x40200000, + .virt_start = 0x40200000, + .size = 0x00999000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU CTRL_MMR0 */ { + .phys_start = 0x40f00000, + .virt_start = 0x40f00000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU R5F Core0 */ { + .phys_start = 0x41000000, + .virt_start = 0x41000000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU R5F Core1 */ { + .phys_start = 0x41400000, + .virt_start = 0x41400000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU SRAM */ { + .phys_start = 0x41c00000, + .virt_start = 0x41c00000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* MCU WKUP peripheral window */ { + .phys_start = 0x42040000, + .virt_start = 0x42040000, + .size = 0x030c0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU MMRs, remaining NAVSS */ { + .phys_start = 0x45100000, + .virt_start = 0x45100000, + .size = 0x00c24000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU CPSW */ { + .phys_start = 0x46000000, + .virt_start = 0x46000000, + .size = 0x00200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU OSPI register space */ { + .phys_start = 0x47000000, + .virt_start = 0x47000000, + .size = 0x00069000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MCU FSS OSPI0/1 data region 0 */ { + .phys_start = 0x50000000, + .virt_start = 0x50000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* MCU FSS OSPI0 data region 3 */ { + .phys_start = 0x500000000, + .virt_start = 0x500000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + /* MCU FSS OSPI1 data region 3 */ { + .phys_start = 0x700000000, + .virt_start = 0x700000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_DMA, + }, + + /* RAM - first bank*/ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - second bank */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x1fa00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - reserved for baremetal apps */ { + .phys_start = 0x89ff40000, + .virt_start = 0x89ff40000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM - reserved for inmate */ { + .phys_start = 0x8a0000000, + .virt_start = 0x8a0000000, + .size = 0x60000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + }, + .irqchips = { + { + .address = 0x01800000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 288, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 416, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 544, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + { + .address = 0x01800000, + .pin_base = 800, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 00:00.0 (demo) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 4, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + /* Non PCIe peripherals */ + {0x0002}, {0xf002}, + /* PCI1 */ + {0x0100}, {0x0101}, {0x0102}, {0x0103}, + {0x0104}, {0x0105}, {0x0106}, {0x0107}, + {0x0108}, {0x0109}, {0x010a}, {0x010b}, + {0x010c}, {0x010d}, {0x010e}, {0x010f}, + /* PCI2 */ + {0x4100}, {0x4101}, {0x4102}, {0x4103}, {0x4104}, {0x4105}, + /* PCI3 */ + {0x8100}, {0x8101}, {0x8102}, {0x8103}, {0x8104}, {0x8105}, + }, +}; diff --git a/configs/arm64/ls1028a-rdb-inmate-demo.c b/configs/arm64/ls1028a-rdb-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..8b45a9ed1092b0be7272982310b928fc628e5ee0 --- /dev/null +++ b/configs/arm64/ls1028a-rdb-inmate-demo.c @@ -0,0 +1,122 @@ +/* + * Configuration for LS1028ARDB board - inmate demo + * + * Copyright NXP 2021 + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 40 - 32, + + .console = { + .address = 0x21c0600, + .divider = 0x6d, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 1 << (40 - 32), + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/ls1028a-rdb-linux-demo.c b/configs/arm64/ls1028a-rdb-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..e2cb01af9a99894c3e7295dffec3a268b9e57c69 --- /dev/null +++ b/configs/arm64/ls1028a-rdb-linux-demo.c @@ -0,0 +1,142 @@ +/* + * Configuration for LS1028ARDB board - linux demo + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 40 - 32, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xbf900000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 1 << (40 - 32) | 1 << (41 - 32) | + 1 << (42 - 32) | 1 << (43 - 32), + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1028a-rdb.c b/configs/arm64/ls1028a-rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..6027772b6c172c9883d8313493d1a27e32a05817 --- /dev/null +++ b/configs/arm64/ls1028a-rdb.c @@ -0,0 +1,609 @@ +/* + * Configuration for LS1028ARDB board + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[76]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfba00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x21c0500, + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + .platform_info = { + .pci_mmconfig_base = 0xfb500000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 3, + .gicd_base = 0x6000000, + .gicr_base = 0x6040000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ls1028a", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 50 - 32, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 0), + /* RAM - 1GB - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DRAM2 2GB */ { + .phys_start = 0x2080000000, + .virt_start = 0x2080000000, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM - ~1GB - inmate */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DDR memory controller */ { + .phys_start = 0x01080000, + .virt_start = 0x01080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01e00000, + .virt_start = 0x01e00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rst */ { + .phys_start = 0x01e60000, + .virt_start = 0x01e60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* scfg */ { + .phys_start = 0x01fc0000, + .virt_start = 0x01fc0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02000000, + .virt_start = 0x02000000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02010000, + .virt_start = 0x02010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x02020000, + .virt_start = 0x02020000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x02030000, + .virt_start = 0x02030000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c4 */ { + .phys_start = 0x02040000, + .virt_start = 0x02040000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c5 */ { + .phys_start = 0x02050000, + .virt_start = 0x02050000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c6 */ { + .phys_start = 0x02060000, + .virt_start = 0x02060000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c7 */ { + .phys_start = 0x02070000, + .virt_start = 0x02070000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* fspi */ { + .phys_start = 0x020c0000, + .virt_start = 0x020c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi0 */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi1 */ { + .phys_start = 0x02110000, + .virt_start = 0x02110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi2 */ { + .phys_start = 0x02120000, + .virt_start = 0x02120000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc */ { + .phys_start = 0x02140000, + .virt_start = 0x02140000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc1 */ { + .phys_start = 0x02150000, + .virt_start = 0x02150000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* can0 */ { + .phys_start = 0x02180000, + .virt_start = 0x02180000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* can1 */ { + .phys_start = 0x02190000, + .virt_start = 0x02190000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart0 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart0 */ { + .phys_start = 0x02260000, + .virt_start = 0x02260000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart1 */ { + .phys_start = 0x02270000, + .virt_start = 0x02270000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart2 */ { + .phys_start = 0x02280000, + .virt_start = 0x02280000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart3 */ { + .phys_start = 0x02290000, + .virt_start = 0x02290000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart4 */ { + .phys_start = 0x022a0000, + .virt_start = 0x022a0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart5 */ { + .phys_start = 0x022b0000, + .virt_start = 0x022b0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* edma0 */ { + .phys_start = 0x022c0000, + .virt_start = 0x022c0000, + .size = 0x30000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03110000, + .virt_start = 0x03110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 pf0 */ { + .phys_start = 0x035c0000, + .virt_start = 0x035c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 host bridge */ { + .phys_start = 0x8000000000, + .virt_start = 0x8000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 host bridge */ { + .phys_start = 0x8800000000, + .virt_start = 0x8800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gic its */ { + .phys_start = 0x06020000, + .virt_start = 0x06020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x08000000, + .virt_start = 0x08000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x0c000000, + .virt_start = 0x0c000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog1 */ { + .phys_start = 0x0c010000, + .virt_start = 0x0c010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpu */ { + .phys_start = 0x0f0c0000, + .virt_start = 0x0f0c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai1 */ { + .phys_start = 0x0f100000, + .virt_start = 0x0f100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai2 */ { + .phys_start = 0x0f110000, + .virt_start = 0x0f110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai3 */ { + .phys_start = 0x0f120000, + .virt_start = 0x0f120000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai4 */ { + .phys_start = 0x0f130000, + .virt_start = 0x0f130000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai5 */ { + .phys_start = 0x0f140000, + .virt_start = 0x0f140000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sai6 */ { + .phys_start = 0x0f150000, + .virt_start = 0x0f150000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f80000, + .virt_start = 0x01f80000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie */ { + .phys_start = 0x1f0000000, + .virt_start = 0x1f0000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm0 */ { + .phys_start = 0x02800000, + .virt_start = 0x02800000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm1 */ { + .phys_start = 0x02810000, + .virt_start = 0x02810000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm2 */ { + .phys_start = 0x02820000, + .virt_start = 0x02820000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm3 */ { + .phys_start = 0x02830000, + .virt_start = 0x02830000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm4 */ { + .phys_start = 0x02840000, + .virt_start = 0x02840000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm5 */ { + .phys_start = 0x02850000, + .virt_start = 0x02850000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm6 */ { + .phys_start = 0x02860000, + .virt_start = 0x02860000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pwm7 */ { + .phys_start = 0x02870000, + .virt_start = 0x02870000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01e30000, + .virt_start = 0x01e30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dpclk */ { + .phys_start = 0x0f1f0000, + .virt_start = 0x0f1f0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* malidp */ { + .phys_start = 0x0f080000, + .virt_start = 0x0f080000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* hdptx0 */ { + .phys_start = 0x0f200000, + .virt_start = 0x0f200000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x6000000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1043a-rdb-dpaa-linux-demo.c b/configs/arm64/ls1043a-rdb-dpaa-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..89552b1667866c8d7f9fd31848629dfe855f9c4d --- /dev/null +++ b/configs/arm64/ls1043a-rdb-dpaa-linux-demo.c @@ -0,0 +1,212 @@ +/* + * ls1043a RDB target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Hongbo Wang + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[23]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 60 - 32, /* vPCI INTx: 60,61,62,63 */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xc0500000, + .virt_start = 0xc0500000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc0501000, + .virt_start = 0xc0501000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050a000, + .virt_start = 0xc050a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050c000, + .virt_start = 0xc050c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050e000, + .virt_start = 0xc050e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xc0600000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* qman */ { + .phys_start = 0x01880000, + .virt_start = 0x01880000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bman */ { + .phys_start = 0x01890000, + .virt_start = 0x01890000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* fman */ { + .phys_start = 0x01a00000, + .virt_start = 0x01a00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qportals CE */ { + .phys_start = 0x500000000, + .virt_start = 0x500000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* qportals CI */ { + .phys_start = 0x504000000, + .virt_start = 0x504000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bportals CE */ { + .phys_start = 0x508000000, + .virt_start = 0x508000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* bportals CI */ { + .phys_start = 0x50c000000, + .virt_start = 0x50c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xc0400000, + .virt_start = 0, + .size = 0x00010000, /* 64K */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM: Top at DRAM1 2GB Space */ { + .phys_start = 0xc0900000, + .virt_start = 0xc0900000, + .size = 0x33700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 1 << (60 - 32) | 1 << (61 - 32) | + 1 << (62 - 32) | 1 << (63 -32), /* vPCI */ + 1 << (44 + 32 - 64) | 1 << (45 + 32 - 64), + 0, + 0, + }, + }, + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 1 << (132 + 32 - 160), /* 10G PHY */ + 0xfffff000, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1043a-rdb-inmate-demo.c b/configs/arm64/ls1043a-rdb-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..256457451e9e8a644e8a47c64aba5f81ef3cbd7e --- /dev/null +++ b/configs/arm64/ls1043a-rdb-inmate-demo.c @@ -0,0 +1,138 @@ +/* + * ls1043a RDB - inmate demo + * + * Copyright NXP 2020 + * + * Authors: + * Hongbo Wang + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 60 - 32, /* vPCI INTx */ + + .console = { + .address = 0x21c0600, /* Uart1 in DUART1 */ + .divider = 0xd9, /* baudrate: 115200 */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xc0500000, + .virt_start = 0xc0500000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc0501000, + .virt_start = 0xc0501000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050a000, + .virt_start = 0xc050a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050c000, + .virt_start = 0xc050c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050e000, + .virt_start = 0xc050e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: Top at 2GB DRAM1 Space */ { + .phys_start = 0xc0900000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 1 << (60 - 32), /* vPCI */ + 0, + 0, + 0, + }, + }, + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0, + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/ls1043a-rdb-linux-demo.c b/configs/arm64/ls1043a-rdb-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..afc10edea06950ebc02827a18c20b6ca5bb4805c --- /dev/null +++ b/configs/arm64/ls1043a-rdb-linux-demo.c @@ -0,0 +1,165 @@ +/* + * ls1043a RDB target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Hongbo Wang + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 60 - 32, /* vPCI INTx: 60,61,62,63 */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xc0500000, + .virt_start = 0xc0500000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc0501000, + .virt_start = 0xc0501000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050a000, + .virt_start = 0xc050a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050c000, + .virt_start = 0xc050c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xc050e000, + .virt_start = 0xc050e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xc0600000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xc0400000, + .virt_start = 0, + .size = 0x00010000, /* 64K */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM: Top at DRAM1 2GB Space */ { + .phys_start = 0xc0900000, + .virt_start = 0xc0900000, + .size = 0x33700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 1 << (60 -32) | 1 << (61 - 32) | + 1 << (62 - 32) | 1 << (63 -32), /* vPCI */ + 0, + 0, + 0, + }, + }, + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0, + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1043a-rdb.c b/configs/arm64/ls1043a-rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..892dc444e7f42783b98096cecdff5a3b9924fb50 --- /dev/null +++ b/configs/arm64/ls1043a-rdb.c @@ -0,0 +1,496 @@ +/* + * ls1043a RDB target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Hongbo Wang + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[61]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xc0000000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x21c0500, /* Uart0 in DUART1 */ + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + .platform_info = { + .pci_mmconfig_base = 0xc0700000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 2, + .gicd_base = 0x1410000, + .gicc_base = 0x142f000, + .gich_base = 0x1440000, + .gicv_base = 0x146f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ls1043a", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 67 - 32, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xc0500000, + .virt_start = 0xc0500000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xc0501000, + .virt_start = 0xc0501000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xc050a000, + .virt_start = 0xc050a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xc050c000, + .virt_start = 0xc050c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xc050e000, + .virt_start = 0xc050e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xc0600000, 0), + /* RAM - 1GB at DRAM1 region - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DRAM2 6GB */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x180000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: Inmate */ { + .phys_start = 0xc0900000, + .virt_start = 0xc0900000, + .size = 0x33700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: loader */ { + .phys_start = 0xc0400000, + .virt_start = 0xc0400000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DDR memory controller */ { + .phys_start = 0x01080000, + .virt_start = 0x01080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IFC */ { + .phys_start = 0x01530000, + .virt_start = 0x01530000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* QSPI */ { + .phys_start = 0x01550000, + .virt_start = 0x01550000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc */ { + .phys_start = 0x01560000, + .virt_start = 0x01560000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* scfg */ { + .phys_start = 0x01570000, + .virt_start = 0x01570000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x01700000, + .virt_start = 0x01700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qman */ { + .phys_start = 0x01880000, + .virt_start = 0x01880000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bman */ { + .phys_start = 0x01890000, + .virt_start = 0x01890000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* fman */ { + .phys_start = 0x01a00000, + .virt_start = 0x01a00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qportals CE */ { + .phys_start = 0x500000000, + .virt_start = 0x500000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* qportals CI */ { + .phys_start = 0x504000000, + .virt_start = 0x504000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bportals CE */ { + .phys_start = 0x508000000, + .virt_start = 0x508000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* bportals CI */ { + .phys_start = 0x50c000000, + .virt_start = 0x50c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01ee2000, + .virt_start = 0x01ee2000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f00000, + .virt_start = 0x01f00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02180000, + .virt_start = 0x02180000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02190000, + .virt_start = 0x02190000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x021a0000, + .virt_start = 0x021a0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x021b0000, + .virt_start = 0x021b0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart1 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart2 */ { + .phys_start = 0x021d0000, + .virt_start = 0x021d0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio0 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02330000, + .virt_start = 0x02330000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart0 */ { + .phys_start = 0x02950000, + .virt_start = 0x02950000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart1 */ { + .phys_start = 0x02960000, + .virt_start = 0x02960000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart2 */ { + .phys_start = 0x02970000, + .virt_start = 0x02970000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart3 */ { + .phys_start = 0x02980000, + .virt_start = 0x02980000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart4 */ { + .phys_start = 0x02990000, + .virt_start = 0x02990000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart5 */ { + .phys_start = 0x029a0000, + .virt_start = 0x029a0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x02ad0000, + .virt_start = 0x02ad0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* edma0 */ { + .phys_start = 0x02c00000, + .virt_start = 0x02c00000, + .size = 0x30000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x02f00000, + .virt_start = 0x02f00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03000000, + .virt_start = 0x03000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb2 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie0 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03600000, + .virt_start = 0x03600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 pf0 */ { + .phys_start = 0x036c0000, + .virt_start = 0x036c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 0 */ { + .phys_start = 0x4000000000, + .virt_start = 0x4000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 1 */ { + .phys_start = 0x4800000000, + .virt_start = 0x4800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 2 */ { + .phys_start = 0x5000000000, + .virt_start = 0x5000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1046a-rdb-inmate-demo.c b/configs/arm64/ls1046a-rdb-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6c992caa1537c3edfef6918f8574e7aa8d34056c --- /dev/null +++ b/configs/arm64/ls1046a-rdb-inmate-demo.c @@ -0,0 +1,139 @@ +/* + * ls1046a RDB - inmate demo + * + * Copyright NXP 2020 + * + * Authors: + * Jiafei Pan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 60 - 32, /* vPCI INTx */ + + .console = { + .address = 0x21c0600, /* Uart1 in DUART1 */ + .divider = 0xbd, /* baudrate: 115200 */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM: Top at 2GB DRAM1 Space */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 1 << (60 - 32), /* vPCI */ + 0, + 0, + 0, + }, + }, + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0, + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, + +}; diff --git a/configs/arm64/ls1046a-rdb-linux-demo.c b/configs/arm64/ls1046a-rdb-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6bba61fb5055c83e746ae5796753c997b158f68c --- /dev/null +++ b/configs/arm64/ls1046a-rdb-linux-demo.c @@ -0,0 +1,165 @@ +/* + * ls1046a RDB target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Jiafei Pan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[16]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 60 - 32, /* vPCI INTx: 60,61,62,63 */ + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0xbf900000, + .virt_start = 0, + .size = 0x00010000, /* 64K */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM: Top at DRAM1 2GB Space */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 1 << (60 -32) | 1 << (61 - 32) | + 1 << (62 - 32) | 1 << (63 -32), /* vPCI */ + 0, + 0, + 0, + }, + }, + /* GIC-400 */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0, + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1046a-rdb.c b/configs/arm64/ls1046a-rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..d05c16289c1b9b4265ee63cb83cd29f68b625452 --- /dev/null +++ b/configs/arm64/ls1046a-rdb.c @@ -0,0 +1,517 @@ +/* + * ls1046a RDB target - linux-demo + * + * Copyright 2020 NXP + * + * Authors: + * Jiafei Pan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[64]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfba00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x21c0500, /* Uart0 in DUART1 */ + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + .platform_info = { + .pci_mmconfig_base = 0xfb500000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 2, + .gicd_base = 0x1410000, + .gicc_base = 0x142f000, + .gich_base = 0x1440000, + .gicv_base = 0x146f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ls1046a", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 67 - 32, /* Not include 32 base */ + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 0), + /* RAM - 1GB at DRAM1 region - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DRAM2 6GB */ { + .phys_start = 0x880000000, + .virt_start = 0x880000000, + .size = 0x180000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: Inmate */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: loader */ { + .phys_start = 0xbf900000, + .virt_start = 0xbf900000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DDR memory controller */ { + .phys_start = 0x01080000, + .virt_start = 0x01080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IFC */ { + .phys_start = 0x01530000, + .virt_start = 0x01530000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* QSPI */ { + .phys_start = 0x01550000, + .virt_start = 0x01550000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc */ { + .phys_start = 0x01560000, + .virt_start = 0x01560000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* scfg */ { + .phys_start = 0x01570000, + .virt_start = 0x01570000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x01700000, + .virt_start = 0x01700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qman */ { + .phys_start = 0x01880000, + .virt_start = 0x01880000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bman */ { + .phys_start = 0x01890000, + .virt_start = 0x01890000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* fman */ { + .phys_start = 0x01a00000, + .virt_start = 0x01a00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qportals CE */ { + .phys_start = 0x500000000, + .virt_start = 0x500000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* qportals CI */ { + .phys_start = 0x504000000, + .virt_start = 0x504000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bportals CE */ { + .phys_start = 0x508000000, + .virt_start = 0x508000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* bportals CI */ { + .phys_start = 0x50c000000, + .virt_start = 0x50c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01ee2000, + .virt_start = 0x01ee2000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f00000, + .virt_start = 0x01f00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02180000, + .virt_start = 0x02180000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02190000, + .virt_start = 0x02190000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x021a0000, + .virt_start = 0x021a0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x021b0000, + .virt_start = 0x021b0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart1 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart2 */ { + .phys_start = 0x021d0000, + .virt_start = 0x021d0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio0 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02330000, + .virt_start = 0x02330000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart0 */ { + .phys_start = 0x02950000, + .virt_start = 0x02950000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart1 */ { + .phys_start = 0x02960000, + .virt_start = 0x02960000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart2 */ { + .phys_start = 0x02970000, + .virt_start = 0x02970000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart3 */ { + .phys_start = 0x02980000, + .virt_start = 0x02980000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart4 */ { + .phys_start = 0x02990000, + .virt_start = 0x02990000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart5 */ { + .phys_start = 0x029a0000, + .virt_start = 0x029a0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x02ad0000, + .virt_start = 0x02ad0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* edma0 */ { + .phys_start = 0x02c00000, + .virt_start = 0x02c00000, + .size = 0x30000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x02f00000, + .virt_start = 0x02f00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03000000, + .virt_start = 0x03000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb2 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi1 */ { + .phys_start = 0x01580000, + .virt_start = 0x01580000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi2 */ { + .phys_start = 0x01590000, + .virt_start = 0x01590000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi3 */ { + .phys_start = 0x015a0000, + .virt_start = 0x015a0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie0 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03600000, + .virt_start = 0x03600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 pf0 */ { + .phys_start = 0x036c0000, + .virt_start = 0x036c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 0 */ { + .phys_start = 0x4000000000, + .virt_start = 0x4000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 1 */ { + .phys_start = 0x4800000000, + .virt_start = 0x4800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 2 */ { + .phys_start = 0x5000000000, + .virt_start = 0x5000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1088a-rdb-inmate-demo.c b/configs/arm64/ls1088a-rdb-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..3caee05d50bea6de2b570aedb16f6bcd18543ea7 --- /dev/null +++ b/configs/arm64/ls1088a-rdb-inmate-demo.c @@ -0,0 +1,128 @@ +/* + * Configuration for LS1088ARDB board - inmate demo + * + * Copyright NXP 2021 + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 81 - 32, + + .console = { + .address = 0x21c0600, + .divider = 0xbd, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 1 << (81 - 64), + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/ls1088a-rdb-linux-demo.c b/configs/arm64/ls1088a-rdb-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..ee8b18e9abb74b0bbba5074b84f33232d77300cc --- /dev/null +++ b/configs/arm64/ls1088a-rdb-linux-demo.c @@ -0,0 +1,148 @@ +/* + * Configuration for LS1088ARDB - linux-demo + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[14]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 81 - 32, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xbf900000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 1 << (81 - 64) | 1 << (82 - 64) | + 1 << (83 - 64) | 1 << (88 - 64), + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls1088a-rdb.c b/configs/arm64/ls1088a-rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..cb93df1e330f4c78930138964bf3cdb98d405837 --- /dev/null +++ b/configs/arm64/ls1088a-rdb.c @@ -0,0 +1,513 @@ +/* + * Configuration for LS1088ARDB board + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[63]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfba00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x21c0500, + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + .platform_info = { + .pci_mmconfig_base = 0x13000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 3, + .gicd_base = 0x6000000, + .gicr_base = 0x6100000, + .gicc_base = 0xc0c0000, + .gich_base = 0xc0d0000, + .gicv_base = 0xc0e0000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ls1088a", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 114 - 32, + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb70e000, + .virt_start = 0xfb70e000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 0), + /* RAM - 1GB - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DRAM2 */ { + .phys_start = 0x8080000000, + .virt_start = 0x8080000000, + .size = 0x180000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: Inmate */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01e00000, + .virt_start = 0x01e00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01e30000, + .virt_start = 0x01e30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rst */ { + .phys_start = 0x01e60000, + .virt_start = 0x01e60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* isc */ { + .phys_start = 0x01f70000, + .virt_start = 0x01f70000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f80000, + .virt_start = 0x01f80000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi0 */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart0 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio0 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02330000, + .virt_start = 0x02330000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ifc */ { + .phys_start = 0x02240000, + .virt_start = 0x02240000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ftm0 */ { + .phys_start = 0x02800000, + .virt_start = 0x02800000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02000000, + .virt_start = 0x02000000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02010000, + .virt_start = 0x02010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x02020000, + .virt_start = 0x02020000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x02030000, + .virt_start = 0x02030000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qspi */ { + .phys_start = 0x020c0000, + .virt_start = 0x020c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc0 */ { + .phys_start = 0x02140000, + .virt_start = 0x02140000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03110000, + .virt_start = 0x03110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata0 */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* its */ { + .phys_start = 0x6020000, + .virt_start = 0x6020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x08000000, + .virt_start = 0x08000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 */ { + .phys_start = 0x03600000, + .virt_start = 0x03600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 pf0 */ { + .phys_start = 0x034c0000, + .virt_start = 0x034c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 pf0 */ { + .phys_start = 0x035c0000, + .virt_start = 0x035c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 pf0 */ { + .phys_start = 0x036c0000, + .virt_start = 0x036c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 host bridge */ { + .phys_start = 0x2000000000, + .virt_start = 0x2000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 host bridge */ { + .phys_start = 0x2800000000, + .virt_start = 0x2800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 host bridge */ { + .phys_start = 0x3000000000, + .virt_start = 0x3000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x0c000000, + .virt_start = 0x0c000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog1 */ { + .phys_start = 0x0c010000, + .virt_start = 0x0c010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog2 */ { + .phys_start = 0x0c020000, + .virt_start = 0x0c020000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog3 */ { + .phys_start = 0x0c030000, + .virt_start = 0x0c030000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog4 */ { + .phys_start = 0x0c100000, + .virt_start = 0x0c100000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog5 */ { + .phys_start = 0x0c110000, + .virt_start = 0x0c110000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog6 */ { + .phys_start = 0x0c120000, + .virt_start = 0x0c120000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog7 */ { + .phys_start = 0x0c130000, + .virt_start = 0x0c130000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* mc */ { + .phys_start = 0x08340000, + .virt_start = 0x08340000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop ni */ { + .phys_start = 0x08800000, + .virt_start = 0x08800000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop config space */ { + .phys_start = 0x08b80000, + .virt_start = 0x08b80000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop ports */ { + .phys_start = 0x08c00000, + .virt_start = 0x08c00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* mc portals */ { + .phys_start = 0x80c000000, + .virt_start = 0x80c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qbman portals */ { + .phys_start = 0x818000000, + .virt_start = 0x818000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop access window */ { + .phys_start = 0x4300000000, + .virt_start = 0x4300000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* peb */ { + .phys_start = 0x4c00000000, + .virt_start = 0x4c00000000, + .size = 0x400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x06000000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x06000000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls2088a-rdb-inmate-demo.c b/configs/arm64/ls2088a-rdb-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..bbc6812c36006075cfc484e37ee19e0a17590b6f --- /dev/null +++ b/configs/arm64/ls2088a-rdb-inmate-demo.c @@ -0,0 +1,122 @@ +/* + * Configuration for LS2088ARDB board - inmate demo + * + * Copyright NXP 2021 + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 85 - 32, + + .console = { + .address = 0x21c0500, + .divider = 0xbd, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 1 << (85 - 64), + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 1, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/ls2088a-rdb-linux-demo.c b/configs/arm64/ls2088a-rdb-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..b20e6f175506e8f7708cedfebabf78aa89f8fea7 --- /dev/null +++ b/configs/arm64/ls2088a-rdb-linux-demo.c @@ -0,0 +1,141 @@ +/* + * Configuration for LS2088ARDB - linux-demo + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .vpci_irq_base = 85 - 32, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 1), + /* DUART1 */ { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xbf900000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC-400 */ { + .address = 0x6000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 1 << (85 - 64) | 1 << (86 - 64) | + 1 << (87 - 64) | 1 << (88 - 64), + 0, + 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ls2088a-rdb.c b/configs/arm64/ls2088a-rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..421ac7dae3adba1e60342ab956e96129461b7c1d --- /dev/null +++ b/configs/arm64/ls2088a-rdb.c @@ -0,0 +1,556 @@ +/* + * Configuration for LS2088ARDB board + * + * Copyright 2021 NXP + * + * Authors: + * Anda-Alexandra Dorneanu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[70]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xfba00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x21c0600, + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + .platform_info = { + .pci_mmconfig_base = 0x13000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + + .arm = { + .gic_version = 3, + .gicd_base = 0x6000000, + .gicr_base = 0x6100000, + .gicc_base = 0xc0c0000, + .gich_base = 0xc0d0000, + .gicv_base = 0xc0e0000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ls2088a", + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 160 - 32, + }, + }, + + .cpus = { + 0xff, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:00.0 */ { + .phys_start = 0xfb700000, + .virt_start = 0xfb700000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0xfb701000, + .virt_start = 0xfb701000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70a000, + .virt_start = 0xfb70a000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0xfb70c000, + .virt_start = 0xfb70c000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xfb800000, 0), + /* RAM - 1GB - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DRAM2 */ { + .phys_start = 0x8080000000, + .virt_start = 0x8080000000, + .size = 0x380000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM: Inmate */ { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x3b500000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* DDR memory controller 1 */ { + .phys_start = 0x01080000, + .virt_start = 0x01080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DDR memory controller 2 */ { + .phys_start = 0x01090000, + .virt_start = 0x01090000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clockgen */ { + .phys_start = 0x01300000, + .virt_start = 0x01300000, + .size = 0xa0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01e00000, + .virt_start = 0x01e00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rst */ { + .phys_start = 0x01e60000, + .virt_start = 0x01e60000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01e30000, + .virt_start = 0x01e30000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* isc */ { + .phys_start = 0x01f70000, + .virt_start = 0x01f70000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f80000, + .virt_start = 0x01f80000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi0 */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serial0 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* serial1 */ { + .phys_start = 0x021d0000, + .virt_start = 0x021d0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio0 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02330000, + .virt_start = 0x02330000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ifc */ { + .phys_start = 0x02240000, + .virt_start = 0x02240000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* ftm0 */ { + .phys_start = 0x02800000, + .virt_start = 0x02800000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02000000, + .virt_start = 0x02000000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02010000, + .virt_start = 0x02010000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x02020000, + .virt_start = 0x02020000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x02030000, + .virt_start = 0x02030000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qspi */ { + .phys_start = 0x020c0000, + .virt_start = 0x020c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc0 */ { + .phys_start = 0x02140000, + .virt_start = 0x02140000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03110000, + .virt_start = 0x03110000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata0 */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata1 */ { + .phys_start = 0x03210000, + .virt_start = 0x03210000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* its */ { + .phys_start = 0x6020000, + .virt_start = 0x6020000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x08000000, + .virt_start = 0x08000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 */ { + .phys_start = 0x03600000, + .virt_start = 0x03600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie4 */ { + .phys_start = 0x03700000, + .virt_start = 0x03700000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 pf0 */ { + .phys_start = 0x034c0000, + .virt_start = 0x034c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 pf0 */ { + .phys_start = 0x035c0000, + .virt_start = 0x035c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 pf0 */ { + .phys_start = 0x036c0000, + .virt_start = 0x036c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie4 pf0 */ { + .phys_start = 0x037c0000, + .virt_start = 0x037c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 host bridge */ { + .phys_start = 0x2000000000, + .virt_start = 0x2000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 host bridge */ { + .phys_start = 0x2800000000, + .virt_start = 0x2800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie3 host bridge */ { + .phys_start = 0x3000000000, + .virt_start = 0x3000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie4 host bridge */ { + .phys_start = 0x3800000000, + .virt_start = 0x3800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x0c000000, + .virt_start = 0x0c000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog1 */ { + .phys_start = 0x0c010000, + .virt_start = 0x0c010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog2 */ { + .phys_start = 0x0c100000, + .virt_start = 0x0c100000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog3 */ { + .phys_start = 0x0c110000, + .virt_start = 0x0c110000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog4 */ { + .phys_start = 0x0c200000, + .virt_start = 0x0c200000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog5 */ { + .phys_start = 0x0c210000, + .virt_start = 0x0c210000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog6 */ { + .phys_start = 0x0c300000, + .virt_start = 0x0c300000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog7 */ { + .phys_start = 0x0c310000, + .virt_start = 0x0c310000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* mc */ { + .phys_start = 0x08340000, + .virt_start = 0x08340000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop ni */ { + .phys_start = 0x08800000, + .virt_start = 0x08800000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop config space */ { + .phys_start = 0x08b80000, + .virt_start = 0x08b80000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop ports */ { + .phys_start = 0x08c00000, + .virt_start = 0x08c00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* mc portals */ { + .phys_start = 0x80c000000, + .virt_start = 0x80c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qbman portals */ { + .phys_start = 0x818000000, + .virt_start = 0x818000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wriop access window */ { + .phys_start = 0x4300000000, + .virt_start = 0x4300000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* peb */ { + .phys_start = 0x4c00000000, + .virt_start = 0x4c00000000, + .size = 0x400000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x06000000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0x06000000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/macchiatobin-inmate-demo.c b/configs/arm64/macchiatobin-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..9c76f6067f7afa70b6f6a7c2f73b41c3e4a0f2a1 --- /dev/null +++ b/configs/arm64/macchiatobin-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Marvell MACCHIATObin board: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2017-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0xf0512000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0xf0512000, + .virt_start = 0xf0512000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x13faf0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/macchiatobin-linux-demo.c b/configs/arm64/macchiatobin-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..ad29bbd5d662f79c5fe71a7fa05887a94d7cf5f3 --- /dev/null +++ b/configs/arm64/macchiatobin-linux-demo.c @@ -0,0 +1,116 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on MACCHIATObin: + * 2 CPUs, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[9]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "MACCHIATObin-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 112-32, + + .console = { + .address = 0xf0512000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x13fb00000, 1), + /* UART */ { + .phys_start = 0xf0512000, + .virt_start = 0xf0512000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* syscon (read-only) */ { + .phys_start = 0xf06f4000, + .virt_start = 0xf06f4000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_IO | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x13fa00000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x137000000, + .virt_start = 0x137000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf0210000, + .pin_base = 32, + .pin_bitmap = { + (1 << (51 - 32)), + 0, + (1 << (113 - 96)), + 0 + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/macchiatobin.c b/configs/arm64/macchiatobin.c new file mode 100644 index 0000000000000000000000000000000000000000..db158824282f9d34f9292a1d9a718ff863c7a6e6 --- /dev/null +++ b/configs/arm64/macchiatobin.c @@ -0,0 +1,127 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Marvell MACCHIATObin board + * + * Copyright (c) Siemens AG, 2017-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: 0x800000000..0x83fffffff + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x13fc00000, + .size = 0x000400000, + }, + .debug_console = { + .address = 0xf0512000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xfc000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0xf0210000, + .gicc_base = 0xf022f000, + .gich_base = 0xf0240000, + .gicv_base = 0xf026f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "MACCHIATObin", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 108-32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x13fb00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0xf0300000, + .virt_start = 0xf0300000, + .size = 0x4300000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMIO (PCIe) */ { + .phys_start = 0xf6000000, + .virt_start = 0xf6000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0xc0000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM */ { + .phys_start = 0x100000000, + .virt_start = 0x100000000, + .size = 0x3fb00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf0210000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/miriac-sbc-ls1046a-inmate-demo.c b/configs/arm64/miriac-sbc-ls1046a-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..39e9788821fa550a01f8cc7f656ae847f6fb3bb6 --- /dev/null +++ b/configs/arm64/miriac-sbc-ls1046a-inmate-demo.c @@ -0,0 +1,71 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Demo inmate for Microsys miriac SBC-LS1046A board + * + * Copyright (c) Linutronix GmbH, 2019 + * + * Authors: + * Andreas Messerschmid + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0x21c0500, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* DUART1 */ + { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ + { + .phys_start = 0xc0400000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/miriac-sbc-ls1046a-linux-demo.c b/configs/arm64/miriac-sbc-ls1046a-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..841c21a4ac2af28fa622c01d5881fd7dfeead98e --- /dev/null +++ b/configs/arm64/miriac-sbc-ls1046a-linux-demo.c @@ -0,0 +1,127 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Microsys miriac SBC-LS1046A board + * 2 CPUs, ~1G RAM, serial console, intercell-comm + * + * Copyright (c) Linutronix GmbH, 2019 + * + * Authors: + * Andreas Messerschmid + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 106-32, + + .console = { + .address = 0x21c0500, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0xc0400000, 1), + /* DUART1 */ + { + .phys_start = 0x21c0000, + .virt_start = 0x21c0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ + { + .phys_start = 0xc0500000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ + { + .phys_start = 0xc0510000, + .virt_start = 0xc0510000, + .size = 0x3faf0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ + { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + (1 << (54 - 32)), + (1 << (86 - 64)), + (1 << (106 - 96)) | (1 << (107 - 96)) | + (1 << (108 - 96)) | (1 << (109 - 96)), + 0, + }, + }, + /* GIC */ + { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0, + 0, + 0, + 0, + }, + }, + }, + + .pci_devices = + { + /* 00:00.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/miriac-sbc-ls1046a.c b/configs/arm64/miriac-sbc-ls1046a.c new file mode 100644 index 0000000000000000000000000000000000000000..96a7139eb17f7efa4e031f109c807dbbe7215207 --- /dev/null +++ b/configs/arm64/miriac-sbc-ls1046a.c @@ -0,0 +1,463 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Microsys miriac SBC-LS1046A board + * + * Copyright (c) Linutronix GmbH, 2019 + * + * Authors: + * Andreas Messerschmid + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: 0xc0000000..0xffffffff + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[55]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xc0000000, + .size = 0x000400000, + }, + + .debug_console = { + .address = 0x021c0500, + .size = 0x100, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_1, + }, + + .platform_info = { + .pci_mmconfig_base = 0x13000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + .arm = { + .gic_version = 2, + .gicd_base = 0x1410000, + .gicc_base = 0x142f000, + .gich_base = 0x1440000, + .gicv_base = 0x146f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "miriac SBC-LS1046A", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 102-32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0xc0400000, 0), + /* DDR memory controller */ { + .phys_start = 0x01080000, + .virt_start = 0x01080000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* IFC */ { + .phys_start = 0x01530000, + .virt_start = 0x01530000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* QSPI */ { + .phys_start = 0x01550000, + .virt_start = 0x01550000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* esdhc */ { + .phys_start = 0x01560000, + .virt_start = 0x01560000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* scfg */ { + .phys_start = 0x01570000, + .virt_start = 0x01570000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* crypto */ { + .phys_start = 0x01700000, + .virt_start = 0x01700000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qman */ { + .phys_start = 0x01880000, + .virt_start = 0x01880000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bman */ { + .phys_start = 0x01890000, + .virt_start = 0x01890000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* fman */ { + .phys_start = 0x01a00000, + .virt_start = 0x01a00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* qportals CE */ { + .phys_start = 0x500000000, + .virt_start = 0x500000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* qportals CI */ { + .phys_start = 0x504000000, + .virt_start = 0x504000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* bportals CE */ { + .phys_start = 0x508000000, + .virt_start = 0x508000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* bportals CI */ { + .phys_start = 0x50c000000, + .virt_start = 0x50c000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dcfg */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* clockgen */ { + .phys_start = 0x01ee1000, + .virt_start = 0x01ee1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* rcpm */ { + .phys_start = 0x01ee2000, + .virt_start = 0x01ee2000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* tmu */ { + .phys_start = 0x01f00000, + .virt_start = 0x01f00000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* dspi */ { + .phys_start = 0x02100000, + .virt_start = 0x02100000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c0 */ { + .phys_start = 0x02180000, + .virt_start = 0x02180000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c1 */ { + .phys_start = 0x02190000, + .virt_start = 0x02190000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c2 */ { + .phys_start = 0x021a0000, + .virt_start = 0x021a0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* i2c3 */ { + .phys_start = 0x021b0000, + .virt_start = 0x021b0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart1 */ { + .phys_start = 0x021c0000, + .virt_start = 0x021c0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* duart2 */ { + .phys_start = 0x021d0000, + .virt_start = 0x021d0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio0 */ { + .phys_start = 0x02300000, + .virt_start = 0x02300000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio1 */ { + .phys_start = 0x02310000, + .virt_start = 0x02310000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio2 */ { + .phys_start = 0x02320000, + .virt_start = 0x02320000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* gpio3 */ { + .phys_start = 0x02330000, + .virt_start = 0x02330000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart0 */ { + .phys_start = 0x02950000, + .virt_start = 0x02950000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart1 */ { + .phys_start = 0x02960000, + .virt_start = 0x02960000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart2 */ { + .phys_start = 0x02970000, + .virt_start = 0x02970000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart3 */ { + .phys_start = 0x02980000, + .virt_start = 0x02980000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart4 */ { + .phys_start = 0x02990000, + .virt_start = 0x02990000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* lpuart5 */ { + .phys_start = 0x029a0000, + .virt_start = 0x029a0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* wdog0 */ { + .phys_start = 0x02ad0000, + .virt_start = 0x02ad0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* edma0 */ { + .phys_start = 0x02c00000, + .virt_start = 0x02c00000, + .size = 0x30000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb0 */ { + .phys_start = 0x02f00000, + .virt_start = 0x02f00000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb1 */ { + .phys_start = 0x03000000, + .virt_start = 0x03000000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* usb2 */ { + .phys_start = 0x03100000, + .virt_start = 0x03100000, + .size = 0x100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* sata */ { + .phys_start = 0x03200000, + .virt_start = 0x03200000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi1 */ { + .phys_start = 0x01580000, + .virt_start = 0x01580000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi2 */ { + .phys_start = 0x01590000, + .virt_start = 0x01590000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* msi3 */ { + .phys_start = 0x015a0000, + .virt_start = 0x015a0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie0 */ { + .phys_start = 0x03400000, + .virt_start = 0x03400000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie1 */ { + .phys_start = 0x03500000, + .virt_start = 0x03500000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* pcie2 */ { + .phys_start = 0x03600000, + .virt_start = 0x03600000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM - 1GB - root cell */ { + .phys_start = 0x80000000, + .virt_start = 0x80000000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM - ~1GB - inmates */ { + .phys_start = 0xc0500000, + .virt_start = 0xc0500000, + .size = 0x3fb00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PCI host bridge 0 */ { + .phys_start = 0x4000000000, + .virt_start = 0x4000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 1 */ { + .phys_start = 0x4800000000, + .virt_start = 0x4800000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* PCI host bridge 2 */ { + .phys_start = 0x5000000000, + .virt_start = 0x5000000000, + .size = 0x800000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x1410000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + /* GIC */ { + .address = 0x1410000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/pine64-plus-inmate-demo.c b/configs/arm64/pine64-plus-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..73cde95c16843c295bbe44877ae122aa7fa2b4b3 --- /dev/null +++ b/configs/arm64/pine64-plus-inmate-demo.c @@ -0,0 +1,130 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for gic-demo inmate on Pine64+ board + * + * Copyright (c) Vijai Kumar K, 2019-2020 + * + * Authors: + * Vijai Kumar K + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .vpci_irq_base = 125, + + .console = { + .address = 0x1c28000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + /* State Table */ { + .phys_start = 0xbbef1000, + .virt_start = 0xbbef1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Read/Write Section */ { + .phys_start = 0xbbef2000, + .virt_start = 0xbbef2000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 0) */ { + .phys_start = 0xbbefb000, + .virt_start = 0xbbefb000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 1) */ { + .phys_start = 0xbbefd000, + .virt_start = 0xbbefd000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 2) */ { + .phys_start = 0xbbeff000, + .virt_start = 0xbbeff000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART */ { + .phys_start = 0x1c28000, + .virt_start = 0x1c28000, + .size = 0x400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32 | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xbbee1000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + (1 << (157 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/pine64-plus-linux-demo.c b/configs/arm64/pine64-plus-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..1d0999064565e5e3f9456f88d096a48d81504f34 --- /dev/null +++ b/configs/arm64/pine64-plus-linux-demo.c @@ -0,0 +1,148 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Pine64+ board: + * 2 CPU, 128M RAM, serial port 0 + * + * Copyright (c) Vijai Kumar K, 2019-2020 + * + * Authors: + * Vijai Kumar K + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "pine64-plus-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 123, + + .console = { + .address = 0x01c28000, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + /* State Table */ { + .phys_start = 0xbbef1000, + .virt_start = 0xbbef1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Read/Write Section */ { + .phys_start = 0xbbef2000, + .virt_start = 0xbbef2000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 0) */ { + .phys_start = 0xbbefb000, + .virt_start = 0xbbefb000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 1) */ { + .phys_start = 0xbbefd000, + .virt_start = 0xbbefd000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* Output (peer 2) */ { + .phys_start = 0xbbeff000, + .virt_start = 0xbbeff000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbf01000, 1), + /* UART 0-3 */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0xbb900000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0xb0000000, + .virt_start = 0xb0000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 1 << (32-32), 0, 0, (1 << (155-128)) | (1 << (156-128)), + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* IVSHMEM 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/pine64-plus.c b/configs/arm64/pine64-plus.c new file mode 100644 index 0000000000000000000000000000000000000000..c824ca78a9d3571ec4fadce83f51509129912cc6 --- /dev/null +++ b/configs/arm64/pine64-plus.c @@ -0,0 +1,375 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Pine64+ board, 2 GB + * + * Copyright (c) Vijai Kumar K, 2019-2020 + * + * Authors: + * Vijai Kumar K + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=1792M" to the kernel command line. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[43]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0xbc000000, + .size = 0x04000000, + }, + .debug_console = { + .address = 0x01c28000, + .size = 0x400, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x02000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0x01c81000, + .gicc_base = 0x01c82000, + .gich_base = 0x01c84000, + .gicv_base = 0x01c86000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Pine64-Plus", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_irqchips = ARRAY_SIZE(config.irqchips), + + .vpci_irq_base = 108, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + /* State Table */ { + .phys_start = 0xbbef1000, + .virt_start = 0xbbef1000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + /* Read/Write Section */ { + .phys_start = 0xbbef2000, + .virt_start = 0xbbef2000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Output (peer 0) */ { + .phys_start = 0xbbefb000, + .virt_start = 0xbbefb000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* Output (peer 1) */ { + .phys_start = 0xbbefd000, + .virt_start = 0xbbefd000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* Output (peer 2) */ { + .phys_start = 0xbbeff000, + .virt_start = 0xbbeff000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory region for 00:01.0 (networking)*/ + JAILHOUSE_SHMEM_NET_REGIONS(0xbbf01000, 0), + /* SRAM */ { + .phys_start = 0x00018000, + .virt_start = 0x00018000, + .size = 0x00028000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* Clock */ { + .phys_start = 0x01000000, + .virt_start = 0x01000000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* 1100000.mixer */ { + .phys_start = 0x01100000, + .virt_start = 0x01100000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* 1200000.mixer */ { + .phys_start = 0x01200000, + .virt_start = 0x01200000, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Syscon */ { + .phys_start = 0x01c00000, + .virt_start = 0x01c00000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* DMA */ { + .phys_start = 0x01c02000, + .virt_start = 0x01c02000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* LCD1 */ { + .phys_start = 0x01c0c000, + .virt_start = 0x01c0c000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* LCD2 */ { + .phys_start = 0x01c0d000, + .virt_start = 0x01c0d000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMC */ { + .phys_start = 0x01c0f000, + .virt_start = 0x01c0f000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* EEPROM */ { + .phys_start = 0x01c14000, + .virt_start = 0x01c14000, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c19000, + .virt_start = 0x01c19000, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c19400, + .virt_start = 0x01c19400, + .size = 0x00000014, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1a000, + .virt_start = 0x01c1a000, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1a400, + .virt_start = 0x01c1a400, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1a800, + .virt_start = 0x01c1a800, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1b000, + .virt_start = 0x01c1b000, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1b400, + .virt_start = 0x01c1b400, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* USB */ { + .phys_start = 0x01c1b800, + .virt_start = 0x01c1b800, + .size = 0x00000004, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Clock */ { + .phys_start = 0x01c20000, + .virt_start = 0x01c20000, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Pincontrol */ { + .phys_start = 0x01c20800, + .virt_start = 0x01c20800, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Watchdog */ { + .phys_start = 0x01c20ca0, + .virt_start = 0x01c20ca0, + .size = 0x00000020, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* UART */ { + .phys_start = 0x01c28000, + .virt_start = 0x01c28000, + .size = 0x00000020, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* I2C */ { + .phys_start = 0x01c2b000, + .virt_start = 0x01c2b000, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* Ethernet */ { + .phys_start = 0x01c30000, + .virt_start = 0x01c30000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* GPU */ { + .phys_start = 0x01c40000, + .virt_start = 0x01c40000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* SRAM */ { + .phys_start = 0x01d00000, + .virt_start = 0x01d00000, + .size = 0x00040000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* HDMI */ { + .phys_start = 0x01ee0000, + .virt_start = 0x01ee0000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* HDMI */ { + .phys_start = 0x01ef0000, + .virt_start = 0x01ef0000, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RTC */ { + .phys_start = 0x01f00000, + .virt_start = 0x01f00000, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Interrupt Controller */ { + .phys_start = 0x01f00c00, + .virt_start = 0x01f00c00, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Clock */ { + .phys_start = 0x01f01400, + .virt_start = 0x01f01400, + .size = 0x00000100, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* Pincontrol */ { + .phys_start = 0x01f02c00, + .virt_start = 0x01f02c00, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_32, + }, + /* RSB(Reduced Serial Bus) */ { + .phys_start = 0x01f03400, + .virt_start = 0x01f03400, + .size = 0x00000400, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* System RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x7bef1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x01c81000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + /* IVSHMEM 00:01.0 (networking) */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/qemu-arm64-inmate-demo.c b/configs/arm64/qemu-arm64-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6863ce245dbbc34ea36e8288a2347bc6c672f42c --- /dev/null +++ b/configs/arm64/qemu-arm64-inmate-demo.c @@ -0,0 +1,132 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on QEMU arm64 virtual target + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 144-32, + + .console = { + .address = 0x09000000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b0010, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7fa00000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + (1 << (144 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/qemu-arm64-linux-demo.c b/configs/arm64/qemu-arm64-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..d8096e8ed37949a317a5958aafe348ab3afe9ac3 --- /dev/null +++ b/configs/arm64/qemu-arm64-linux-demo.c @@ -0,0 +1,152 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on QEMU arm64: + * 2 CPUs, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "qemu-arm64-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + + .console = { + .address = 0x09000000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b1100, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 1), + /* UART */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7f900000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 1 << (33 - 32), + 0, + 0, + (1 << (140 - 128)) | (1 << (141 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/qemu-arm64-zephyr-demo.c b/configs/arm64/qemu-arm64-zephyr-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..e5e36237ccf0722f9556024447d26392ce8e4247 --- /dev/null +++ b/configs/arm64/qemu-arm64-zephyr-demo.c @@ -0,0 +1,155 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for zephyr-demo inmate on QEMU arm64: + * 2 CPUs, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2017 + * Copyright 2022 NXP + * + * Authors: + * Jan Kiszka + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "qemu-arm64-zephyr-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + .cpu_reset_address = 0x70000000, + + .console = { + .address = 0x09000000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 1), + /* UART */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7f900000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x70000000, + .virt_start = 0x70000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 1 << (33 - 32), + 0, + 0, + (1 << (140 - 128)) | (1 << (141 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/qemu-arm64.c b/configs/arm64/qemu-arm64.c new file mode 100644 index 0000000000000000000000000000000000000000..2e9fcde67ca6905392665eb53cc7f924123e4a92 --- /dev/null +++ b/configs/arm64/qemu-arm64.c @@ -0,0 +1,159 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for QEMU arm64 virtual target, 1G RAM, 16 cores + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * NOTE: Add "mem=768M" to the kernel command line. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[12]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7fc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0x09000000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0x08e00000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 3, + .gicd_base = 0x08000000, + .gicr_base = 0x080a0000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "qemu-arm64", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 128-32, + }, + }, + + .cpus = { + 0xffff, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0x09000000, + .virt_start = 0x09000000, + .size = 0x37000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x40000000, + .virt_start = 0x40000000, + .size = 0x3fa10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* "physical" PCI ECAM */ { + .phys_start = 0x4010000000, + .virt_start = 0x4010000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0x08000000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0001:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0001:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/rpi4-inmate-demo.c b/configs/arm64/rpi4-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..1bc244f5104a0a5f73478f4f66e250b347a9799d --- /dev/null +++ b/configs/arm64/rpi4-inmate-demo.c @@ -0,0 +1,133 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Raspberry Pi 4: + * 1 CPU, 64K RAM, serial port 0 + * + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 184-32, + + .console = { + .address = 0xfe215040, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b0010, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x1faf0000, + .virt_start = 0x1faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1faf1000, + .virt_start = 0x1faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafa000, + .virt_start = 0x1fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafc000, + .virt_start = 0x1fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafe000, + .virt_start = 0x1fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART */ { + .phys_start = 0xfe215040, + .virt_start = 0xfe215040, + .size = 0x40, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_8 | + JAILHOUSE_MEM_IO_32 | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x1fa00000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xff841000, + .pin_base = 160, + .pin_bitmap = { + 1 << (184 - 160), + 0, + 0, + 0 + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/rpi4-linux-demo.c b/configs/arm64/rpi4-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..f93c564a2351b2752037880cde45fb5c0f48dd26 --- /dev/null +++ b/configs/arm64/rpi4-linux-demo.c @@ -0,0 +1,163 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Raspberry Pi 4: + * 2 CPUs, 128M RAM, serial port + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "rpi4-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 185-32, + + .console = { + .address = 0xfe215040, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b1100, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x1faf0000, + .virt_start = 0x1faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1faf1000, + .virt_start = 0x1faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafa000, + .virt_start = 0x1fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafc000, + .virt_start = 0x1fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x1fafe000, + .virt_start = 0x1fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x1fb00000, 1), + /* UART */ { + .phys_start = 0xfe215040, + .virt_start = 0xfe215040, + .size = 0x40, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_8 | + JAILHOUSE_MEM_IO_32 | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x1f900000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x10000000, + .virt_start = 0x10000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xff841000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 1 << (125 - 96), + 0, + }, + }, + /* GIC */ { + .address = 0xff841000, + .pin_base = 160, + .pin_bitmap = { + (1 << (185 - 160)) | (1 << (186 - 160)), + 0, + 0, + 0 + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/rpi4.c b/configs/arm64/rpi4.c new file mode 100644 index 0000000000000000000000000000000000000000..68bb1a24f13213d4e41229599ab4295067568cc8 --- /dev/null +++ b/configs/arm64/rpi4.c @@ -0,0 +1,188 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for Raspberry Pi 4 (quad-core Cortex-A72, 1GB, 2GB, 4GB or 8GB RAM) + * + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: reg = <0x0 0x20000000 0x10000000>; + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[14]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x1fc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0xfe215040, + .size = 0x40, + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xff900000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = 1, + .arm = { + .gic_version = 2, + .gicd_base = 0xff841000, + .gicc_base = 0xff842000, + .gich_base = 0xff844000, + .gicv_base = 0xff846000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Raspberry-Pi4", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 182 - 32, + }, + }, + + .cpus = { + 0b1111, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x1faf0000, + .virt_start = 0x1faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x1faf1000, + .virt_start = 0x1faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x1fafa000, + .virt_start = 0x1fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x1fafc000, + .virt_start = 0x1fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x1fafe000, + .virt_start = 0x1fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions for 00:01.0 (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x1fb00000, 0), + /* MMIO 1 (permissive) */ { + .phys_start = 0xfd500000, + .virt_start = 0xfd500000, + .size = 0x1b00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* MMIO 2 (permissive) */ { + .phys_start = 0x600000000, + .virt_start = 0x600000000, + .size = 0x4000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM (0M-~506M) */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x1fa10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + + /* ~2M reserved for shared memory regions */ + + /* 4M reserved for the hypervisor */ + + /* RAM (512M-4032M) */ { + .phys_start = 0x20000000, + .virt_start = 0x20000000, + .size = 0xdc000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + + /* RAM (4096M-8192M) */ { + .phys_start = 0x100000000, + .virt_start = 0x100000000, + .size = 0x100000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xff841000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + /* GIC */ { + .address = 0xff841000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0001:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0001:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ultra96-inmate-demo.c b/configs/arm64/ultra96-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..c61130a186ba8e935476f4a2c860544c73b1673a --- /dev/null +++ b/configs/arm64/ultra96-inmate-demo.c @@ -0,0 +1,132 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Avnet Ultra96 board: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2016-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 144-32, + + .console = { + .address = 0xff010000, + .type = JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b0010, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* UART */ { + .phys_start = 0xff010000, + .virt_start = 0xff010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7bfe0000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + (1 << (144 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/arm64/ultra96-linux-demo.c b/configs/arm64/ultra96-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..f1f32fd2d1c720ba0b157ebd025b9daf32fc0b3e --- /dev/null +++ b/configs/arm64/ultra96-linux-demo.c @@ -0,0 +1,151 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on Avnet Ultra96 board: + * 2 CPUs, 128M RAM, serial port 2 + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[13]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "Ultra96-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + + .console = { + .address = 0xff010000, + .type= JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0b1100, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory region */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 1), + /* UART */ { + .phys_start = 0xff010000, + .virt_start = 0xff010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x7bef0000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x74000000, + .virt_start = 0x74000000, + .size = 0x7ef0000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 1 << (54 - 32), + 0, + 0, + (1 << (140 - 128)) | (1 << (141 - 128)) + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/ultra96.c b/configs/arm64/ultra96.c new file mode 100644 index 0000000000000000000000000000000000000000..93e2ee83594d312cb6e7abd544eccfd08056635c --- /dev/null +++ b/configs/arm64/ultra96.c @@ -0,0 +1,173 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Avnet Ultra96 board + * + * Copyright (c) Siemens AG, 2016-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[11]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[2]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x7fc00000, + .size = 0x00400000, + }, + .debug_console = { + .address = 0xff010000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xfc000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_ARM_MMU500, + .base = 0xfd800000, + .size = 0x20000, + }, + }, + + .arm = { + .gic_version = 2, + .gicd_base = 0xf9010000, + .gicc_base = 0xf902f000, + .gich_base = 0xf9040000, + .gicv_base = 0xf906f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "Ultra96", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + + .vpci_irq_base = 136-32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions for 00:00.0 (demo) */ + { + .phys_start = 0x7faf0000, + .virt_start = 0x7faf0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7faf1000, + .virt_start = 0x7faf1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafa000, + .virt_start = 0x7fafa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x7fafc000, + .virt_start = 0x7fafc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x7fafe000, + .virt_start = 0x7fafe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x7fb00000, 0), + /* MMIO (permissive) */ { + .phys_start = 0xfd000000, + .virt_start = 0xfd000000, + .size = 0x03000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x7fa10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0001:00:00.0 (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 0 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM 0001:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + { + .mmu500.id = 0x870, + .mmu500.mask_out = 0x0, + }, + { + .mmu500.id = 0x871, + .mmu500.mask_out = 0x0, + }, + }, +}; diff --git a/configs/arm64/zynqmp-zcu102-inmate-demo.c b/configs/arm64/zynqmp-zcu102-inmate-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..304b4cdab918e8edceee11765f37a413d5bb0a19 --- /dev/null +++ b/configs/arm64/zynqmp-zcu102-inmate-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for demo inmate on Xilinx ZynqMP ZCU102 eval board: + * 1 CPU, 64K RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "inmate-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pci_devices = 0, + + .console = { + .address = 0xff010000, + .type = JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* UART */ { + .phys_start = 0xff010000, + .virt_start = 0xff010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x800600000, + .virt_start = 0, + .size = 0x00010000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + } +}; diff --git a/configs/arm64/zynqmp-zcu102-linux-demo-2.c b/configs/arm64/zynqmp-zcu102-linux-demo-2.c new file mode 100644 index 0000000000000000000000000000000000000000..76ed806445f5ae25f1871d116388ee0d5eece21f --- /dev/null +++ b/configs/arm64/zynqmp-zcu102-linux-demo-2.c @@ -0,0 +1,113 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for 2nd linux-demo inmate on ZynqMP ZCU102: + * 1 CPU, 112M RAM + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[11]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "ZynqMP-linux-demo-2", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 144-32, + + .console = { + .address = 0xff010000, + .type = JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x2, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800500000, 1), + /* IVSHMEM shared memory region for 00:02.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800700000, 1), + /* RAM */ { + .phys_start = 0x800610000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x809000000, + .virt_start = 0x809000000, + .size = 0x7000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 0, + (1 << (146 - 128)) | (1 << (147 - 128)) + }, + }, + }, + + .pci_devices = { + /* 00:02.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 2 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + /* 00:03.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 3 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/zynqmp-zcu102-linux-demo.c b/configs/arm64/zynqmp-zcu102-linux-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..32e380895f6864e6e7ecfdd1a08d9ce0b71f2ca7 --- /dev/null +++ b/configs/arm64/zynqmp-zcu102-linux-demo.c @@ -0,0 +1,119 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for linux-demo inmate on ZynqMP ZCU102: + * 2 CPUs, 128M RAM, serial port 2 + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[12]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "ZynqMP-linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + + .vpci_irq_base = 140-32, + + .console = { + .address = 0xff010000, + .type= JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0xc, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800400000, 1), + /* IVSHMEM shared memory region for 00:03.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800700000, 0), + /* UART */ { + .phys_start = 0xff010000, + .virt_start = 0xff010000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x800600000, + .virt_start = 0, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* RAM */ { + .phys_start = 0x810000000, + .virt_start = 0x810000000, + .size = 0x8000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 1 << (54 - 32), + 0, + 0, + (1 << (141 - 128)) | (1 << (143 - 128)) + }, + }, + }, + + .pci_devices = { + /* 00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + /* 00:03.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .bdf = 3 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/configs/arm64/zynqmp-zcu102.c b/configs/arm64/zynqmp-zcu102.c new file mode 100644 index 0000000000000000000000000000000000000000..492dc566e5e7b0fb1d994fba7ae9834b2b9890b7 --- /dev/null +++ b/configs/arm64/zynqmp-zcu102.c @@ -0,0 +1,163 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Xilinx ZynqMP ZCU102 eval board + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Reservation via device tree: 0x800000000..0x83fffffff + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[12]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[2]; + union jailhouse_stream_id stream_ids[3]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x800000000, + .size = 0x000400000, + }, + .debug_console = { + .address = 0xff000000, + .size = 0x1000, + .type = JAILHOUSE_CON_TYPE_XUARTPS, + .flags = JAILHOUSE_CON_ACCESS_MMIO | + JAILHOUSE_CON_REGDIST_4, + }, + .platform_info = { + .pci_mmconfig_base = 0xfc000000, + .pci_mmconfig_end_bus = 0, + .pci_is_virtual = 1, + .pci_domain = -1, + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_ARM_MMU500, + .base = 0xfd800000, + .size = 0x20000, + }, + }, + .arm = { + .gic_version = 2, + .gicd_base = 0xf9010000, + .gicc_base = 0xf902f000, + .gich_base = 0xf9040000, + .gicv_base = 0xf906f000, + .maintenance_irq = 25, + }, + }, + .root_cell = { + .name = "ZynqMP-ZCU102", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_stream_ids = ARRAY_SIZE(config.stream_ids), + + .vpci_irq_base = 136-32, + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region for 0001:00:00.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800400000, 0), + /* IVSHMEM shared memory region for 0001:00:01.0 */ + JAILHOUSE_SHMEM_NET_REGIONS(0x800500000, 0), + /* MMIO (permissive) */ { + .phys_start = 0xfd000000, + .virt_start = 0xfd000000, + .size = 0x03000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + /* RAM */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x80000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* RAM */ { + .phys_start = 0x800600000, + .virt_start = 0x800600000, + .size = 0x7fa00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE, + }, + /* PCI host bridge */ { + .phys_start = 0x8000000000, + .virt_start = 0x8000000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO, + }, + }, + + .irqchips = { + /* GIC */ { + .address = 0xf9010000, + .pin_base = 32, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, + }, + + .pci_devices = { + /* 0001:00:01.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + /* 0001:00:02.0 */ { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 1, + .bdf = 2 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .stream_ids = { + { + .mmu500.id = 0x860, + .mmu500.mask_out = 0x0, + }, + { + .mmu500.id = 0x861, + .mmu500.mask_out = 0x0, + }, + { + .mmu500.id = 0x870, + .mmu500.mask_out = 0xf, + }, + }, +}; diff --git a/configs/x86/apic-demo.c b/configs/x86/apic-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..d014f267c93b548931487fcda62a25538d34a2a7 --- /dev/null +++ b/configs/x86/apic-demo.c @@ -0,0 +1,78 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for demo inmates, 1 CPU, 1 MB RAM, 1 serial port + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[2]; + struct jailhouse_cache cache_regions[1]; + struct jailhouse_pio pio_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "apic-demo", + .flags = JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_cache_regions = ARRAY_SIZE(config.cache_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = 0, + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0x8, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ef00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .cache_regions = { + { + .start = 0, + .size = 2, + .type = JAILHOUSE_CACHE_L3, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial */ + }, +}; diff --git a/configs/x86/e1000-demo.c b/configs/x86/e1000-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..8ae312205bb2cf3153a58f2f6b49e647d8d28967 --- /dev/null +++ b/configs/x86/e1000-demo.c @@ -0,0 +1,102 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for PCI demo inmate: + * 1 CPU, 1 MB RAM, 1 serial port, 1 Intel HDA PCI device + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; + struct jailhouse_pio pio_regions[4]; + struct jailhouse_pci_device pci_devices[1]; + struct jailhouse_pci_capability pci_caps[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "e1000-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + /* e1000 BAR0 */ { + .phys_start = 0xfebc0000, + .virt_start = 0xfebc0000, + .size = 0x00020000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xc000, 0x3f), /* e1000 */ + PIO_RANGE(0xe000, 8), /* OXPCIe952 serial 2 */ + }, + + .pci_devices = { + { /* Intel e1000 @00:19.0 */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00c8, + .caps_start = 0, + .num_caps = 1, + .num_msi_vectors = 1, + .msi_64bits = 1, + }, + }, + + .pci_caps = { + { /* Intel e1000 @00:19.0 */ + .id = PCI_CAP_ID_MSI, + .start = 0xd0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + }, +}; diff --git a/configs/x86/f2a88xm-hd3.c b/configs/x86/f2a88xm-hd3.c new file mode 100644 index 0000000000000000000000000000000000000000..b529e6a62f80a17f30395919ede7997148c6698b --- /dev/null +++ b/configs/x86/f2a88xm-hd3.c @@ -0,0 +1,890 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Gigabyte Technology Co., Ltd. GA-F2A88XM-HD3 Rev. 3.0 + * board with AMD A10-7800 APU and 1G RAM. + * + * Copyright (c) Siemens AG, 2014 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Created with 'jailhouse config create f2a88xm-hd3.c' and adjusted + * by Valentine Sinitsyn . + * + * NOTE: This config expects the following to be appended to your kernel cmdline + * "memmap=82M$0x3a000000" + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[35]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pio pio_regions[8]; + struct jailhouse_pci_device pci_devices[26]; + struct jailhouse_pci_capability pci_caps[24]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x3a000000, + .size = 0x600000, + }, + .debug_console = { + .address = 0x3f8, + /* .divider = 0x1, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + }, + .platform_info = { + .pci_mmconfig_base = 0xe0000000, + .pci_mmconfig_end_bus = 0xff, + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_AMD, + .base = 0xfeb80000, + .size = 0x80000, + .amd.bdf = 0x02, + .amd.base_cap = 0x40, + .amd.msi_cap = 0x54, + .amd.features = 0x80048824, + }, + }, + .x86 = { + .pm_timer_address = 0x808, + }, + }, + .root_cell = { + .name = "F2A88XM-HD3", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + }, + }, + + .cpus = { + 0x000000000000000f, + }, + + .mem_regions = { + /* MemRegion: 00000000-0009e7ff : System RAM */ + { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x9f000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 000a0000-000bffff : PCI Bus 0000:00 */ + { + .phys_start = 0xa0000, + .virt_start = 0xa0000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 000c0000-000cf5ff : Video ROM */ + { + .phys_start = 0xc0000, + .virt_start = 0xc0000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 000e0000-000fffff : System ROM */ + { + .phys_start = 0xe0000, + .virt_start = 0xe0000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: 00100000-00ffffff : System RAM */ + { + .phys_start = 0x100000, + .virt_start = 0x100000, + .size = 0xf00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 01000000-01ffffff : Kernel */ + { + .phys_start = 0x1000000, + .virt_start = 0x1000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 02000000-3affffff : System RAM */ + { + .phys_start = 0x2000000, + .virt_start = 0x2000000, + .size = 0x39000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 3f200000-6b8ecfff : System RAM */ + { + .phys_start = 0x3f200000, + .virt_start = 0x3f200000, + .size = 0x2c6ed000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 6b91d000-6bbdffff : System RAM */ + { + .phys_start = 0x6b91d000, + .virt_start = 0x6b91d000, + .size = 0x2c3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 6bbe0000-6bcadfff : ACPI Non-volatile Storage */ + { + .phys_start = 0x6bbe0000, + .virt_start = 0x6bbe0000, + .size = 0xce000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 6d1c9000-6d1c9fff : System RAM */ + { + .phys_start = 0x6d1c9000, + .virt_start = 0x6d1c9000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 6d1ca000-6d3cffff : ACPI Non-volatile Storage */ + { + .phys_start = 0x6d1ca000, + .virt_start = 0x6d1ca000, + .size = 0x206000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 6d3d0000-6d850fff : System RAM */ + { + .phys_start = 0x6d3d0000, + .virt_start = 0x6d3d0000, + .size = 0x481000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 6dfe2000-6dffffff : System RAM */ + { + .phys_start = 0x6dfe2000, + .virt_start = 0x6dfe2000, + .size = 0x1e000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 6e000000-6fffffff : RAM buffer */ + { + .phys_start = 0x6e000000, + .virt_start = 0x6e000000, + .size = 0x2000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: c0000000-cfffffff : 0000:00:01.0 */ + { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0000000-d07fffff : 0000:00:01.0 */ + { + .phys_start = 0xd0000000, + .virt_start = 0xd0000000, + .size = 0x800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0801000-d0803fff : r8169 */ + { + .phys_start = 0xd0801000, + .virt_start = 0xd0801000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea00000-fea00fff : r8169 */ + { + .phys_start = 0xfea00000, + .virt_start = 0xfea00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb00000-feb3ffff : 0000:00:01.0 */ + { + .phys_start = 0xfeb00000, + .virt_start = 0xfeb00000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb40000-feb5ffff : 0000:00:01.0 */ + { + .phys_start = 0xfeb40000, + .virt_start = 0xfeb40000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb60000-feb63fff : ICH HD audio */ + { + .phys_start = 0xfeb60000, + .virt_start = 0xfeb60000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb64000-feb67fff : ICH HD audio */ + { + .phys_start = 0xfeb64000, + .virt_start = 0xfeb64000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb68000-feb68fff : xhci_hcd */ + { + .phys_start = 0xfeb68000, + .virt_start = 0xfeb68000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6a000-feb6afff : xhci_hcd */ + { + .phys_start = 0xfeb6a000, + .virt_start = 0xfeb6a000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6c000-feb6cfff : ohci_hcd */ + { + .phys_start = 0xfeb6c000, + .virt_start = 0xfeb6c000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6d000-feb6d0ff : ehci_hcd */ + { + .phys_start = 0xfeb6d000, + .virt_start = 0xfeb6d000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6e000-feb6efff : ohci_hcd */ + { + .phys_start = 0xfeb6e000, + .virt_start = 0xfeb6e000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6f000-feb6f0ff : ehci_hcd */ + { + .phys_start = 0xfeb6f000, + .virt_start = 0xfeb6f000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb70000-feb70fff : ohci_hcd */ + { + .phys_start = 0xfeb70000, + .virt_start = 0xfeb70000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb71000-feb717ff : ahci */ + { + .phys_start = 0xfeb71000, + .virt_start = 0xfeb71000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb80000-febfffff : pnp 00:02 */ + { + .phys_start = 0xfeb80000, + .virt_start = 0xfeb80000, + .size = 0x80000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fed00000-fed003ff : HPET 0 */ + { + .phys_start = 0xfed00000, + .virt_start = 0xfed00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fed61000-fed70fff : pnp 00:09 */ + { + .phys_start = 0xfed61000, + .virt_start = 0xfed61000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 3f000000-3f1fffff : JAILHOUSE Inmate Memory */ + { + .phys_start = 0x3f000000, + .virt_start = 0x3f000000, + .size = 0x200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* IOAPIC 0, GSI base 0 */ + { + .address = 0xfec00000, + .id = 0x0, + .pin_bitmap = { + 0xffffff + }, + }, + /* IOAPIC 1, GSI base 24 */ + { + .address = 0xfec01000, + .id = 0x0, + .pin_bitmap = { + 0xffffff + }, + }, + }, + + .pio_regions = { + PIO_RANGE(0x20, 8), /* HACK: PIC */ + PIO_RANGE(0x40, 4), /* PIT */ + PIO_RANGE(0x60, 2), /* HACK: NMI status/control */ + PIO_RANGE(0x64, 1), /* i8042 */ + PIO_RANGE(0x70, 2), /* RTC */ + PIO_RANGE(0x3b0, 0x30), /* VGA */ + PIO_RANGE(0x3e0, 0x918), /* HACK: PCI bus */ + PIO_RANGE(0xd00, 0xf300), /* HACK: PCI bus */ + }, + + .pci_devices = { + /* PCIDevice: 00:00.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x0, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:01.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x8, + .caps_start = 0, + .num_caps = 4, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:01.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x9, + .caps_start = 0, + .num_caps = 4, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:02.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x10, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:03.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x18, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:03.1 */ + { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x19, + .caps_start = 4, + .num_caps = 5, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:04.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x20, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:10.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x80, + .caps_start = 9, + .num_caps = 4, + .num_msi_vectors = 8, + .msi_64bits = 1, + .num_msix_vectors = 8, + .msix_region_size = 0x1000, + .msix_address = 0xfeb6b000, + }, + /* PCIDevice: 00:10.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x81, + .caps_start = 9, + .num_caps = 4, + .num_msi_vectors = 8, + .msi_64bits = 1, + .num_msix_vectors = 8, + .msix_region_size = 0x1000, + .msix_address = 0xfeb69000, + }, + /* PCIDevice: 00:11.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x88, + .caps_start = 13, + .num_caps = 2, + .num_msi_vectors = 8, + .msi_64bits = 1, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:12.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x90, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:12.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x92, + .caps_start = 15, + .num_caps = 2, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:13.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x98, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:13.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x9a, + .caps_start = 15, + .num_caps = 2, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:14.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xa0, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:14.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xa2, + .caps_start = 17, + .num_caps = 1, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:14.3 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xa3, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:14.4 */ + { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xa4, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:14.5 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xa5, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc0, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc1, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc2, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.3 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc3, + .caps_start = 18, + .num_caps = 1, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.4 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc4, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 00:18.5 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0xc5, + .caps_start = 0, + .num_caps = 0, + .num_msi_vectors = 0, + .msi_64bits = 0, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + /* PCIDevice: 01:00.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, + .domain = 0x0, + .bdf = 0x100, + .caps_start = 19, + .num_caps = 5, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 4, + .msix_region_size = 0x1000, + .msix_address = 0xd0800000, + }, + }, + + .pci_caps = { + /* PCIDevice: 00:01.0 */ + /* PCIDevice: 00:01.1 */ + { + .id = PCI_CAP_ID_VNDR, + .start = 0x48, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x58, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xa0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + /* PCIDevice: 00:03.1 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x58, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xa0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_SSVID, + .start = 0xb0, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_HT, + .start = 0xb8, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:10.0 */ + /* PCIDevice: 00:10.1 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x70, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0x90, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0xa0, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:11.0 */ + { + .id = PCI_CAP_ID_MSI, + .start = 0x50, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_SATA, + .start = 0x70, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:12.2 */ + /* PCIDevice: 00:13.2 */ + { + .id = PCI_CAP_ID_PM, + .start = 0xc0, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_DBG, + .start = 0xe4, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:14.2 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + /* PCIDevice: 00:18.3 */ + { + .id = PCI_CAP_ID_SECDEV, + .start = 0xf0, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 01:00.0 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x40, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x50, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x70, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0xb0, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_VPD, + .start = 0xd0, + .len = 2, + .flags = 0, + }, + }, +}; diff --git a/configs/x86/imb-a180.c b/configs/x86/imb-a180.c new file mode 100644 index 0000000000000000000000000000000000000000..05f7279a2552e9aca93fc655ea0c09ba9d7061a2 --- /dev/null +++ b/configs/x86/imb-a180.c @@ -0,0 +1,780 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for ASRock IMB-A180 G-Series (4G RAM) board + * created with 'jailhouse config create imb-a180.c' + * + * Copyright (c) Siemens AG, 2014 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Adjusted by Valentine Sinitsyn + * + * NOTE: This config expects the following to be appended to your kernel cmdline + * "memmap=82M$0x3a000000" + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[42]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pio pio_regions[8]; + struct jailhouse_pci_device pci_devices[26]; + struct jailhouse_pci_capability pci_caps[26]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x3a000000, + .size = 0x600000, + }, + .debug_console = { + .address = 0x3f8, + /* .divider = 0x1, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + }, + .platform_info = { + .pci_mmconfig_base = 0xe0000000, + .pci_mmconfig_end_bus = 0xff, + .x86 = { + .pm_timer_address = 0x808, + }, + }, + .root_cell = { + .name = "IMB-A180", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + }, + }, + + .cpus = { + 0x000000000000000f, + }, + + .mem_regions = { + /* MemRegion: 00000000-0009e7ff : System RAM */ + { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x9f000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 000a0000-000bffff : PCI Bus 0000:00 */ + { + .phys_start = 0xa0000, + .virt_start = 0xa0000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 000c0000-000ce9ff : Video ROM */ + { + .phys_start = 0xc0000, + .virt_start = 0xc0000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: 000e0000-000fffff : System ROM */ + { + .phys_start = 0xe0000, + .virt_start = 0xe0000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: 00100000-3affffff : System RAM */ + { + .phys_start = 0x00100000, + .virt_start = 0x00100000, + .size = 0x3af00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 3f200000-9db10fff : System RAM */ + { + .phys_start = 0x3f200000, + .virt_start = 0x3f200000, + .size = 0x5e911000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9db41000-9dc7ffff : System RAM */ + { + .phys_start = 0x9db41000, + .virt_start = 0x9db41000, + .size = 0x13f000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9dc80000-9e148fff : ACPI Non-volatile Storage */ + { + .phys_start = 0x9dc80000, + .virt_start = 0x9dc80000, + .size = 0x4c9000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: 9ede5000-9ede5fff : System RAM */ + { + .phys_start = 0x9ede5000, + .virt_start = 0x9ede5000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9ede6000-9ededfff : ACPI Non-volatile Storage */ + { + .phys_start = 0x9ede6000, + .virt_start = 0x9ede6000, + .size = 0x8000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: 9edee000-9ef42fff : System RAM */ + { + .phys_start = 0x9edee000, + .virt_start = 0x9edee000, + .size = 0x155000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9f42d000-9f46ffff : System RAM */ + { + .phys_start = 0x9f42d000, + .virt_start = 0x9f42d000, + .size = 0x43000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9f7f1000-9f7fffff : System RAM */ + { + .phys_start = 0x9f7f1000, + .virt_start = 0x9f7f1000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 9f800000-9fffffff : RAM buffer */ + { + .phys_start = 0x9f800000, + .virt_start = 0x9f800000, + .size = 0x800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: a0000000-bfffffff : pnp 00:01 */ + { + .phys_start = 0xa0000000, + .virt_start = 0xa0000000, + .size = 0x20000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: c0000000-cfffffff : 0000:00:01.0 */ + { + .phys_start = 0xc0000000, + .virt_start = 0xc0000000, + .size = 0x10000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0000000-d07fffff : 0000:00:01.0 */ + { + .phys_start = 0xd0000000, + .virt_start = 0xd0000000, + .size = 0x800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0800000-d0803fff : r8169 */ + { + .phys_start = 0xd0800000, + .virt_start = 0xd0800000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0804000-d0804fff : r8169 */ + { + .phys_start = 0xd0804000, + .virt_start = 0xd0804000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: d0900000-d0903fff : r8169 */ + { + .phys_start = 0xd0900000, + .virt_start = 0xd0900000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea00000-fea03fff : 0000:01:00.3 */ + { + .phys_start = 0xfea00000, + .virt_start = 0xfea00000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea04000-fea07fff : 0000:01:00.2 */ + { + .phys_start = 0xfea04000, + .virt_start = 0xfea04000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea08000-fea0bfff : 0000:01:00.1 */ + { + .phys_start = 0xfea08000, + .virt_start = 0xfea08000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea0c000-fea0c0ff : 0000:01:00.3 */ + { + .phys_start = 0xfea0c000, + .virt_start = 0xfea0c000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea0d000-fea0dfff : 0000:01:00.2 */ + { + .phys_start = 0xfea0d000, + .virt_start = 0xfea0d000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea0e000-fea0efff : 0000:01:00.1 */ + { + .phys_start = 0xfea0e000, + .virt_start = 0xfea0e000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea0f000-fea0ffff : r8169 */ + { + .phys_start = 0xfea0f000, + .virt_start = 0xfea0f000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb00000-feb3ffff : 0000:00:01.0 */ + { + .phys_start = 0xfeb00000, + .virt_start = 0xfeb00000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb40000-feb5ffff : 0000:00:01.0 */ + { + .phys_start = 0xfeb40000, + .virt_start = 0xfeb40000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb60000-feb63fff : ICH HD audio */ + { + .phys_start = 0xfeb60000, + .virt_start = 0xfeb60000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb64000-feb67fff : ICH HD audio */ + { + .phys_start = 0xfeb64000, + .virt_start = 0xfeb64000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb68000-feb69fff : xhci_hcd */ + { + .phys_start = 0xfeb68000, + .virt_start = 0xfeb68000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6a000-feb6a0ff : ehci_hcd */ + { + .phys_start = 0xfeb6a000, + .virt_start = 0xfeb6a000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6b000-feb6bfff : ohci_hcd */ + { + .phys_start = 0xfeb6b000, + .virt_start = 0xfeb6b000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6c000-feb6c0ff : ehci_hcd */ + { + .phys_start = 0xfeb6c000, + .virt_start = 0xfeb6c000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6d000-feb6dfff : ohci_hcd */ + { + .phys_start = 0xfeb6d000, + .virt_start = 0xfeb6d000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: feb6e000-feb6e3ff : ahci */ + { + .phys_start = 0xfeb6e000, + .virt_start = 0xfeb6e000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fed00000-fed003ff : HPET 0 */ + { + .phys_start = 0xfed00000, + .virt_start = 0xfed00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fed61000-fed70fff : pnp 00:0e */ + { + .phys_start = 0xfed61000, + .virt_start = 0xfed61000, + .size = 0x10000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: 100001000-13effffff : System RAM */ + { + .phys_start = 0x100001000, + .virt_start = 0x100001000, + .size = 0x3efff000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 13f000000-13fffffff : RAM buffer */ + { + .phys_start = 0x13f000000, + .virt_start = 0x13f000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* MemRegion: 3f000000-3f1fffff : JAILHOUSE Inmate Memory */ + { + .phys_start = 0x3f000000, + .virt_start = 0x3f000000, + .size = 0x200000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* IOAPIC */ { + .address = 0xfec00000, + .id = 0x0, + .pin_bitmap = { + 0xffffff + }, + }, + }, + + .pio_regions = { + PIO_RANGE(0x20, 2), /* HACK: PIC */ + PIO_RANGE(0x40, 4), /* PIT */ + PIO_RANGE(0x60, 2), /* HACK: NMI status/control */ + PIO_RANGE(0x64, 1), /* i8042 */ + PIO_RANGE(0x70, 2), /* RTC */ + PIO_RANGE(0x3b0, 0x30), /* VGA */ + PIO_RANGE(0x3e0, 0x918), /* HACK: PCI bus */ + PIO_RANGE(0xd00, 0xf300), /* HACK: PCI bus */ + }, + + .pci_devices = { + /* PCIDevice: 00:00.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x0, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:01.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x8, + .caps_start = 0, + .num_caps = 4, + }, + /* PCIDevice: 00:01.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x9, + .caps_start = 0, + .num_caps = 4, + }, + /* PCIDevice: 00:02.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x10, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:02.3 */ + { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .domain = 0x0, + .bdf = 0x13, + .caps_start = 4, + .num_caps = 5, + }, + /* PCIDevice: 00:02.4 */ + { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .domain = 0x0, + .bdf = 0x14, + .caps_start = 4, + .num_caps = 5, + }, + /* PCIDevice: 00:10.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x80, + .caps_start = 9, + .num_caps = 4, + }, + /* PCIDevice: 00:11.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x88, + .caps_start = 13, + .num_caps = 4, + }, + /* PCIDevice: 00:12.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x90, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:12.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x92, + .caps_start = 17, + .num_caps = 2, + }, + /* PCIDevice: 00:13.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x98, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:13.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x9a, + .caps_start = 17, + .num_caps = 2, + }, + /* PCIDevice: 00:14.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xa0, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:14.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xa2, + .caps_start = 19, + .num_caps = 1, + }, + /* PCIDevice: 00:14.3 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xa3, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:18.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc0, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:18.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc1, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:18.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc2, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:18.3 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc3, + .caps_start = 20, + .num_caps = 1, + }, + /* PCIDevice: 00:18.4 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc4, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 00:18.5 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0xc5, + .caps_start = 0, + .num_caps = 0, + }, + /* PCIDevice: 01:00.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x100, + .caps_start = 21, + .num_caps = 5, + }, + /* PCIDevice: 01:00.1 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x101, + .caps_start = 21, + .num_caps = 5, + }, + /* PCIDevice: 01:00.2 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x102, + .caps_start = 21, + .num_caps = 5, + }, + /* PCIDevice: 01:00.3 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x103, + .caps_start = 21, + .num_caps = 5, + }, + /* PCIDevice: 02:00.0 */ + { + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0, + .bdf = 0x200, + .caps_start = 21, + .num_caps = 5, + }, + }, + + .pci_caps = { + /* PCIDevice: 00:01.0 */ + /* PCIDevice: 00:01.1 */ + { + .id = PCI_CAP_ID_VNDR, + .start = 0x48, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x58, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xa0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + /* PCIDevice: 00:02.3 */ + /* PCIDevice: 00:02.4 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x58, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xa0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_SSVID, + .start = 0xb0, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_HT, + .start = 0xb8, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:10.0 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x70, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0x90, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0xa0, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:11.0 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x60, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_SATA, + .start = 0x70, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x50, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_AF, + .start = 0xd0, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:12.2 */ + /* PCIDevice: 00:13.2 */ + { + .id = PCI_CAP_ID_PM, + .start = 0xc0, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_DBG, + .start = 0xe4, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 00:14.2 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x50, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + /* PCIDevice: 00:18.3 */ + { + .id = PCI_CAP_ID_SECDEV, + .start = 0xf0, + .len = 2, + .flags = 0, + }, + /* PCIDevice: 01:00.0 */ + /* PCIDevice: 01:00.1 */ + /* PCIDevice: 01:00.2 */ + /* PCIDevice: 01:00.3 */ + /* PCIDevice: 02:00.0 */ + { + .id = PCI_CAP_ID_PM, + .start = 0x40, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x50, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x70, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0xb0, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_VPD, + .start = 0xd0, + .len = 2, + .flags = 0, + }, + }, +}; diff --git a/configs/x86/ioapic-demo.c b/configs/x86/ioapic-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..863b3ea7fb634c681a7aea4eae8a81c6e33afae7 --- /dev/null +++ b/configs/x86/ioapic-demo.c @@ -0,0 +1,83 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for IOAPIC demo inmate: + * 1 CPU, 1 MB RAM, serial ports, 1 ACPI IRQ pin + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[2]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pio pio_regions[5]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "ioapic-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = 0, + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* IOAPIC */ { + .address = 0xfec00000, + .id = 0xff01, + .pin_bitmap = { + 0x000200 /* ACPI IRQ */ + }, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0x600, 4), /* acpi-evt */ + PIO_RANGE(0x800, 4), /* apci-pm1a */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial2 */ + }, +}; diff --git a/configs/x86/ivshmem-demo.c b/configs/x86/ivshmem-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..4c24193f30a3a5719ce1e2572cdb2ca415e759c1 --- /dev/null +++ b/configs/x86/ivshmem-demo.c @@ -0,0 +1,119 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for ivshmem inmate demo: + * 1 CPU, 1MB RAM, serial ports, 4K shmem + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[7]; + struct jailhouse_pio pio_regions[2]; + struct jailhouse_pci_device pci_devices[1]; + struct jailhouse_pci_capability pci_caps[0]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "ivshmem-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0b0010, + }, + + .mem_regions = { + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x3f0f0000, + .virt_start = 0x3f0f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0f1000, + .virt_start = 0x3f0f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fa000, + .virt_start = 0x3f0fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fc000, + .virt_start = 0x3f0fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fe000, + .virt_start = 0x3f0fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0000, + .bdf = 0x100 | (0x0e << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 16, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + }, +}; diff --git a/configs/x86/linux-x86-demo.c b/configs/x86/linux-x86-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..0703c5b9f673cc270da8d87ea5abdb214d057380 --- /dev/null +++ b/configs/x86/linux-x86-demo.c @@ -0,0 +1,307 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Linux inmate, 1 CPU, 74 MB RAM, ~1MB shmem, serial ports + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; +#ifdef CONFIG_QEMU_E1000E_ASSIGNMENT + struct jailhouse_memory mem_regions[24]; +#else + struct jailhouse_memory mem_regions[20]; +#endif + struct jailhouse_cache cache_regions[1]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pio pio_regions[3]; +#ifdef CONFIG_QEMU_E1000E_ASSIGNMENT + struct jailhouse_pci_device pci_devices[5]; +#else + struct jailhouse_pci_device pci_devices[4]; +#endif + struct jailhouse_pci_capability pci_caps[6]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-x86-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_cache_regions = ARRAY_SIZE(config.cache_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + }, + + .cpus = { + 0b1100, + }, + + .mem_regions = { + /* IVSHMEM shared memory region (virtio-blk front) */ + { + .phys_start = 0x3f000000, + .virt_start = 0x3f000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f001000, + .virt_start = 0x3f001000, + .size = 0xdf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory region (virtio-con front) */ + { + .phys_start = 0x3f0e0000, + .virt_start = 0x3f0e0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0e1000, + .virt_start = 0x3f0e1000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x3f0f0000, + .virt_start = 0x3f0f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0f1000, + .virt_start = 0x3f0f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fa000, + .virt_start = 0x3f0fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fc000, + .virt_start = 0x3f0fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, + }, + { + .phys_start = 0x3f0fe000, + .virt_start = 0x3f0fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_ROOTSHARED, + }, + /* IVSHMEM shared memory regions (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x3f100000, 1), + /* low RAM */ { + .phys_start = 0x3a600000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + /* high RAM */ { + .phys_start = 0x3a700000, + .virt_start = 0x00200000, + .size = 0x4700000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | + JAILHOUSE_MEM_LOADABLE, + }, +#ifdef CONFIG_QEMU_E1000E_ASSIGNMENT + /* MemRegion: fea00000-fea3ffff : 0000:00:02.0 */ + { + .phys_start = 0xfea00000, + .virt_start = 0xfea00000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea40000-fea5ffff : e1000e */ + { + .phys_start = 0xfea40000, + .virt_start = 0xfea40000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea60000-fea7ffff : e1000e */ + { + .phys_start = 0xfea60000, + .virt_start = 0xfea60000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea91000-fea93fff : e1000e */ + { + .phys_start = 0xfea91000, + .virt_start = 0xfea91000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, +#endif + }, + + .cache_regions = { + { + .start = 0, + .size = 2, + .type = JAILHOUSE_CACHE_L3, + }, + }, + + .irqchips = { + /* IOAPIC */ { + .address = 0xfec00000, + .id = 0xff00, + .pin_bitmap = { + (1 << 3) | (1 << 4), + }, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial1 */ + }, + + .pci_devices = { + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0c << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT + + VIRTIO_DEV_BLOCK, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0d << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 3, + .shmem_regions_start = 4, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT + + VIRTIO_DEV_CONSOLE, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0e << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 16, + .shmem_regions_start = 8, + .shmem_dev_id = 2, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0f << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 13, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, +#ifdef CONFIG_QEMU_E1000E_ASSIGNMENT + { /* e1000e */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x0010, + .bar_mask = { + 0xfffe0000, 0xfffe0000, 0xffffffe0, + 0xffffc000, 0x00000000, 0x00000000, + }, + .caps_start = 0, + .num_caps = 6, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 5, + .msix_region_size = 0x1000, + .msix_address = 0xfea90000, + }, +#endif + }, + + .pci_caps = { + { /* e1000e */ + .id = PCI_CAP_ID_PM, + .start = 0xc8, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xd0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0xe0, + .len = 20, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0xa0, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_EXT_CAP_ID_ERR | JAILHOUSE_PCI_EXT_CAP, + .start = 0x100, + .len = 4, + .flags = 0, + }, + { + .id = PCI_EXT_CAP_ID_DSN | JAILHOUSE_PCI_EXT_CAP, + .start = 0x140, + .len = 4, + .flags = 0, + }, + } +}; diff --git a/configs/x86/pci-demo.c b/configs/x86/pci-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..a4115744928caf8f69fb58983123ac2109018d04 --- /dev/null +++ b/configs/x86/pci-demo.c @@ -0,0 +1,100 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for PCI demo inmate: + * 1 CPU, 1 MB RAM, serial ports, 1 Intel HDA PCI device + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[3]; + struct jailhouse_pio pio_regions[3]; + struct jailhouse_pci_device pci_devices[1]; + struct jailhouse_pci_capability pci_caps[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "pci-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + /* HDA BAR0 */ { + .phys_start = 0xfebd4000, + .virt_start = 0xfebd4000, + .size = 0x00004000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial2 */ + }, + + .pci_devices = { + { /* Intel HDA @00:1b.0 */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00d8, + .caps_start = 0, + .num_caps = 1, + .num_msi_vectors = 1, + .msi_64bits = 1, + }, + }, + + .pci_caps = { + { /* Intel HDA @00:1b.0 */ + .id = PCI_CAP_ID_MSI, + .start = 0x60, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + }, +}; diff --git a/configs/x86/qemu-x86.c b/configs/x86/qemu-x86.c new file mode 100644 index 0000000000000000000000000000000000000000..c4d7ecfc8900bb2590dbcc80dea47fe8ffcd8fa3 --- /dev/null +++ b/configs/x86/qemu-x86.c @@ -0,0 +1,493 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Test configuration for QEMU Q35 VM, 1 GB RAM, 4 cores, + * 6 MB hypervisor, 74 MB inmates, 1MB shared mem devices + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * See README.md for QEMU command lines on Intel and AMD. + * Guest kernel command line appendix: memmap=82M$0x3a000000 + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[31]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pio pio_regions[13]; + struct jailhouse_pci_device pci_devices[12]; + struct jailhouse_pci_capability pci_caps[16]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = 0x3a000000, + .size = 0x600000, + }, + .debug_console = { + .address = 0x3f8, + /* .divider = 0x1, */ + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + }, + .platform_info = { + .pci_mmconfig_base = 0xb0000000, + .pci_mmconfig_end_bus = 0xff, + .iommu_units = { + { + .type = JAILHOUSE_IOMMU_INTEL, + .base = 0xfed90000, + .size = 0x1000, + }, + }, + .x86 = { + .pm_timer_address = 0x608, + .vtd_interrupt_limit = 256, + }, + }, + .root_cell = { + .name = "QEMU-VM", + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + }, + }, + + .cpus = { + 0xf, + }, + + .mem_regions = { + /* IVSHMEM shared memory region (virtio-blk back-end) */ + { + .phys_start = 0x3f000000, + .virt_start = 0x3f000000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x3f001000, + .virt_start = 0x3f001000, + .size = 0xdf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory region (virtio-con back-end) */ + { + .phys_start = 0x3f0e0000, + .virt_start = 0x3f0e0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x3f0e1000, + .virt_start = 0x3f0e1000, + .size = 0xf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { 0 }, + { 0 }, + /* IVSHMEM shared memory regions (demo) */ + { + .phys_start = 0x3f0f0000, + .virt_start = 0x3f0f0000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x3f0f1000, + .virt_start = 0x3f0f1000, + .size = 0x9000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x3f0fa000, + .virt_start = 0x3f0fa000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + { + .phys_start = 0x3f0fc000, + .virt_start = 0x3f0fc000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + { + .phys_start = 0x3f0fe000, + .virt_start = 0x3f0fe000, + .size = 0x2000, + .flags = JAILHOUSE_MEM_READ, + }, + /* IVSHMEM shared memory regions (networking) */ + JAILHOUSE_SHMEM_NET_REGIONS(0x3f100000, 0), + /* RAM */ { + .phys_start = 0x0, + .virt_start = 0x0, + .size = 0x3a000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* RAM (inmates) */ { + .phys_start = 0x3a600000, + .virt_start = 0x3a600000, + .size = 0x4a00000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* RAM */ { + .phys_start = 0x3f200000, + .virt_start = 0x3f200000, + .size = 0xddf000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA, + }, + /* ACPI */ { + .phys_start = 0x3ffdf000, + .virt_start = 0x3ffdf000, + .size = 0x21000, + .flags = JAILHOUSE_MEM_READ, + }, + /* MemRegion: fd000000-fdffffff : 0000:00:01.0 (vesafb) */ + { + .phys_start = 0xfd000000, + .virt_start = 0xfd000000, + .size = 0x1000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fe200000-fe203fff : 0000:00:1f.7 (virtio-9p) */ + { + .phys_start = 0xfe200000, + .virt_start = 0xfe200000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea00000-fea3ffff : 0000:00:02.0 */ + { + .phys_start = 0xfea00000, + .virt_start = 0xfea00000, + .size = 0x40000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea40000-fea5ffff : e1000e */ + { + .phys_start = 0xfea40000, + .virt_start = 0xfea40000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea60000-fea7ffff : e1000e */ + { + .phys_start = 0xfea60000, + .virt_start = 0xfea60000, + .size = 0x20000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea91000-fea93fff : e1000e */ + { + .phys_start = 0xfea91000, + .virt_start = 0xfea91000, + .size = 0x3000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea94000-fea97fff : 0000:00:1b.0 (ICH HD audio) */ + { + .phys_start = 0xfea94000, + .virt_start = 0xfea94000, + .size = 0x4000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea98000-fea98fff : 0000:00:01.0 (vesafd) */ + { + .phys_start = 0xfea98000, + .virt_start = 0xfea98000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fea9a000-fea9afff : 0000:00:1f.2 (ahci) */ + { + .phys_start = 0xfea9a000, + .virt_start = 0xfea9a000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + /* MemRegion: fed00000-fed003ff : PNP0103:00 (HPET) */ + { + .phys_start = 0xfed00000, + .virt_start = 0xfed00000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, + }, + }, + + .irqchips = { + /* IOAPIC */ { + .address = 0xfec00000, + .id = 0xff00, + .pin_bitmap = { + 0xffffff + }, + }, + }, + + .pio_regions = { + PIO_RANGE(0x0, 0x1f), /* floppy DMA controller */ + PIO_RANGE(0x40, 0x4), /* PIT */ + PIO_RANGE(0x60, 0x2), /* HACK: NMI status/control */ + PIO_RANGE(0x64, 0x1), /* i8042 */ + PIO_RANGE(0x70, 0x2), /* rtc */ + PIO_RANGE(0x1ce, 0x3), /* vbe */ + PIO_RANGE(0x2f8, 0x8), /* serial2 */ + PIO_RANGE(0x3b0, 0x30), /* VGA */ + PIO_RANGE(0x3f0, 0x8), /* floppy */ + PIO_RANGE(0x402, 0x1), /* invalid but accessed by X */ + PIO_RANGE(0xcd0, 0x8), /* QEMU ACPI hotplug */ + PIO_RANGE(0x5658, 0x4), /* vmport */ + PIO_RANGE(0xd000, 0xff), /* PCI devices */ + }, + + .pci_devices = { + { /* VGA */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x0008, + }, + { /* e1000e */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x0010, + .bar_mask = { + 0xfffe0000, 0xfffe0000, 0xffffffe0, + 0xffffc000, 0x00000000, 0x00000000, + }, + .caps_start = 5, + .num_caps = 6, + .num_msi_vectors = 1, + .msi_64bits = 1, + .num_msix_vectors = 5, + .msix_region_size = 0x1000, + .msix_address = 0xfea90000, + }, + /* PCI bridge */ + { + .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .domain = 0x0000, + .bdf = 0x0018, + .bar_mask = { + 0xffffff00, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, + }, + .caps_start = 11, + .num_caps = 5, + .num_msi_vectors = 1, + .msi_64bits = 1, + .msi_maskable = 1, + .num_msix_vectors = 0, + .msix_region_size = 0x0, + .msix_address = 0x0, + }, + { /* ICH HD audio */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00d8, + .caps_start = 0, + .num_caps = 2, + .num_msi_vectors = 1, + .msi_64bits = 1, + }, + { /* ISA bridge */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00f8, + }, + { /* AHCI */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00fa, + .caps_start = 2, + .num_caps = 2, + .num_msi_vectors = 1, + .msi_64bits = 1, + }, + { /* SMBus */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00fb, + }, + { /* virtio-9p-pci */ + .type = JAILHOUSE_PCI_TYPE_DEVICE, + .domain = 0x0000, + .bdf = 0x00ff, + .bar_mask = { + 0xffffffe0, 0xfffff000, 0x00000000, + 0x00000000, 0xffffc000, 0xffffffff, + }, + .caps_start = 4, + .num_caps = 1, + .num_msix_vectors = 2, + .msix_region_size = 0x1000, + .msix_address = 0xfea9b000, + }, + { /* IVSHMEM (virtio-blk back-end) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0c << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 0, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK + + VIRTIO_DEV_BLOCK, + }, + { /* IVSHMEM (virtio-con back-end) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0, + .bdf = 0x100 | (0x0d << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 3, + .shmem_regions_start = 4, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK + + VIRTIO_DEV_CONSOLE, + }, + { /* IVSHMEM (demo) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0000, + .bdf = 0x100 | (0x0e << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 16, + .shmem_regions_start = 8, + .shmem_dev_id = 0, + .shmem_peers = 3, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, + }, + { /* IVSHMEM (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0x0000, + .bdf = 0x100 | (0x0f << 3), + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX, + .num_msix_vectors = 2, + .shmem_regions_start = 13, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, + + .pci_caps = { + { /* ICH HD audio */ + .id = PCI_CAP_ID_MSI, + .start = 0x60, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { /* non-cap registers: HDCTL, TCSEL, DCKCTL, DCKSTS */ + .start = 0x40, + .len = 0x10, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { /* AHCI */ + .id = PCI_CAP_ID_SATA, + .start = 0xa8, + .len = 2, + .flags = 0, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0x80, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { /* virtio-9p-pci */ + .id = PCI_CAP_ID_MSIX, + .start = 0x98, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { /* e1000e */ + .id = PCI_CAP_ID_PM, + .start = 0xc8, + .len = 8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSI, + .start = 0xd0, + .len = 14, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0xe0, + .len = 20, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_MSIX, + .start = 0xa0, + .len = 12, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_EXT_CAP_ID_ERR | JAILHOUSE_PCI_EXT_CAP, + .start = 0x100, + .len = 4, + .flags = 0, + }, + { + .id = PCI_EXT_CAP_ID_DSN | JAILHOUSE_PCI_EXT_CAP, + .start = 0x140, + .len = 4, + .flags = 0, + }, + /* PCI bridge */ + { + .id = PCI_CAP_ID_MSI, + .start = 0x8c, + .len = 0x18, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_PM, + .start = 0x84, + .len = 0x8, + .flags = JAILHOUSE_PCICAPS_WRITE, + }, + { + .id = PCI_CAP_ID_EXP, + .start = 0x48, + .len = 0x3c, + .flags = 0, + }, + { + .id = 0xc, + .start = 0x40, + .len = 0x02, + .flags = 0, + }, + { + .id = PCI_EXT_CAP_ID_ERR | JAILHOUSE_PCI_EXT_CAP, + .start = 0x100, + .len = 0x40, + .flags = 0, + }, + }, +}; diff --git a/configs/x86/smp-demo.c b/configs/x86/smp-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..35bf9504a8498cd2ecd9486cc982321f470b0bea --- /dev/null +++ b/configs/x86/smp-demo.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for SMP demo inmates, 3 CPUs, 1 MB RAM, serial ports + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[2]; + struct jailhouse_pio pio_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "smp-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = 0, + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0xe, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial2 */ + }, +}; diff --git a/configs/x86/tiny-demo.c b/configs/x86/tiny-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..464c7acb167337e2c572aa40aca10a77f524e73f --- /dev/null +++ b/configs/x86/tiny-demo.c @@ -0,0 +1,80 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Minimal configuration for demo inmates, 1 CPU, 1 MB RAM, serial ports + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[2]; + struct jailhouse_cache cache_regions[1]; + struct jailhouse_pio pio_regions[3]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "tiny-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | + JAILHOUSE_CELL_TEST_DEVICE | + JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_cache_regions = ARRAY_SIZE(config.cache_regions), + .num_irqchips = 0, + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = 0, + + .console = { + .type = JAILHOUSE_CON_TYPE_8250, + .flags = JAILHOUSE_CON_ACCESS_PIO, + .address = 0x3f8, + }, + }, + + .cpus = { + 0x4, + }, + + .mem_regions = { + /* RAM */ { + .phys_start = 0x3ee00000, + .virt_start = 0, + .size = 0x00100000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + /* communication region */ { + .virt_start = 0x00100000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .cache_regions = { + { + .start = 2, + .size = 1, + .type = JAILHOUSE_CACHE_L3, + }, + }, + + .pio_regions = { + PIO_RANGE(0x2f8, 8), /* serial 2 */ + PIO_RANGE(0x3f8, 8), /* serial 1 */ + PIO_RANGE(0xe010, 8), /* OXPCIe952 serial2 */ + }, +}; diff --git a/driver/Makefile b/driver/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8dded8483d61700f4fddd87bb506a8147fc49848 --- /dev/null +++ b/driver/Makefile @@ -0,0 +1,29 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2015 +# +# Authors: +# Jan Kiszka +# Benjamin Block +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +obj-m := jailhouse.o + +ccflags-y := -I$(src)/../hypervisor/arch/$(SRCARCH)/include \ + -I$(src)/../hypervisor/include \ + -I$(src)/../include/arch/$(SRCARCH) \ + -I$(src)/../include + +jailhouse-y := cell.o main.o sysfs.o +jailhouse-$(CONFIG_PCI) += pci.o +jailhouse-$(CONFIG_OF) += vpci_template.dtb.o + +targets += vpci_template.dtb vpci_template.dtb.S + +.SECONDARY: \ + $(obj)/vpci_template.dtb.S \ + $(obj)/vpci_template.dtb diff --git a/driver/cell.c b/driver/cell.c new file mode 100644 index 0000000000000000000000000000000000000000..ade61edb2880bc3c696647a53ad7a28746cb94ab --- /dev/null +++ b/driver/cell.c @@ -0,0 +1,486 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* For compatibility with older kernel versions */ +#include + +#include +#include +#include +#include +#include + +#include "cell.h" +#include "main.h" +#include "pci.h" +#include "sysfs.h" + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0) +#define add_cpu(cpu) cpu_up(cpu) +#define remove_cpu(cpu) cpu_down(cpu) +#endif + +struct cell *root_cell; + +static LIST_HEAD(cells); +static cpumask_t offlined_cpus; + +void jailhouse_cell_kobj_release(struct kobject *kobj) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + jailhouse_pci_cell_cleanup(cell); + vfree(cell->memory_regions); + kfree(cell); +} + +static struct cell *cell_create(const struct jailhouse_cell_desc *cell_desc) +{ + struct cell *cell; + unsigned int id; + int err; + + if (cell_desc->num_memory_regions >= + ULONG_MAX / sizeof(struct jailhouse_memory)) + return ERR_PTR(-EINVAL); + + /* determine cell id */ + id = 0; +retry: + list_for_each_entry(cell, &cells, entry) + if (cell->id == id) { + id++; + goto retry; + } + + cell = kzalloc(sizeof(*cell), GFP_KERNEL); + if (!cell) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&cell->entry); + + cell->id = id; + + bitmap_copy(cpumask_bits(&cell->cpus_assigned), + jailhouse_cell_cpu_set(cell_desc), + min((unsigned int)nr_cpumask_bits, + cell_desc->cpu_set_size * 8)); + + cell->num_memory_regions = cell_desc->num_memory_regions; + cell->memory_regions = vmalloc(sizeof(struct jailhouse_memory) * + cell->num_memory_regions); + if (!cell->memory_regions) { + kfree(cell); + return ERR_PTR(-ENOMEM); + } + + memcpy(cell->name, cell_desc->name, JAILHOUSE_CELL_ID_NAMELEN); + cell->name[JAILHOUSE_CELL_ID_NAMELEN] = 0; + + memcpy(cell->memory_regions, jailhouse_cell_mem_regions(cell_desc), + sizeof(struct jailhouse_memory) * cell->num_memory_regions); + + err = jailhouse_pci_cell_setup(cell, cell_desc); + if (err) { + vfree(cell->memory_regions); + kfree(cell); + return ERR_PTR(err); + } + + err = jailhouse_sysfs_cell_create(cell); + if (err) + /* cleanup done by jailhouse_sysfs_cell_create */ + return ERR_PTR(err); + + return cell; +} + +static void cell_register(struct cell *cell) +{ + list_add_tail(&cell->entry, &cells); + jailhouse_sysfs_cell_register(cell); +} + +static struct cell *find_cell(struct jailhouse_cell_id *cell_id) +{ + struct cell *cell; + + list_for_each_entry(cell, &cells, entry) + if (cell_id->id == cell->id || + (cell_id->id == JAILHOUSE_CELL_ID_UNUSED && + strcmp(cell->name, cell_id->name) == 0)) + return cell; + return NULL; +} + +static void cell_delete(struct cell *cell) +{ + list_del(&cell->entry); + jailhouse_sysfs_cell_delete(cell); +} + +int jailhouse_cell_prepare_root(const struct jailhouse_cell_desc *cell_desc) +{ + root_cell = cell_create(cell_desc); + if (IS_ERR(root_cell)) + return PTR_ERR(root_cell); + + return 0; +} + +void jailhouse_cell_register_root(void) +{ + root_cell->id = 0; + cell_register(root_cell); +} + +void jailhouse_cell_delete_root(void) +{ + cell_delete(root_cell); + root_cell = NULL; +} + +int jailhouse_cmd_cell_create(struct jailhouse_cell_create __user *arg) +{ + struct jailhouse_cell_create cell_params; + struct jailhouse_cell_desc *config; + struct jailhouse_cell_id cell_id; + void __user *user_config; + struct cell *cell; + unsigned int cpu; + int err = 0; + + if (copy_from_user(&cell_params, arg, sizeof(cell_params))) + return -EFAULT; + + config = kmalloc(cell_params.config_size, GFP_USER | __GFP_NOWARN); + if (!config) + return -ENOMEM; + + user_config = (void __user *)(unsigned long)cell_params.config_address; + if (copy_from_user(config, user_config, cell_params.config_size)) { + err = -EFAULT; + goto kfree_config_out; + } + + if (cell_params.config_size < sizeof(*config) || + memcmp(config->signature, JAILHOUSE_CELL_DESC_SIGNATURE, + sizeof(config->signature)) != 0) { + pr_err("jailhouse: Not a cell configuration\n"); + err = -EINVAL; + goto kfree_config_out; + } + if (config->revision != JAILHOUSE_CONFIG_REVISION) { + pr_err("jailhouse: Configuration revision mismatch\n"); + err = -EINVAL; + goto kfree_config_out; + } + + config->name[JAILHOUSE_CELL_NAME_MAXLEN] = 0; + + /* CONSOLE_ACTIVE implies CONSOLE_PERMITTED for non-root cells */ + if (CELL_FLAGS_VIRTUAL_CONSOLE_ACTIVE(config->flags)) + config->flags |= JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) { + err = -EINTR; + goto kfree_config_out; + } + + if (!jailhouse_enabled) { + err = -EINVAL; + goto unlock_out; + } + + cell_id.id = JAILHOUSE_CELL_ID_UNUSED; + memcpy(cell_id.name, config->name, sizeof(cell_id.name)); + if (find_cell(&cell_id) != NULL) { + err = -EEXIST; + goto unlock_out; + } + + cell = cell_create(config); + if (IS_ERR(cell)) { + err = PTR_ERR(cell); + goto unlock_out; + } + + config->id = cell->id; + + if (!cpumask_subset(&cell->cpus_assigned, &root_cell->cpus_assigned)) { + err = -EBUSY; + goto error_cell_delete; + } + + /* Off-line each CPU assigned to the new cell and remove it from the + * root cell's set. */ + for_each_cpu(cpu, &cell->cpus_assigned) { +#ifdef CONFIG_X86 + if (cpu == 0) { + /* + * On x86, Linux only parks CPU 0 when offlining it and + * expects to be able to get it back by sending an IPI. + * This is not support by Jailhouse wich destroys the + * CPU state across non-root assignments. + */ + pr_err("Cannot assign CPU 0 to other cells\n"); + err = -EINVAL; + goto error_cpu_online; + } +#endif + if (cpu_online(cpu)) { + err = remove_cpu(cpu); + if (err) + goto error_cpu_online; + cpumask_set_cpu(cpu, &offlined_cpus); + } + cpumask_clear_cpu(cpu, &root_cell->cpus_assigned); + } + + jailhouse_pci_do_all_devices(cell, JAILHOUSE_PCI_TYPE_DEVICE, + JAILHOUSE_PCI_ACTION_CLAIM); + + err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_CREATE, __pa(config)); + if (err < 0) + goto error_cpu_online; + + cell_register(cell); + + pr_info("Created Jailhouse cell \"%s\"\n", config->name); + +unlock_out: + mutex_unlock(&jailhouse_lock); + +kfree_config_out: + kfree(config); + + return err; + +error_cpu_online: + for_each_cpu(cpu, &cell->cpus_assigned) { + if (!cpu_online(cpu) && add_cpu(cpu) == 0) + cpumask_clear_cpu(cpu, &offlined_cpus); + cpumask_set_cpu(cpu, &root_cell->cpus_assigned); + } + +error_cell_delete: + cell_delete(cell); + goto unlock_out; +} + +static int cell_management_prologue(struct jailhouse_cell_id *cell_id, + struct cell **cell_ptr) +{ + cell_id->name[JAILHOUSE_CELL_ID_NAMELEN] = 0; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) + return -EINTR; + + if (!jailhouse_enabled) { + mutex_unlock(&jailhouse_lock); + return -EINVAL; + } + + *cell_ptr = find_cell(cell_id); + if (*cell_ptr == NULL) { + mutex_unlock(&jailhouse_lock); + return -ENOENT; + } + return 0; +} + +#define MEM_REQ_FLAGS (JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_LOADABLE) + +static int load_image(struct cell *cell, + struct jailhouse_preload_image __user *uimage) +{ + struct jailhouse_preload_image image; + const struct jailhouse_memory *mem; + unsigned int regions, page_offs; + u64 image_offset, phys_start; + void *image_mem; + int err = 0; + + if (copy_from_user(&image, uimage, sizeof(image))) + return -EFAULT; + + if (image.size == 0) + return 0; + + mem = cell->memory_regions; + for (regions = cell->num_memory_regions; regions > 0; regions--) { + image_offset = image.target_address - mem->virt_start; + if (image.target_address >= mem->virt_start && + image_offset < mem->size) { + if (image.size > mem->size - image_offset || + (mem->flags & MEM_REQ_FLAGS) != MEM_REQ_FLAGS) + return -EINVAL; + break; + } + mem++; + } + if (regions == 0) + return -EINVAL; + + phys_start = (mem->phys_start + image_offset) & PAGE_MASK; + page_offs = offset_in_page(image_offset); + image_mem = jailhouse_ioremap(phys_start, 0, + PAGE_ALIGN(image.size + page_offs)); + if (!image_mem) { + pr_err("jailhouse: Unable to map cell RAM at %08llx " + "for image loading\n", + (unsigned long long)(mem->phys_start + image_offset)); + return -EBUSY; + } + + if (copy_from_user(image_mem + page_offs, + (void __user *)(unsigned long)image.source_address, + image.size)) + err = -EFAULT; + /* + * ARMv7 and ARMv8 require to clean D-cache and invalidate I-cache for + * memory containing new instructions. On x86 this is a NOP. + */ + flush_icache_range((unsigned long)(image_mem + page_offs), + (unsigned long)(image_mem + page_offs) + image.size); +#ifdef CONFIG_ARM + /* + * ARMv7 requires to flush the written code and data out of D-cache to + * allow the guest starting off with caches disabled. + */ + __cpuc_flush_dcache_area(image_mem + page_offs, image.size); +#endif + + vunmap(image_mem); + + return err; +} + +int jailhouse_cmd_cell_load(struct jailhouse_cell_load __user *arg) +{ + struct jailhouse_preload_image __user *image = arg->image; + struct jailhouse_cell_load cell_load; + struct cell *cell; + unsigned int n; + int err; + + if (copy_from_user(&cell_load, arg, sizeof(cell_load))) + return -EFAULT; + + err = cell_management_prologue(&cell_load.cell_id, &cell); + if (err) + return err; + + err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_SET_LOADABLE, cell->id); + if (err) + goto unlock_out; + + for (n = cell_load.num_preload_images; n > 0; n--, image++) { + err = load_image(cell, image); + if (err) + break; + } + +unlock_out: + mutex_unlock(&jailhouse_lock); + + return err; +} + +int jailhouse_cmd_cell_start(const char __user *arg) +{ + struct jailhouse_cell_id cell_id; + struct cell *cell; + int err; + + if (copy_from_user(&cell_id, arg, sizeof(cell_id))) + return -EFAULT; + + err = cell_management_prologue(&cell_id, &cell); + if (err) + return err; + + err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_START, cell->id); + + mutex_unlock(&jailhouse_lock); + + return err; +} + +static int cell_destroy(struct cell *cell) +{ + unsigned int cpu; + int err; + + err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_DESTROY, cell->id); + if (err) + return err; + + for_each_cpu(cpu, &cell->cpus_assigned) { + if (cpumask_test_cpu(cpu, &offlined_cpus)) { + if (add_cpu(cpu) != 0) + pr_err("Jailhouse: failed to bring CPU %d " + "back online\n", cpu); + cpumask_clear_cpu(cpu, &offlined_cpus); + } + cpumask_set_cpu(cpu, &root_cell->cpus_assigned); + } + + jailhouse_pci_do_all_devices(cell, JAILHOUSE_PCI_TYPE_DEVICE, + JAILHOUSE_PCI_ACTION_RELEASE); + + pr_info("Destroyed Jailhouse cell \"%s\"\n", cell->name); + + cell_delete(cell); + + return 0; +} + +int jailhouse_cmd_cell_destroy(const char __user *arg) +{ + struct jailhouse_cell_id cell_id; + struct cell *cell; + int err; + + if (copy_from_user(&cell_id, arg, sizeof(cell_id))) + return -EFAULT; + + err = cell_management_prologue(&cell_id, &cell); + if (err) + return err; + + err = cell_destroy(cell); + + mutex_unlock(&jailhouse_lock); + + return err; +} + +int jailhouse_cmd_cell_destroy_non_root(void) +{ + struct cell *cell, *tmp; + int err; + + list_for_each_entry_safe(cell, tmp, &cells, entry) { + if (cell == root_cell) + continue; + err = cell_destroy(cell); + if (err) { + pr_err("Jailhouse: failed to destroy cell \"%s\"\n", cell->name); + return err; + } + } + + return 0; +} diff --git a/driver/cell.h b/driver/cell.h new file mode 100644 index 0000000000000000000000000000000000000000..92afbff884ca23ef3841e7e0e19b6e5e72078f31 --- /dev/null +++ b/driver/cell.h @@ -0,0 +1,56 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_DRIVER_CELL_H +#define _JAILHOUSE_DRIVER_CELL_H + +#include +#include +#include +#include + +#include "jailhouse.h" + +#include + +struct cell { + struct kobject kobj; + struct kobject stats_kobj; + struct list_head cell_cpus; + struct list_head entry; + unsigned int id; + char name[JAILHOUSE_CELL_ID_NAMELEN+1]; + cpumask_t cpus_assigned; + u32 num_memory_regions; + struct jailhouse_memory *memory_regions; +#ifdef CONFIG_PCI + u32 num_pci_devices; + struct jailhouse_pci_device *pci_devices; +#endif /* CONFIG_PCI */ +}; + +extern struct cell *root_cell; + +void jailhouse_cell_kobj_release(struct kobject *kobj); + +int jailhouse_cell_prepare_root(const struct jailhouse_cell_desc *cell_desc); +void jailhouse_cell_register_root(void); +void jailhouse_cell_delete_root(void); + +int jailhouse_cmd_cell_create(struct jailhouse_cell_create __user *arg); +int jailhouse_cmd_cell_load(struct jailhouse_cell_load __user *arg); +int jailhouse_cmd_cell_start(const char __user *arg); +int jailhouse_cmd_cell_destroy(const char __user *arg); + +int jailhouse_cmd_cell_destroy_non_root(void); + +#endif /* !_JAILHOUSE_DRIVER_CELL_H */ diff --git a/driver/jailhouse.h b/driver/jailhouse.h new file mode 100644 index 0000000000000000000000000000000000000000..9066d31df4712c981ef5dd8245b7304a2e49bf88 --- /dev/null +++ b/driver/jailhouse.h @@ -0,0 +1,82 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_DRIVER_H +#define _JAILHOUSE_DRIVER_H + +#include +#include + +#define JAILHOUSE_CELL_ID_NAMELEN 31 + +struct jailhouse_cell_create { + __u64 config_address; + __u32 config_size; + __u32 padding; +}; + +struct jailhouse_preload_image { + __u64 source_address; + __u64 size; + __u64 target_address; + __u64 padding; +}; + +struct jailhouse_cell_id { + __s32 id; + __u32 padding; + char name[JAILHOUSE_CELL_ID_NAMELEN + 1]; +}; + +struct jailhouse_cell_load { + struct jailhouse_cell_id cell_id; + __u32 num_preload_images; + __u32 padding; + struct jailhouse_preload_image image[]; +}; + +#define JAILHOUSE_CELL_ID_UNUSED (-1) + +#define JAILHOUSE_ENABLE _IOW(0, 0, void *) +#define JAILHOUSE_DISABLE _IO(0, 1) +#define JAILHOUSE_CELL_CREATE _IOW(0, 2, struct jailhouse_cell_create) +#define JAILHOUSE_CELL_LOAD _IOW(0, 3, struct jailhouse_cell_load) +#define JAILHOUSE_CELL_START _IOW(0, 4, struct jailhouse_cell_id) +#define JAILHOUSE_CELL_DESTROY _IOW(0, 5, struct jailhouse_cell_id) + +#endif /* !_JAILHOUSE_DRIVER_H */ diff --git a/driver/main.c b/driver/main.c new file mode 100644 index 0000000000000000000000000000000000000000..64e2b9a468acfa25eabd6239cebf7a261fe96eca --- /dev/null +++ b/driver/main.c @@ -0,0 +1,987 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* For compatibility with older kernel versions */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ARM +#include +#endif +#ifdef CONFIG_X86 +#include +#include +#endif + +#include "cell.h" +#include "jailhouse.h" +#include "main.h" +#include "pci.h" +#include "sysfs.h" + +#include +#include +#include + +#ifdef CONFIG_X86_32 +#error 64-bit kernel required! +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) +#define MSR_IA32_FEAT_CTL MSR_IA32_FEATURE_CONTROL +#define FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX \ + FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX +#endif + +#if JAILHOUSE_CELL_ID_NAMELEN != JAILHOUSE_CELL_NAME_MAXLEN +# warning JAILHOUSE_CELL_ID_NAMELEN and JAILHOUSE_CELL_NAME_MAXLEN out of sync! +#endif + +#ifdef CONFIG_X86 +#define JAILHOUSE_AMD_FW_NAME "jailhouse-amd.bin" +#define JAILHOUSE_INTEL_FW_NAME "jailhouse-intel.bin" +#else +#define JAILHOUSE_FW_NAME "jailhouse.bin" +#endif + +MODULE_DESCRIPTION("Management driver for Jailhouse partitioning hypervisor"); +MODULE_LICENSE("GPL"); +#ifdef CONFIG_X86 +MODULE_FIRMWARE(JAILHOUSE_AMD_FW_NAME); +MODULE_FIRMWARE(JAILHOUSE_INTEL_FW_NAME); +#else +MODULE_FIRMWARE(JAILHOUSE_FW_NAME); +#endif +MODULE_VERSION(JAILHOUSE_VERSION); + +extern char __hyp_stub_vectors[]; + +struct console_state { + unsigned int head; + unsigned int last_console_id; +}; + +DEFINE_MUTEX(jailhouse_lock); +bool jailhouse_enabled; +void *hypervisor_mem; + +static struct device *jailhouse_dev; +static unsigned long hv_core_and_percpu_size; +static atomic_t call_done; +static int error_code; +static struct jailhouse_virt_console* volatile console_page; +static bool console_available; +static struct resource *hypervisor_mem_res; + +static typeof(ioremap_page_range) *ioremap_page_range_sym; +#ifdef CONFIG_X86 +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0) +#define lapic_timer_period lapic_timer_frequency +#define lapic_timer_period_sym lapic_timer_frequency_sym +#endif +static typeof(lapic_timer_period) *lapic_timer_period_sym; +#endif +#ifdef CONFIG_ARM +static typeof(__boot_cpu_mode) *__boot_cpu_mode_sym; +#endif +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +static typeof(__hyp_stub_vectors) *__hyp_stub_vectors_sym; +#endif + +/* last_console contains three members: + * - valid: indicates if content in the page member is present + * - id: hint for the consumer if it already consumed the content + * - page: actual content + * + * Those members are updated in following cases: + * - on disabling the hypervisor to print last messages + * - on failures when enabling the hypervisor + * + * We need this structure, as in those cases the hypervisor memory gets + * unmapped. + */ +static struct { + bool valid; + unsigned int id; + struct jailhouse_virt_console page; +} last_console; + +#ifdef CONFIG_X86 +bool jailhouse_use_vmcall; + +static void init_hypercall(void) +{ + jailhouse_use_vmcall = boot_cpu_has(X86_FEATURE_VMX); +} +#else /* !CONFIG_X86 */ +static void init_hypercall(void) +{ +} +#endif + +static void copy_console_page(struct jailhouse_virt_console *dst) +{ + unsigned int tail; + + do { + /* spin while hypervisor is writing to console */ + while (console_page->busy) + cpu_relax(); + tail = console_page->tail; + rmb(); + + /* copy console page */ + memcpy(dst, console_page, + sizeof(struct jailhouse_virt_console)); + rmb(); + } while (console_page->tail != tail || console_page->busy); +} + +static inline void update_last_console(void) +{ + if (!console_available) + return; + + copy_console_page(&last_console.page); + last_console.id++; + last_console.valid = true; +} + +static long get_max_cpus(u32 cpu_set_size, + const struct jailhouse_system __user *system_config) +{ + u8 __user *cpu_set = + (u8 __user *)jailhouse_cell_cpu_set( + (const struct jailhouse_cell_desc * __force) + &system_config->root_cell); + unsigned int pos = cpu_set_size; + long max_cpu_id; + u8 bitmap; + + while (pos-- > 0) { + if (get_user(bitmap, cpu_set + pos)) + return -EFAULT; + max_cpu_id = fls(bitmap); + if (max_cpu_id > 0) + return pos * 8 + max_cpu_id; + } + return -EINVAL; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) +#define __get_vm_area(size, flags, start, end) \ + __get_vm_area_caller(size, flags, start, end, \ + __builtin_return_address(0)) +#endif + +void *jailhouse_ioremap(phys_addr_t phys, unsigned long virt, + unsigned long size) +{ + struct vm_struct *vma; + + size = PAGE_ALIGN(size); + if (virt) + vma = __get_vm_area(size, VM_IOREMAP, virt, + virt + size + PAGE_SIZE); + else + vma = __get_vm_area(size, VM_IOREMAP, VMALLOC_START, + VMALLOC_END); + if (!vma) + return NULL; + vma->phys_addr = phys; + + if (ioremap_page_range_sym((unsigned long)vma->addr, + (unsigned long)vma->addr + size, phys, + PAGE_KERNEL_EXEC)) { + vunmap(vma->addr); + return NULL; + } + + return vma->addr; +} + +/* + * Called for each cpu by the JAILHOUSE_ENABLE ioctl. + * It jumps to the entry point set in the header, reports the result and + * signals completion to the main thread that invoked it. + */ +static void enter_hypervisor(void *info) +{ + struct jailhouse_header *header = info; + unsigned int cpu = smp_processor_id(); + int (*entry)(unsigned int); + int err; + + entry = header->entry + (unsigned long) hypervisor_mem; + + if (cpu < header->max_cpus) + /* either returns 0 or the same error code across all CPUs */ + err = entry(cpu); + else + err = -EINVAL; + + if (err) + error_code = err; + +#if defined(CONFIG_X86) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) + /* on Intel, VMXE is now on - update the shadow */ + if (boot_cpu_has(X86_FEATURE_VMX) && !err) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + cr4_set_bits_irqsoff(X86_CR4_VMXE); +#else + cr4_set_bits(X86_CR4_VMXE); +#endif + } +#endif + + atomic_inc(&call_done); +} + +static inline const char * jailhouse_get_fw_name(void) +{ +#ifdef CONFIG_X86 + if (boot_cpu_has(X86_FEATURE_SVM)) + return JAILHOUSE_AMD_FW_NAME; + if (boot_cpu_has(X86_FEATURE_VMX)) + return JAILHOUSE_INTEL_FW_NAME; + return NULL; +#else + return JAILHOUSE_FW_NAME; +#endif +} + +static int __jailhouse_console_dump_delta(struct jailhouse_virt_console + *console, + char *dst, unsigned int head, + unsigned int *miss) +{ + int ret; + unsigned int head_mod, tail_mod; + unsigned int delta, missed = 0; + + /* we might underflow here intentionally */ + delta = console->tail - head; + + /* check if we have misses */ + if (delta > sizeof(console->content)) { + missed = delta - sizeof(console->content); + head = console->tail - sizeof(console->content); + delta = sizeof(console->content); + } + + head_mod = head % sizeof(console->content); + tail_mod = console->tail % sizeof(console->content); + + if (head_mod + delta > sizeof(console->content)) { + ret = sizeof(console->content) - head_mod; + memcpy(dst, console->content + head_mod, ret); + delta -= ret; + memcpy(dst + ret, console->content, delta); + ret += delta; + } else { + ret = delta; + memcpy(dst, console->content + head_mod, delta); + } + + if (miss) + *miss = missed; + + return ret; +} + +static void jailhouse_firmware_free(void) +{ + jailhouse_sysfs_core_exit(jailhouse_dev); + if (hypervisor_mem_res) { + release_mem_region(hypervisor_mem_res->start, + resource_size(hypervisor_mem_res)); + hypervisor_mem_res = NULL; + } + vunmap(hypervisor_mem); + hypervisor_mem = NULL; +} + +int jailhouse_console_dump_delta(char *dst, unsigned int head, + unsigned int *miss) +{ + int ret; + struct jailhouse_virt_console *console; + + if (!jailhouse_enabled) + return -EAGAIN; + + if (!console_available) + return -EPERM; + + console = kmalloc(sizeof(struct jailhouse_virt_console), GFP_KERNEL); + if (console == NULL) + return -ENOMEM; + + copy_console_page(console); + if (console->tail == head) { + ret = 0; + goto console_free_out; + } + + ret = __jailhouse_console_dump_delta(console, dst, head, miss); + +console_free_out: + kfree(console); + return ret; +} + +/* See Documentation/bootstrap-interface.txt */ +static int jailhouse_cmd_enable(struct jailhouse_system __user *arg) +{ + const struct firmware *hypervisor; + struct jailhouse_system config_header; + struct jailhouse_system *config; + struct jailhouse_memory *hv_mem = &config_header.hypervisor_memory; + struct jailhouse_header *header; + unsigned long remap_addr = 0; + void __iomem *console = NULL, *clock_reg = NULL; + unsigned long config_size; + unsigned int clock_gates; + const char *fw_name; + long max_cpus; + int err; + + fw_name = jailhouse_get_fw_name(); + if (!fw_name) { + pr_err("jailhouse: Missing or unsupported HVM technology\n"); + return -ENODEV; + } + + if (copy_from_user(&config_header, arg, sizeof(config_header))) + return -EFAULT; + + if (memcmp(config_header.signature, JAILHOUSE_SYSTEM_SIGNATURE, + sizeof(config_header.signature)) != 0) { + pr_err("jailhouse: Not a system configuration\n"); + return -EINVAL; + } + if (config_header.revision != JAILHOUSE_CONFIG_REVISION) { + pr_err("jailhouse: Configuration revision mismatch\n"); + return -EINVAL; + } + + config_header.root_cell.name[JAILHOUSE_CELL_NAME_MAXLEN] = 0; + + max_cpus = get_max_cpus(config_header.root_cell.cpu_set_size, arg); + if (max_cpus < 0) + return max_cpus; + if (max_cpus > UINT_MAX) + return -EINVAL; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) + return -EINTR; + + err = -EBUSY; + if (jailhouse_enabled || !try_module_get(THIS_MODULE)) + goto error_unlock; + +#ifdef CONFIG_ARM + /* open-coded is_hyp_mode_available to use __boot_cpu_mode_sym */ + if ((*__boot_cpu_mode_sym & MODE_MASK) != HYP_MODE || + (*__boot_cpu_mode_sym) & BOOT_CPU_MODE_MISMATCH) { + pr_err("jailhouse: HYP mode not available\n"); + err = -ENODEV; + goto error_put_module; + } +#endif +#ifdef CONFIG_X86 + if (boot_cpu_has(X86_FEATURE_VMX)) { + u64 features; + + rdmsrl(MSR_IA32_FEAT_CTL, features); + if ((features & FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX) == 0) { + pr_err("jailhouse: VT-x disabled by Firmware/BIOS\n"); + err = -ENODEV; + goto error_put_module; + } + } +#endif + + /* Load hypervisor image */ + err = request_firmware(&hypervisor, fw_name, jailhouse_dev); + if (err) { + pr_err("jailhouse: Missing hypervisor image %s\n", fw_name); + goto error_put_module; + } + + header = (struct jailhouse_header *)hypervisor->data; + + err = -EINVAL; + if (memcmp(header->signature, JAILHOUSE_SIGNATURE, + sizeof(header->signature)) != 0 || + hypervisor->size >= hv_mem->size) + goto error_release_fw; + + hv_core_and_percpu_size = header->core_size + + max_cpus * header->percpu_size; + config_size = jailhouse_system_config_size(&config_header); + if (hv_core_and_percpu_size >= hv_mem->size || + config_size >= hv_mem->size - hv_core_and_percpu_size) + goto error_release_fw; + +#ifdef JAILHOUSE_BORROW_ROOT_PT + remap_addr = JAILHOUSE_BASE; +#endif + /* Unmap hypervisor_mem from a previous "enable". The mapping has to be + * redone since the root-cell config might have changed. */ + jailhouse_firmware_free(); + + hypervisor_mem_res = request_mem_region(hv_mem->phys_start, + hv_mem->size, + "Jailhouse hypervisor"); + if (!hypervisor_mem_res) { + pr_err("jailhouse: request_mem_region failed for hypervisor " + "memory.\n"); + pr_notice("jailhouse: Did you reserve the memory with " + "\"memmap=\" or \"mem=\"?\n"); + goto error_release_fw; + } + + /* Map physical memory region reserved for Jailhouse. */ + hypervisor_mem = jailhouse_ioremap(hv_mem->phys_start, remap_addr, + hv_mem->size); + if (!hypervisor_mem) { + pr_err("jailhouse: Unable to map RAM reserved for hypervisor " + "at %08lx\n", (unsigned long)hv_mem->phys_start); + goto error_release_memreg; + } + + console_page = (struct jailhouse_virt_console*) + (hypervisor_mem + header->console_page); + last_console.valid = false; + + /* Copy hypervisor's binary image at beginning of the memory region + * and clear the rest to zero. */ + memcpy(hypervisor_mem, hypervisor->data, hypervisor->size); + memset(hypervisor_mem + hypervisor->size, 0, + hv_mem->size - hypervisor->size); + + header = (struct jailhouse_header *)hypervisor_mem; + header->max_cpus = max_cpus; + +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) + header->arm_linux_hyp_vectors = virt_to_phys(*__hyp_stub_vectors_sym); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) + header->arm_linux_hyp_abi = HYP_STUB_ABI_LEGACY; +#else + header->arm_linux_hyp_abi = HYP_STUB_ABI_OPCODE; +#endif +#endif + + err = jailhouse_sysfs_core_init(jailhouse_dev, header->core_size); + if (err) + goto error_unmap; + + /* + * ARMv8 requires to clean D-cache and invalidate I-cache for memory + * containing new instructions. On x86 this is a NOP. On ARMv7 the + * firmware does its own cache maintenance, so it is an + * extraneous (but harmless) flush. + */ + flush_icache_range((unsigned long)hypervisor_mem, + (unsigned long)(hypervisor_mem + header->core_size)); + + /* Copy system configuration to its target address in hypervisor memory + * region. */ + config = (struct jailhouse_system *) + (hypervisor_mem + hv_core_and_percpu_size); + if (copy_from_user(config, arg, config_size)) { + err = -EFAULT; + goto error_unmap; + } + + if (config->debug_console.clock_reg) { + clock_reg = ioremap(config->debug_console.clock_reg, + sizeof(clock_gates)); + if (!clock_reg) { + err = -EINVAL; + pr_err("jailhouse: Unable to map clock register at " + "%08lx\n", + (unsigned long)config->debug_console.clock_reg); + goto error_unmap; + } + + clock_gates = readl(clock_reg); + if (CON_HAS_INVERTED_GATE(config->debug_console.flags)) + clock_gates &= ~(1 << config->debug_console.gate_nr); + else + clock_gates |= (1 << config->debug_console.gate_nr); + writel(clock_gates, clock_reg); + + iounmap(clock_reg); + } + +#ifdef JAILHOUSE_BORROW_ROOT_PT + if (CON_IS_MMIO(config->debug_console.flags)) { + console = ioremap(config->debug_console.address, + config->debug_console.size); + if (!console) { + err = -EINVAL; + pr_err("jailhouse: Unable to map hypervisor debug " + "console at %08lx\n", + (unsigned long)config->debug_console.address); + goto error_unmap; + } + /* The hypervisor has no notion of address spaces, so we need + * to enforce conversion. */ + header->debug_console_base = (void * __force)console; + } +#endif + + console_available = SYS_FLAGS_VIRTUAL_DEBUG_CONSOLE(config->flags); + +#ifdef CONFIG_X86 + if (config->platform_info.x86.tsc_khz == 0) + config->platform_info.x86.tsc_khz = tsc_khz; + if (config->platform_info.x86.apic_khz == 0) + config->platform_info.x86.apic_khz = + *lapic_timer_period_sym / (1000 / HZ); +#endif + + err = jailhouse_cell_prepare_root(&config->root_cell); + if (err) + goto error_unmap; + + error_code = 0; + + preempt_disable(); + + header->online_cpus = num_online_cpus(); + + /* + * Cannot use wait=true here because all CPUs have to enter the + * hypervisor to start the handover while on_each_cpu holds the calling + * CPU back. + */ + atomic_set(&call_done, 0); + on_each_cpu(enter_hypervisor, header, 0); + while (atomic_read(&call_done) != num_online_cpus()) + cpu_relax(); + + preempt_enable(); + + if (error_code) { + err = error_code; + goto error_free_cell; + } + + if (console) + iounmap(console); + + release_firmware(hypervisor); + + jailhouse_cell_register_root(); + jailhouse_pci_virtual_root_devices_add(&config_header); + + jailhouse_enabled = true; + + mutex_unlock(&jailhouse_lock); + + pr_info("The Jailhouse is opening.\n"); + + return 0; + +error_free_cell: + update_last_console(); + jailhouse_cell_delete_root(); + +error_unmap: + jailhouse_firmware_free(); + if (console) + iounmap(console); + +error_release_memreg: + /* jailhouse_firmware_free() could have been called already and + * has released hypervisor_mem_res. */ + if (hypervisor_mem_res) + release_mem_region(hypervisor_mem_res->start, + resource_size(hypervisor_mem_res)); + hypervisor_mem_res = NULL; + +error_release_fw: + release_firmware(hypervisor); + +error_put_module: + module_put(THIS_MODULE); + +error_unlock: + mutex_unlock(&jailhouse_lock); + return err; +} + +static void leave_hypervisor(void *info) +{ + void *page; + int err; + + /* Touch each hypervisor page we may need during the switch so that + * the active mm definitely contains all mappings. At least x86 does + * not support taking any faults while switching worlds. */ + for (page = hypervisor_mem; + page < hypervisor_mem + hv_core_and_percpu_size; + page += PAGE_SIZE) + readl((void __iomem *)page); + + /* either returns 0 or the same error code across all CPUs */ + err = jailhouse_call(JAILHOUSE_HC_DISABLE); + if (err) + error_code = err; + +#if defined(CONFIG_X86) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) + /* on Intel, VMXE is now off - update the shadow */ + if (boot_cpu_has(X86_FEATURE_VMX) && !err) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + cr4_clear_bits_irqsoff(X86_CR4_VMXE); +#else + cr4_clear_bits(X86_CR4_VMXE); +#endif + } +#endif + + atomic_inc(&call_done); +} + +static int jailhouse_cmd_disable(void) +{ + int err; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) + return -EINTR; + + if (!jailhouse_enabled) { + err = -EINVAL; + goto unlock_out; + } + + err = jailhouse_cmd_cell_destroy_non_root(); + if (err) + goto unlock_out; + + jailhouse_pci_virtual_root_devices_remove(); + + error_code = 0; + + preempt_disable(); + + if (num_online_cpus() != cpumask_weight(&root_cell->cpus_assigned)) { + /* + * Not all assigned CPUs are currently online. If we disable + * now, we will lose the offlined ones. + */ + + preempt_enable(); + + err = -EBUSY; + goto unlock_out; + } + +#ifdef CONFIG_ARM + /* + * This flag has been set when onlining a CPU under Jailhouse + * supervision into SVC instead of HYP mode. + */ + *__boot_cpu_mode_sym &= ~BOOT_CPU_MODE_MISMATCH; +#endif + + atomic_set(&call_done, 0); + /* See jailhouse_cmd_enable while wait=true does not work. */ + on_each_cpu(leave_hypervisor, NULL, 0); + while (atomic_read(&call_done) != num_online_cpus()) + cpu_relax(); + + preempt_enable(); + + err = error_code; + if (err) + goto unlock_out; + + update_last_console(); + + jailhouse_cell_delete_root(); + jailhouse_enabled = false; + module_put(THIS_MODULE); + + pr_info("The Jailhouse was closed.\n"); + +unlock_out: + mutex_unlock(&jailhouse_lock); + + return err; +} + +static long jailhouse_ioctl(struct file *file, unsigned int ioctl, + unsigned long arg) +{ + long err; + + switch (ioctl) { + case JAILHOUSE_ENABLE: + err = jailhouse_cmd_enable( + (struct jailhouse_system __user *)arg); + break; + case JAILHOUSE_DISABLE: + err = jailhouse_cmd_disable(); + break; + case JAILHOUSE_CELL_CREATE: + err = jailhouse_cmd_cell_create( + (struct jailhouse_cell_create __user *)arg); + break; + case JAILHOUSE_CELL_LOAD: + err = jailhouse_cmd_cell_load( + (struct jailhouse_cell_load __user *)arg); + break; + case JAILHOUSE_CELL_START: + err = jailhouse_cmd_cell_start((const char __user *)arg); + break; + case JAILHOUSE_CELL_DESTROY: + err = jailhouse_cmd_cell_destroy((const char __user *)arg); + break; + default: + err = -EINVAL; + break; + } + + return err; +} + +static int jailhouse_console_open(struct inode *inode, struct file *file) +{ + struct console_state *user; + + user = kzalloc(sizeof(struct console_state), GFP_KERNEL); + if (!user) + return -ENOMEM; + + file->private_data = user; + + return 0; +} + +static int jailhouse_console_release(struct inode *inode, struct file *file) +{ + struct console_state *user = file->private_data; + + kfree(user); + + return 0; +} + +static ssize_t jailhouse_console_read(struct file *file, char __user *out, + size_t size, loff_t *off) +{ + struct console_state *user = file->private_data; + char *content; + unsigned int miss; + int ret; + + content = kmalloc(sizeof(console_page->content), GFP_KERNEL); + if (content == NULL) + return -ENOMEM; + + /* wait for new data */ + while (1) { + if (mutex_lock_interruptible(&jailhouse_lock) != 0) { + ret = -EINTR; + goto console_free_out; + } + + if (last_console.id != user->last_console_id && + last_console.valid) { + ret = __jailhouse_console_dump_delta(&last_console.page, + content, + user->head, + &miss); + if (!ret) + user->last_console_id = + last_console.id; + } else { + ret = jailhouse_console_dump_delta(content, user->head, + &miss); + } + + mutex_unlock(&jailhouse_lock); + + if ((!ret || ret == -EAGAIN) && file->f_flags & O_NONBLOCK) + goto console_free_out; + + if (ret == -EAGAIN) + /* Reset the user head, if jailhouse is not enabled. We + * have to do this, as jailhouse might be reenabled and + * the file handle was kept open in the meanwhile */ + user->head = 0; + else if (ret < 0) + goto console_free_out; + else if (ret) + break; + + schedule_timeout_uninterruptible(HZ / 10); + if (signal_pending(current)) { + ret = -EINTR; + goto console_free_out; + } + } + + if (miss) { + /* If we missed anything, warn user. We will dump the actual + * content in the next call. */ + ret = snprintf(content, sizeof(console_page->content), + "\n", + miss); + user->head += miss; + if (size < ret) + ret = size; + } else { + if (size < ret) + ret = size; + user->head += ret; + } + + if (copy_to_user(out, content, ret)) + ret = -EFAULT; + +console_free_out: + set_current_state(TASK_RUNNING); + kfree(content); + return ret; +} + + +static const struct file_operations jailhouse_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = jailhouse_ioctl, + .compat_ioctl = jailhouse_ioctl, + .llseek = noop_llseek, + .open = jailhouse_console_open, + .release = jailhouse_console_release, + .read = jailhouse_console_read, +}; + +static struct miscdevice jailhouse_misc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "jailhouse", + .fops = &jailhouse_fops, +}; + +static int jailhouse_shutdown_notify(struct notifier_block *unused1, + unsigned long unused2, void *unused3) +{ + int err; + + err = jailhouse_cmd_disable(); + if (err && err != -EINVAL) + pr_emerg("jailhouse: ordered shutdown failed!\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block jailhouse_shutdown_nb = { + .notifier_call = jailhouse_shutdown_notify, +}; + +static int __init jailhouse_init(void) +{ + int err; + +#if defined(CONFIG_KALLSYMS_ALL) && LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0) +#define __RESOLVE_EXTERNAL_SYMBOL(symbol) \ + symbol##_sym = (void *)kallsyms_lookup_name(#symbol); \ + if (!symbol##_sym) \ + return -EINVAL +#else +#define __RESOLVE_EXTERNAL_SYMBOL(symbol) \ + symbol##_sym = &symbol +#endif +#define RESOLVE_EXTERNAL_SYMBOL(symbol...) __RESOLVE_EXTERNAL_SYMBOL(symbol) + + RESOLVE_EXTERNAL_SYMBOL(ioremap_page_range); +#ifdef CONFIG_X86 + RESOLVE_EXTERNAL_SYMBOL(lapic_timer_period); +#endif +#ifdef CONFIG_ARM + RESOLVE_EXTERNAL_SYMBOL(__boot_cpu_mode); +#endif +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) + RESOLVE_EXTERNAL_SYMBOL(__hyp_stub_vectors); +#endif + + jailhouse_dev = root_device_register("jailhouse"); + if (IS_ERR(jailhouse_dev)) + return PTR_ERR(jailhouse_dev); + + err = jailhouse_sysfs_init(jailhouse_dev); + if (err) + goto unreg_dev; + + err = misc_register(&jailhouse_misc_dev); + if (err) + goto exit_sysfs; + + err = jailhouse_pci_register(); + if (err) + goto exit_misc; + + register_reboot_notifier(&jailhouse_shutdown_nb); + + init_hypercall(); + + return 0; +exit_misc: + misc_deregister(&jailhouse_misc_dev); + +exit_sysfs: + jailhouse_sysfs_exit(jailhouse_dev); + +unreg_dev: + root_device_unregister(jailhouse_dev); + return err; +} + +static void __exit jailhouse_exit(void) +{ + unregister_reboot_notifier(&jailhouse_shutdown_nb); + misc_deregister(&jailhouse_misc_dev); + jailhouse_sysfs_exit(jailhouse_dev); + jailhouse_firmware_free(); + jailhouse_pci_unregister(); + root_device_unregister(jailhouse_dev); +} + +module_init(jailhouse_init); +module_exit(jailhouse_exit); diff --git a/driver/main.h b/driver/main.h new file mode 100644 index 0000000000000000000000000000000000000000..7c9f661c0ad2f583b9bebf7cc4ebe7720cf18aa3 --- /dev/null +++ b/driver/main.h @@ -0,0 +1,29 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_DRIVER_MAIN_H +#define _JAILHOUSE_DRIVER_MAIN_H + +#include + +#include "cell.h" + +extern struct mutex jailhouse_lock; +extern bool jailhouse_enabled; +extern void *hypervisor_mem; + +void *jailhouse_ioremap(phys_addr_t phys, unsigned long virt, + unsigned long size); +int jailhouse_console_dump_delta(char *dst, unsigned int head, + unsigned int *miss); + +#endif /* !_JAILHOUSE_DRIVER_MAIN_H */ diff --git a/driver/pci.c b/driver/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..da516479bad46301041f8ef0680130ea65dd88f1 --- /dev/null +++ b/driver/pci.c @@ -0,0 +1,526 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2015 + * + * Authors: + * Jan Kiszka + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF_OVERLAY +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) +#define of_overlay_apply(overlay, id) (*id = of_overlay_create(overlay)) +#define of_overlay_remove(id) of_overlay_destroy(*id) +#endif + +#include "pci.h" + +struct claimed_dev { + struct list_head list; + struct pci_dev *dev; +}; + +static LIST_HEAD(claimed_devs); +static DEFINE_SPINLOCK(claimed_devs_lock); + +static int jailhouse_pci_stub_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct claimed_dev *claimed_dev; + int ret = -ENODEV; + + spin_lock(&claimed_devs_lock); + list_for_each_entry(claimed_dev, &claimed_devs, list) { + if (claimed_dev->dev == dev) { + dev_info(&dev->dev, + "claimed for use in non-root cell\n"); + ret = 0; + break; + } + } + spin_unlock(&claimed_devs_lock); + return ret; +} + +/** + * When assigning PCI devices to cells we need to make sure Linux in the + * root-cell does not use them anymore. As long as devices are assigned to + * other cells the root-cell must not access the devices. + * Unfortunately we can not just use PCI hotplugging to remove/re-add + * devices at runtime. Linux will reprogram the BARs and locate ressources + * where we do not expect/allow them. + * So Jailhouse acts as a PCI dummy driver and claims the devices while + * other cells use them. When creating a cell devices will be unbound from + * their drivers and bound to jailhouse. When a cell is destroyed jailhouse + * will release its devices. When jailhouse is disabled it will release all + * assigned devices. + * @see jailhouse_pci_claim_release + * + * When releasing devices they will not be bound to any driver anymore and + * from Linuxs point of view the jailhouse dummy will still look like a + * valid driver. Assignment back to the original driver has to be done + * manually. + */ +static struct pci_driver jailhouse_pci_stub_driver = { + .name = "jailhouse-pci-stub", + .id_table = NULL, + .probe = jailhouse_pci_stub_probe, +}; + +static void jailhouse_pci_add_device(const struct jailhouse_pci_device *dev) +{ + int num; + struct pci_bus *bus; + + bus = pci_find_bus(dev->domain, PCI_BUS_NUM(dev->bdf)); + if (bus) { + num = pci_scan_slot(bus, dev->bdf & 0xff); + if (num) { + pci_lock_rescan_remove(); + pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); + pci_unlock_rescan_remove(); + } + } +} + +static void jailhouse_pci_remove_device(const struct jailhouse_pci_device *dev) +{ + struct pci_dev *l_dev; + + l_dev = pci_get_domain_bus_and_slot(dev->domain, PCI_BUS_NUM(dev->bdf), + dev->bdf & 0xff); + if (l_dev) { + pci_stop_and_remove_bus_device_locked(l_dev); + pci_dev_put(l_dev); + } +} + +static void jailhouse_pci_claim_release(const struct jailhouse_pci_device *dev, + unsigned int action) +{ + int err; + struct pci_bus *bus; + struct pci_dev *l_dev; + struct device_driver *drv; + struct claimed_dev *claimed_dev, *tmp_claimed_dev; + + bus = pci_find_bus(dev->domain, PCI_BUS_NUM(dev->bdf)); + if (!bus) + return; + l_dev = pci_get_slot(bus, dev->bdf & 0xff); + if (!l_dev) + return; + drv = l_dev->dev.driver; + + if (action == JAILHOUSE_PCI_ACTION_CLAIM) { + if (drv == &jailhouse_pci_stub_driver.driver) + return; + claimed_dev = kmalloc(sizeof(*claimed_dev), GFP_KERNEL); + if (!claimed_dev) { + dev_warn(&l_dev->dev, "failed to allocate list entry, " + "the driver might not work as expected\n"); + return; + } + claimed_dev->dev = l_dev; + spin_lock(&claimed_devs_lock); + list_add(&(claimed_dev->list), &claimed_devs); + spin_unlock(&claimed_devs_lock); + device_release_driver(&l_dev->dev); + err = pci_add_dynid(&jailhouse_pci_stub_driver, l_dev->vendor, + l_dev->device, l_dev->subsystem_vendor, + l_dev->subsystem_device, l_dev->class, + 0, 0); + if (err) + dev_warn(&l_dev->dev, "failed to add dynamic id (%d)\n", + err); + } else { + /* on "jailhouse disable" we will come here with the + * request to release all pci devices, so check the driver */ + if (drv == &jailhouse_pci_stub_driver.driver) + device_release_driver(&l_dev->dev); + list_for_each_entry_safe(claimed_dev, tmp_claimed_dev, + &claimed_devs, list) + if (claimed_dev->dev == l_dev) { + spin_lock(&claimed_devs_lock); + list_del(&(claimed_dev->list)); + spin_unlock(&claimed_devs_lock); + kfree(claimed_dev); + break; + } + } +} + +/** + * Register jailhouse as a PCI device driver so it can claim assigned devices. + * + * @return 0 on success, or error code + */ +int jailhouse_pci_register(void) +{ + return pci_register_driver(&jailhouse_pci_stub_driver); +} + +/** + * Unegister jailhouse as a PCI device driver. + */ +void jailhouse_pci_unregister(void) +{ + pci_unregister_driver(&jailhouse_pci_stub_driver); +} + +/** + * Apply the given action to all of the cells PCI devices matching the given + * type. + * @param cell the cell containing the PCI devices + * @param type PCI device type (JAILHOUSE_PCI_TYPE_*) + * @param action action (JAILHOUSE_PCI_ACTION_*) + */ +void jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type, + unsigned int action) +{ + unsigned int n; + const struct jailhouse_pci_device *dev; + + dev = cell->pci_devices; + for (n = cell->num_pci_devices; n > 0; n--) { + if (dev->type == type) { + switch(action) { + case JAILHOUSE_PCI_ACTION_ADD: + jailhouse_pci_add_device(dev); + break; + case JAILHOUSE_PCI_ACTION_DEL: + jailhouse_pci_remove_device(dev); + break; + default: + jailhouse_pci_claim_release(dev, action); + } + } + dev++; + } +} + +int jailhouse_pci_cell_setup(struct cell *cell, + const struct jailhouse_cell_desc *cell_desc) +{ + if (cell_desc->num_pci_devices == 0) + /* cell is zero-initialized, no need to set pci fields */ + return 0; + + if (cell_desc->num_pci_devices >= + ULONG_MAX / sizeof(struct jailhouse_pci_device)) + return -EINVAL; + + cell->num_pci_devices = cell_desc->num_pci_devices; + cell->pci_devices = vmalloc(sizeof(struct jailhouse_pci_device) * + cell->num_pci_devices); + if (!cell->pci_devices) + return -ENOMEM; + + memcpy(cell->pci_devices, + jailhouse_cell_pci_devices(cell_desc), + sizeof(struct jailhouse_pci_device) * cell->num_pci_devices); + + return 0; +} + +void jailhouse_pci_cell_cleanup(struct cell *cell) +{ + vfree(cell->pci_devices); +} + +#ifdef CONFIG_OF_OVERLAY +extern u8 __dtb_vpci_template_begin[], __dtb_vpci_template_end[]; + +static int overlay_id; +static bool overlay_applied; +static struct of_changeset overlay_changeset; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0) +static struct device_node *overlay; +#endif + +static void free_prop(struct property *prop) +{ + if (!prop) + return; + + kfree(prop->name); + kfree(prop->value); + kfree(prop); +} + +static struct property *alloc_prop(const char *name, int length) +{ + struct property *prop; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return NULL; + + prop->name = kstrdup(name, GFP_KERNEL); + prop->length = length; + prop->value = kzalloc(length, GFP_KERNEL); + if (!prop->name || !prop->value) { + free_prop(prop); + return NULL; + } + + return prop; +} + +static unsigned int count_ivshmem_devices(struct cell *cell) +{ + const struct jailhouse_pci_device *dev = cell->pci_devices; + unsigned int n, count = 0; + + for (n = cell->num_pci_devices; n > 0; n--, dev++) + if (dev->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + count++; + return count; +} + +static const struct of_device_id gic_of_match[] = { + { .compatible = "arm,cortex-a15-gic", }, + { .compatible = "arm,cortex-a7-gic", }, + { .compatible = "arm,gic-400", }, + { .compatible = "arm,gic-v3", }, + {}, +}; + +static bool create_vpci_of_overlay(struct jailhouse_system *config) +{ + u32 address_cells, size_cells, gic_address_cells, gic_phandle; + struct device_node *vpci_node = NULL; + struct device_node *root, *gic; + struct property *prop = NULL; + unsigned int n, cell; + u64 base_addr; + u32 *prop_val; + + root = of_find_node_by_path("/"); + if (!root) + return false; + + if (of_property_read_u32(root, "#address-cells", &address_cells) < 0 || + of_property_read_u32(root, "#size-cells", &size_cells) < 0) { + of_node_put(root); + return false; + } + + of_node_put(root); + + gic = of_find_matching_node(NULL, gic_of_match); + if (!gic) + return false; + + if (of_property_read_u32(gic, "#address-cells", &gic_address_cells) < 0) + gic_address_cells = 0; + gic_phandle = gic->phandle; + + of_node_put(gic); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) + if (of_overlay_fdt_apply(__dtb_vpci_template_begin, + __dtb_vpci_template_end - __dtb_vpci_template_begin, + &overlay_id) < 0) + return false; + +#else /* < 4.17 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) + of_fdt_unflatten_tree((const void *)__dtb_vpci_template_begin, NULL, + &overlay); +#else /* < 4.7 */ + of_fdt_unflatten_tree((const void *)__dtb_vpci_template_begin, &overlay); +#endif /* < 4.7 */ + if (!overlay) + goto out_compat; + + of_node_set_flag(overlay, OF_DETACHED); + + if (of_overlay_apply(overlay, &overlay_id) < 0) + goto out_compat; +#endif /* < 4.17 */ + + of_changeset_init(&overlay_changeset); + + vpci_node = of_find_node_by_path("/pci@0"); + if (!vpci_node) + goto out; + + /* + * Set only here to suppress warnings of dtc when compiling the + * incomplete overlay. + */ + prop = alloc_prop("device_type", 4); + if (!prop) + goto out; + strcpy(prop->value, "pci"); + + if (of_changeset_add_property(&overlay_changeset, vpci_node, prop) < 0) + goto out; + + if (config->platform_info.pci_domain != (u16)-1) { + prop = alloc_prop("linux,pci-domain", sizeof(u32)); + if (!prop) + goto out; + + prop_val = prop->value; + prop_val[0] = cpu_to_be32(config->platform_info.pci_domain); + + if (of_changeset_add_property(&overlay_changeset, vpci_node, + prop) < 0) + goto out; + } + + prop = alloc_prop("interrupt-map", + sizeof(u32) * (8 + gic_address_cells) * 4); + if (!prop) + goto out; + + prop_val = prop->value; + for (n = 0, cell = 0; n < 4; n++) { + cell += 3; /* match addr (0) */ + prop_val[cell++] = cpu_to_be32(n + 1); /* match addr */ + prop_val[cell++] = cpu_to_be32(gic_phandle); + cell += gic_address_cells; /* parent addr (0) */ + prop_val[cell++] = cpu_to_be32(GIC_SPI); + prop_val[cell++] = + cpu_to_be32(config->root_cell.vpci_irq_base + n); + prop_val[cell++] = cpu_to_be32(IRQ_TYPE_EDGE_RISING); + } + + if (of_changeset_add_property(&overlay_changeset, vpci_node, prop) < 0) + goto out; + + prop = alloc_prop("reg", sizeof(u32) * (address_cells + size_cells)); + if (!prop) + goto out; + + /* Set the MMCONFIG base address of the host controller. */ + base_addr = config->platform_info.pci_mmconfig_base; + prop_val = prop->value; + if (address_cells > 1) + *prop_val++ = cpu_to_be32(base_addr >> 32); + *prop_val++ = cpu_to_be32(base_addr); + if (size_cells > 1) + *prop_val++ = 0; + *prop_val = cpu_to_be32(0x100000); + + if (of_changeset_add_property(&overlay_changeset, vpci_node, prop) < 0) + goto out; + + prop = alloc_prop("ranges", sizeof(u32) * (5 + address_cells)); + if (!prop) + goto out; + + /* + * Locate the resource window right after MMCONFIG, which is only + * covering one bus. Reserve 2 pages per virtual shared memory device. + */ + base_addr += 0x100000; + prop_val = prop->value; + *prop_val++ = cpu_to_be32(0x02000000); + *prop_val++ = cpu_to_be32(base_addr >> 32); + *prop_val++ = cpu_to_be32(base_addr); + if (address_cells > 1) + *prop_val++ = cpu_to_be32(base_addr >> 32); + *prop_val++ = cpu_to_be32(base_addr); + *prop_val++ = 0; + *prop_val = cpu_to_be32(count_ivshmem_devices(root_cell) * + 2 * PAGE_SIZE); + + if (of_changeset_add_property(&overlay_changeset, vpci_node, prop) < 0) + goto out; + + prop = alloc_prop("status", 3); + if (!prop) + goto out; + strcpy(prop->value, "ok"); + + if (of_changeset_update_property(&overlay_changeset, vpci_node, + prop) < 0) + goto out; + prop = NULL; + + if (of_changeset_apply(&overlay_changeset) < 0) + goto out; + + overlay_applied = true; + +out: + free_prop(prop); + of_node_put(vpci_node); + if (!overlay_applied) { + struct of_changeset_entry *ce; + + list_for_each_entry(ce, &overlay_changeset.entries, node) + free_prop(ce->prop); + of_changeset_destroy(&overlay_changeset); + of_overlay_remove(&overlay_id); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0) +out_compat: + kfree(overlay); + overlay = NULL; +#endif + } + + return overlay_applied; +} + +static void destroy_vpci_of_overlay(void) +{ + if (overlay_applied) { + of_changeset_revert(&overlay_changeset); + of_changeset_destroy(&overlay_changeset); + of_overlay_remove(&overlay_id); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0) + kfree(overlay); + overlay = NULL; +#endif + overlay_applied = false; + } +} +#else /* !CONFIG_OF_OVERLAY */ +static bool create_vpci_of_overlay(struct jailhouse_system *config) +{ + pr_warn("jailhouse: CONFIG_OF_OVERLAY disabled\n"); + return false; +} + +static void destroy_vpci_of_overlay(void) +{ +} +#endif + +void jailhouse_pci_virtual_root_devices_add(struct jailhouse_system *config) +{ + if (config->platform_info.pci_is_virtual && + !create_vpci_of_overlay(config)) { + pr_warn("jailhouse: failed to add virtual host controller\n"); + return; + } + + jailhouse_pci_do_all_devices(root_cell, JAILHOUSE_PCI_TYPE_IVSHMEM, + JAILHOUSE_PCI_ACTION_ADD); +} + +void jailhouse_pci_virtual_root_devices_remove(void) +{ + jailhouse_pci_do_all_devices(root_cell, JAILHOUSE_PCI_TYPE_IVSHMEM, + JAILHOUSE_PCI_ACTION_DEL); + + destroy_vpci_of_overlay(); +} diff --git a/driver/pci.h b/driver/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..598c6c8d3bc8174a6eb4e2aa078744f9df1253f0 --- /dev/null +++ b/driver/pci.h @@ -0,0 +1,70 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2015 + * + * Authors: + * Jan Kiszka + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "cell.h" + +enum { + JAILHOUSE_PCI_ACTION_ADD, JAILHOUSE_PCI_ACTION_DEL, + JAILHOUSE_PCI_ACTION_CLAIM, JAILHOUSE_PCI_ACTION_RELEASE, +}; + +#ifdef CONFIG_PCI + +void jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type, + unsigned int action); +int jailhouse_pci_cell_setup(struct cell *cell, + const struct jailhouse_cell_desc *cell_desc); +void jailhouse_pci_cell_cleanup(struct cell *cell); +void jailhouse_pci_virtual_root_devices_add(struct jailhouse_system *config); +void jailhouse_pci_virtual_root_devices_remove(void); +int jailhouse_pci_register(void); +void jailhouse_pci_unregister(void); + +#else /* !CONFIG_PCI */ + +static inline void +jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type, + unsigned int action) +{ +} + +static inline int +jailhouse_pci_cell_setup(struct cell *cell, + const struct jailhouse_cell_desc *cell_desc) +{ + return 0; +} + +static inline void jailhouse_pci_cell_cleanup(struct cell *cell) +{ +} + +static inline void +jailhouse_pci_virtual_root_devices_add(struct jailhouse_system *config) +{ +} + +static inline void jailhouse_pci_virtual_root_devices_remove(void) +{ +} + +static inline int jailhouse_pci_register(void) +{ + return 0; +} + +static inline void jailhouse_pci_unregister(void) +{ +} + +#endif /* !CONFIG_PCI */ diff --git a/driver/sysfs.c b/driver/sysfs.c new file mode 100644 index 0000000000000000000000000000000000000000..a5a02831da553c24e3b29256b1313950c59c22a9 --- /dev/null +++ b/driver/sysfs.c @@ -0,0 +1,606 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "cell.h" +#include "jailhouse.h" +#include "main.h" +#include "sysfs.h" + +#include + +/* For compatibility with older kernel versions */ +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) +#define DEVICE_ATTR_RO(_name) \ + struct device_attribute dev_attr_##_name = __ATTR_RO(_name) +#endif /* < 3.11 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) +static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct kobj_attribute *kattr; + ssize_t ret = -EIO; + + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->show) + ret = kattr->show(kobj, kattr, buf); + return ret; +} + +static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct kobj_attribute *kattr; + ssize_t ret = -EIO; + + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->store) + ret = kattr->store(kobj, kattr, buf, count); + return ret; +} + +static const struct sysfs_ops cell_sysfs_ops = { + .show = kobj_attr_show, + .store = kobj_attr_store, +}; +#define kobj_sysfs_ops cell_sysfs_ops +#endif /* < 3.14 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) +#define COMPAT_ATTRIBUTE_GROUPS(x) /* not used */ +#define DEFAULT_GROUPS(x) .default_attrs = x##_attrs +#else +#define COMPAT_ATTRIBUTE_GROUPS(x) ATTRIBUTE_GROUPS(x) +#define DEFAULT_GROUPS(x) .default_groups = x##_groups +#endif /* < 5.2 */ +/* End of compatibility section - remove as version become obsolete */ + +static struct kobject *cells_dir; + +struct cell_cpu { + struct kobject kobj; + struct list_head entry; + unsigned int cpu; +}; + +struct jailhouse_cpu_stats_attr { + struct kobj_attribute kattr; + unsigned int code; +}; + +static ssize_t cell_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buffer) +{ + struct jailhouse_cpu_stats_attr *stats_attr = + container_of(attr, struct jailhouse_cpu_stats_attr, kattr); + unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code; + struct cell *cell = container_of(kobj, struct cell, stats_kobj); + unsigned long sum = 0; + unsigned int cpu; + int value; + + for_each_cpu(cpu, &cell->cpus_assigned) { + value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu, + code); + if (value > 0) + sum += value; + } + + return sprintf(buffer, "%lu\n", sum); +} + +static ssize_t cpu_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buffer) +{ + struct jailhouse_cpu_stats_attr *stats_attr = + container_of(attr, struct jailhouse_cpu_stats_attr, kattr); + unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code; + struct cell_cpu *cell_cpu = container_of(kobj, struct cell_cpu, kobj); + int value; + + value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cell_cpu->cpu, + code); + if (value < 0) + value = 0; + + return sprintf(buffer, "%d\n", value); +} + +#define JAILHOUSE_CPU_STATS_ATTR(_name, _code) \ + static struct jailhouse_cpu_stats_attr _name##_cell_attr = { \ + .kattr = __ATTR(_name, S_IRUGO, cell_stats_show, NULL), \ + .code = _code, \ + }; \ + static struct jailhouse_cpu_stats_attr _name##_cpu_attr = { \ + .kattr = __ATTR(_name, S_IRUGO, cpu_stats_show, NULL), \ + .code = _code, \ + } + +JAILHOUSE_CPU_STATS_ATTR(vmexits_total, JAILHOUSE_CPU_STAT_VMEXITS_TOTAL); +JAILHOUSE_CPU_STATS_ATTR(vmexits_mmio, JAILHOUSE_CPU_STAT_VMEXITS_MMIO); +JAILHOUSE_CPU_STATS_ATTR(vmexits_management, + JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT); +JAILHOUSE_CPU_STATS_ATTR(vmexits_hypercall, + JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL); +#ifdef CONFIG_X86 +JAILHOUSE_CPU_STATS_ATTR(vmexits_pio, JAILHOUSE_CPU_STAT_VMEXITS_PIO); +JAILHOUSE_CPU_STATS_ATTR(vmexits_xapic, JAILHOUSE_CPU_STAT_VMEXITS_XAPIC); +JAILHOUSE_CPU_STATS_ATTR(vmexits_cr, JAILHOUSE_CPU_STAT_VMEXITS_CR); +JAILHOUSE_CPU_STATS_ATTR(vmexits_cpuid, JAILHOUSE_CPU_STAT_VMEXITS_CPUID); +JAILHOUSE_CPU_STATS_ATTR(vmexits_xsetbv, JAILHOUSE_CPU_STAT_VMEXITS_XSETBV); +JAILHOUSE_CPU_STATS_ATTR(vmexits_exception, + JAILHOUSE_CPU_STAT_VMEXITS_EXCEPTION); +JAILHOUSE_CPU_STATS_ATTR(vmexits_msr_other, + JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER); +JAILHOUSE_CPU_STATS_ATTR(vmexits_msr_x2apic_icr, + JAILHOUSE_CPU_STAT_VMEXITS_MSR_X2APIC_ICR); +#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) +JAILHOUSE_CPU_STATS_ATTR(vmexits_maintenance, + JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE); +JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_irq, JAILHOUSE_CPU_STAT_VMEXITS_VIRQ); +JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_sgi, JAILHOUSE_CPU_STAT_VMEXITS_VSGI); +JAILHOUSE_CPU_STATS_ATTR(vmexits_psci, JAILHOUSE_CPU_STAT_VMEXITS_PSCI); +JAILHOUSE_CPU_STATS_ATTR(vmexits_smccc, JAILHOUSE_CPU_STAT_VMEXITS_SMCCC); +#ifdef CONFIG_ARM +JAILHOUSE_CPU_STATS_ATTR(vmexits_cp15, JAILHOUSE_CPU_STAT_VMEXITS_CP15); +#endif +#endif + +static struct attribute *cell_stats_attrs[] = { + &vmexits_total_cell_attr.kattr.attr, + &vmexits_mmio_cell_attr.kattr.attr, + &vmexits_management_cell_attr.kattr.attr, + &vmexits_hypercall_cell_attr.kattr.attr, +#ifdef CONFIG_X86 + &vmexits_pio_cell_attr.kattr.attr, + &vmexits_xapic_cell_attr.kattr.attr, + &vmexits_cr_cell_attr.kattr.attr, + &vmexits_cpuid_cell_attr.kattr.attr, + &vmexits_xsetbv_cell_attr.kattr.attr, + &vmexits_exception_cell_attr.kattr.attr, + &vmexits_msr_other_cell_attr.kattr.attr, + &vmexits_msr_x2apic_icr_cell_attr.kattr.attr, +#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) + &vmexits_maintenance_cell_attr.kattr.attr, + &vmexits_virt_irq_cell_attr.kattr.attr, + &vmexits_virt_sgi_cell_attr.kattr.attr, + &vmexits_psci_cell_attr.kattr.attr, + &vmexits_smccc_cell_attr.kattr.attr, +#ifdef CONFIG_ARM + &vmexits_cp15_cell_attr.kattr.attr, +#endif +#endif + NULL +}; +COMPAT_ATTRIBUTE_GROUPS(cell_stats); + +static struct kobj_type cell_stats_type = { + .sysfs_ops = &kobj_sysfs_ops, + DEFAULT_GROUPS(cell_stats), +}; + +static struct attribute *cpu_stats_attrs[] = { + &vmexits_total_cpu_attr.kattr.attr, + &vmexits_mmio_cpu_attr.kattr.attr, + &vmexits_management_cpu_attr.kattr.attr, + &vmexits_hypercall_cpu_attr.kattr.attr, +#ifdef CONFIG_X86 + &vmexits_pio_cpu_attr.kattr.attr, + &vmexits_xapic_cpu_attr.kattr.attr, + &vmexits_cr_cpu_attr.kattr.attr, + &vmexits_cpuid_cpu_attr.kattr.attr, + &vmexits_xsetbv_cpu_attr.kattr.attr, + &vmexits_exception_cpu_attr.kattr.attr, + &vmexits_msr_other_cpu_attr.kattr.attr, + &vmexits_msr_x2apic_icr_cpu_attr.kattr.attr, +#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) + &vmexits_maintenance_cpu_attr.kattr.attr, + &vmexits_virt_irq_cpu_attr.kattr.attr, + &vmexits_virt_sgi_cpu_attr.kattr.attr, + &vmexits_psci_cpu_attr.kattr.attr, + &vmexits_smccc_cpu_attr.kattr.attr, +#ifdef CONFIG_ARM + &vmexits_cp15_cpu_attr.kattr.attr, +#endif +#endif + NULL +}; +COMPAT_ATTRIBUTE_GROUPS(cpu_stats); + +static struct kobj_type cell_cpu_type = { + .sysfs_ops = &kobj_sysfs_ops, + DEFAULT_GROUPS(cpu_stats), +}; + +static int print_cpumask(char *buf, size_t size, cpumask_t *mask, bool as_list) +{ + int written; + + if (as_list) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) + written = scnprintf(buf, size, "%*pbl\n", + cpumask_pr_args(mask)); + else + written = scnprintf(buf, size, "%*pb\n", + cpumask_pr_args(mask)); +#else + written = cpulist_scnprintf(buf, size, mask); + else + written = cpumask_scnprintf(buf, size, mask); + written += scnprintf(buf + written, size - written, "\n"); +#endif + + return written; +} + +static int print_failed_cpus(char *buf, size_t size, const struct cell *cell, + bool as_list) +{ + cpumask_var_t cpus_failed; + unsigned int cpu; + int written; + + if (!zalloc_cpumask_var(&cpus_failed, GFP_KERNEL)) + return -ENOMEM; + + for_each_cpu(cpu, &cell->cpus_assigned) + if (jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu, + JAILHOUSE_CPU_INFO_STATE) == + JAILHOUSE_CPU_FAILED) + cpumask_set_cpu(cpu, cpus_failed); + + written = print_cpumask(buf, size, cpus_failed, as_list); + + free_cpumask_var(cpus_failed); + + return written; +} + +static ssize_t name_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buffer) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + return sprintf(buffer, "%s\n", cell->name); +} + +static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buffer) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + switch (jailhouse_call_arg1(JAILHOUSE_HC_CELL_GET_STATE, cell->id)) { + case JAILHOUSE_CELL_RUNNING: + return sprintf(buffer, "running\n"); + case JAILHOUSE_CELL_RUNNING_LOCKED: + return sprintf(buffer, "running/locked\n"); + case JAILHOUSE_CELL_SHUT_DOWN: + return sprintf(buffer, "shut down\n"); + case JAILHOUSE_CELL_FAILED: + return sprintf(buffer, "failed\n"); + case JAILHOUSE_CELL_FAILED_COMM_REV: + return sprintf(buffer, "Comm ABI mismatch\n"); + default: + return sprintf(buffer, "invalid\n"); + } +} + +static ssize_t cpus_assigned_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + return print_cpumask(buf, PAGE_SIZE, &cell->cpus_assigned, false); +} + +static ssize_t cpus_assigned_list_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + return print_cpumask(buf, PAGE_SIZE, &cell->cpus_assigned, true); +} + +static ssize_t cpus_failed_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + return print_failed_cpus(buf, PAGE_SIZE, cell, false); +} + +static ssize_t cpus_failed_list_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct cell *cell = container_of(kobj, struct cell, kobj); + + return print_failed_cpus(buf, PAGE_SIZE, cell, true); +} + +static struct kobj_attribute cell_name_attr = __ATTR_RO(name); +static struct kobj_attribute cell_state_attr = __ATTR_RO(state); +static struct kobj_attribute cell_cpus_assigned_attr = + __ATTR_RO(cpus_assigned); +static struct kobj_attribute cell_cpus_assigned_list_attr = + __ATTR_RO(cpus_assigned_list); +static struct kobj_attribute cell_cpus_failed_attr = __ATTR_RO(cpus_failed); +static struct kobj_attribute cell_cpus_failed_list_attr = + __ATTR_RO(cpus_failed_list); + +static struct attribute *cell_attrs[] = { + &cell_name_attr.attr, + &cell_state_attr.attr, + &cell_cpus_assigned_attr.attr, + &cell_cpus_assigned_list_attr.attr, + &cell_cpus_failed_attr.attr, + &cell_cpus_failed_list_attr.attr, + NULL, +}; +COMPAT_ATTRIBUTE_GROUPS(cell); + +static struct kobj_type cell_type = { + .release = jailhouse_cell_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, + DEFAULT_GROUPS(cell), +}; + +static struct cell_cpu *find_cell_cpu(struct cell *cell, unsigned int cpu) +{ + struct cell_cpu *cell_cpu; + + list_for_each_entry(cell_cpu, &cell->cell_cpus, entry) + if (cell_cpu->cpu == cpu) + return cell_cpu; + + return NULL; +} + +int jailhouse_sysfs_cell_create(struct cell *cell) +{ + struct cell_cpu *cell_cpu; + unsigned int cpu; + int err; + + err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%d", + cell->id); + if (err) { + jailhouse_cell_kobj_release(&cell->kobj); + return err; + } + + err = kobject_init_and_add(&cell->stats_kobj, &cell_stats_type, + &cell->kobj, "%s", "statistics"); + if (err) { + jailhouse_cell_kobj_release(&cell->stats_kobj); + kobject_put(&cell->kobj); + return err; + } + + INIT_LIST_HEAD(&cell->cell_cpus); + + for_each_cpu(cpu, &cell->cpus_assigned) { + if (root_cell == NULL) { + cell_cpu = kzalloc(sizeof(struct cell_cpu), GFP_KERNEL); + if (cell_cpu == NULL) { + jailhouse_sysfs_cell_delete(cell); + return -ENOMEM; + } + + cell_cpu->cpu = cpu; + + err = kobject_init_and_add(&cell_cpu->kobj, + &cell_cpu_type, + &cell->stats_kobj, + "cpu%u", cpu); + if (err) { + jailhouse_cell_kobj_release(&cell_cpu->kobj); + kfree(cell_cpu); + jailhouse_sysfs_cell_delete(cell); + return err; + } + list_add_tail(&cell_cpu->entry, &cell->cell_cpus); + } else { + cell_cpu = find_cell_cpu(root_cell, cpu); + if (cell_cpu == NULL) + continue; + + err = kobject_move(&cell_cpu->kobj, &cell->stats_kobj); + if (WARN_ON(err)) + continue; + + list_del(&cell_cpu->entry); + list_add_tail(&cell_cpu->entry, &cell->cell_cpus); + } + } + + return 0; +} + +void jailhouse_sysfs_cell_register(struct cell *cell) +{ + kobject_uevent(&cell->kobj, KOBJ_ADD); +} + +void jailhouse_sysfs_cell_delete(struct cell *cell) +{ + struct cell_cpu *cell_cpu, *tmp; + int err; + + if (cell == root_cell) { + list_for_each_entry_safe(cell_cpu, tmp, &cell->cell_cpus, + entry) { + list_del(&cell_cpu->entry); + kobject_put(&cell_cpu->kobj); + kfree(cell_cpu); + } + } else { + list_for_each_entry_safe(cell_cpu, tmp, &cell->cell_cpus, + entry) { + err = kobject_move(&cell_cpu->kobj, + &root_cell->stats_kobj); + if (WARN_ON(err)) + continue; + + list_del(&cell_cpu->entry); + list_add_tail(&cell_cpu->entry, &root_cell->cell_cpus); + } + } + kobject_put(&cell->stats_kobj); + kobject_put(&cell->kobj); +} + +static ssize_t console_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + ssize_t ret; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) + return -EINTR; + + ret = jailhouse_console_dump_delta(buffer, 0, NULL); + /* don't return error if jailhouse is not enabled */ + if (ret == -EAGAIN) + ret = 0; + + mutex_unlock(&jailhouse_lock); + + return ret; +} + +static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + return sprintf(buffer, "%d\n", jailhouse_enabled); +} + +static ssize_t info_show(struct device *dev, char *buffer, unsigned int type) +{ + ssize_t result; + long val = 0; + + if (mutex_lock_interruptible(&jailhouse_lock) != 0) + return -EINTR; + + if (jailhouse_enabled) + val = jailhouse_call_arg1(JAILHOUSE_HC_HYPERVISOR_GET_INFO, + type); + if (val >= 0) + result = sprintf(buffer, "%ld\n", val); + else + result = val; + + mutex_unlock(&jailhouse_lock); + return result; +} + +static ssize_t mem_pool_size_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_SIZE); +} + +static ssize_t mem_pool_used_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_USED); +} + +static ssize_t remap_pool_size_show(struct device *dev, + struct device_attribute *attr, + char *buffer) +{ + return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_SIZE); +} + +static ssize_t remap_pool_used_show(struct device *dev, + struct device_attribute *attr, + char *buffer) +{ + return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_USED); +} + +static ssize_t core_show(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, + size_t count) +{ + return memory_read_from_buffer(buf, count, &off, hypervisor_mem, + attr->size); +} + +static DEVICE_ATTR_RO(console); +static DEVICE_ATTR_RO(enabled); +static DEVICE_ATTR_RO(mem_pool_size); +static DEVICE_ATTR_RO(mem_pool_used); +static DEVICE_ATTR_RO(remap_pool_size); +static DEVICE_ATTR_RO(remap_pool_used); + +static struct attribute *jailhouse_sysfs_entries[] = { + &dev_attr_console.attr, + &dev_attr_enabled.attr, + &dev_attr_mem_pool_size.attr, + &dev_attr_mem_pool_used.attr, + &dev_attr_remap_pool_size.attr, + &dev_attr_remap_pool_used.attr, + NULL +}; + +static struct attribute_group jailhouse_attribute_group = { + .name = NULL, + .attrs = jailhouse_sysfs_entries, +}; + +static struct bin_attribute bin_attr_core = { + .attr.name = "core", + .attr.mode = S_IRUSR, + .read = core_show, +}; + +int jailhouse_sysfs_core_init(struct device *dev, size_t hypervisor_size) +{ + bin_attr_core.size = hypervisor_size; + return sysfs_create_bin_file(&dev->kobj, &bin_attr_core); +} + +void jailhouse_sysfs_core_exit(struct device *dev) +{ + sysfs_remove_bin_file(&dev->kobj, &bin_attr_core); +} + +int jailhouse_sysfs_init(struct device *dev) +{ + int err; + + err = sysfs_create_group(&dev->kobj, &jailhouse_attribute_group); + if (err) + return err; + + cells_dir = kobject_create_and_add("cells", &dev->kobj); + if (!cells_dir) { + sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group); + return -ENOMEM; + } + + return 0; +} + +void jailhouse_sysfs_exit(struct device *dev) +{ + kobject_put(cells_dir); + sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group); +} diff --git a/driver/sysfs.h b/driver/sysfs.h new file mode 100644 index 0000000000000000000000000000000000000000..b90483cb355ef0b60fcb8883b99d57b979ea6c78 --- /dev/null +++ b/driver/sysfs.h @@ -0,0 +1,27 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_DRIVER_SYSFS_H +#define _JAILHOUSE_DRIVER_SYSFS_H + +#include + +int jailhouse_sysfs_cell_create(struct cell *cell); +void jailhouse_sysfs_cell_register(struct cell *cell); +void jailhouse_sysfs_cell_delete(struct cell *cell); + +int jailhouse_sysfs_core_init(struct device *dev, size_t hypervisor_size); +void jailhouse_sysfs_core_exit(struct device *dev); +int jailhouse_sysfs_init(struct device *dev); +void jailhouse_sysfs_exit(struct device *dev); + +#endif /* !_JAILHOUSE_DRIVER_SYSFS_H */ diff --git a/driver/vpci_template.dts b/driver/vpci_template.dts new file mode 100644 index 0000000000000000000000000000000000000000..f6d25c59b49882d9f0d0c5007c43b64c0d34049b --- /dev/null +++ b/driver/vpci_template.dts @@ -0,0 +1,27 @@ +/dts-v1/; +/ { + fragment { + target-path = "/"; + __overlay__ { + pci@0 { + compatible = "pci-host-ecam-generic"; + /* + * added dynamically: + * - device_type = "pci" + * - linux,pci-domain = <...> + * - reg = <...> + * - ranges = <...> + * - interrupt-map = <...> + */ + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + dma-coherent; + /* set to "ok" during dynamic update */ + status = "disabled"; + }; + }; + }; +}; diff --git a/hypervisor/Makefile b/hypervisor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bb761b8f7746fe20a142cf5a08772bb137d69075 --- /dev/null +++ b/hypervisor/Makefile @@ -0,0 +1,134 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2017 +# Copyright (c) Valentine Sinitsyn, 2014 +# +# Authors: +# Jan Kiszka +# Valentine Sinitsyn +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# asm-defines.h generation code derived from linux/Kbuild: +# +# Copyright (c) Linux kernel developers, 2014 +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +LINUXINCLUDE := -I$(src)/arch/$(SRCARCH)/include \ + -I$(src)/arch/$(SRCARCH)/include/generated \ + -I$(src)/include \ + -I$(src)/../include/arch/$(SRCARCH) \ + -I$(src)/../include +KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE +KBUILD_CFLAGS := -g -Os -Werror -Wall -Wextra -Wno-unused-parameter \ + -Wstrict-prototypes -Wtype-limits \ + -Wmissing-declarations -Wmissing-prototypes \ + -Wnested-externs -Wshadow -Wredundant-decls \ + -Wundef -Wdeprecated \ + -fno-strict-aliasing -fno-pic -fno-common \ + -fno-stack-protector -fno-builtin-ffsl -ffreestanding \ + -D__LINUX_COMPILER_TYPES_H + +include $(src)/arch/$(SRCARCH)/Makefile + +ifneq ($(wildcard $(INC_CONFIG_H)),) +KBUILD_CFLAGS += -include $(INC_CONFIG_H) +endif + +CORE_OBJECTS = setup.o printk.o paging.o control.o lib.o mmio.o pci.o ivshmem.o +CORE_OBJECTS += uart.o uart-8250.o + +ifdef CONFIG_JAILHOUSE_GCOV +CORE_OBJECTS += gcov.o +endif +ccflags-$(CONFIG_JAILHOUSE_GCOV) += -fprofile-arcs -ftest-coverage +clean-files += *.gcda arch/*/.*.gcda + +CLEAN_DIRS := arch/$(SRCARCH)/include/generated + +ifeq ($(shell test $(VERSION) -ge 5 && test $(PATCHLEVEL) -ge 4 && echo 1),1) +clean-files += $(CLEAN_DIRS) +else +clean-dirs += $(CLEAN_DIRS) +endif + +define sed-y + "/^=>/{s:=>#\(.*\):/* \1 */:; \ + s:^=>\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:^=>\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:=>::; p;}" +endef + +quiet_cmd_defines = GEN $@ +define cmd_defines + (set -e; \ + echo "#ifndef _GENERATED_ASM_DEFINES_H"; \ + echo "#define _GENERATED_ASM_DEFINES_H"; \ + echo "/*"; \ + echo " * This file is autogenerated. If you need to change it,"; \ + echo " * edit arch/$(SRCARCH)/asm-defines.c instead."; \ + echo " *"; \ + echo " * ALL MANUAL CHANGES TO THIS FILE WILL BE LOST!"; \ + echo " */"; \ + echo ""; \ + sed -ne $(sed-y) $<; \ + echo ""; \ + echo "#endif" ) > $@ +endef + +ASM_DEFINES_H := arch/$(SRCARCH)/include/generated/asm/asm-defines.h + +targets := $(ASM_DEFINES_H) arch/$(SRCARCH)/asm-defines.s + +$(obj)/arch/$(SRCARCH)/asm-defines.s: $(src)/arch/$(SRCARCH)/asm-defines.c FORCE + $(call if_changed_dep,cc_s_c) + +$(obj)/$(ASM_DEFINES_H): $(obj)/arch/$(SRCARCH)/asm-defines.s + $(Q)mkdir -p $(dir $@) + $(call cmd,defines) + +# Do not generate files by creating dependencies if we are cleaning up +ifeq ($(filter %/Makefile.clean,$(MAKEFILE_LIST)),) +$(obj)/arch/$(SRCARCH): $(obj)/$(ASM_DEFINES_H) +endif + +always-y := + +subdir-y := arch/$(SRCARCH) + +define BUILD_JAILHOUSE_template +always-y += jailhouse$(1).bin + +$$(obj)/arch/$$(SRCARCH)/lib$(1).a: $$(obj)/arch/$$(SRCARCH) + @true + +hypervisor$(1)-y := arch/$$(SRCARCH)/lib$(1).a $$(CORE_OBJECTS) hypervisor.lds +targets += $$(hypervisor$(1)-y) + +HYPERVISOR$(1)_OBJS = $$(addprefix $$(obj)/,$$(hypervisor$(1)-y)) + +LDFLAGS_hypervisor$(1).o := --whole-archive -T + +targets += hypervisor$(1).o +$$(obj)/hypervisor$(1).o: $$(src)/hypervisor.lds $$(HYPERVISOR$(1)_OBJS) FORCE + $$(call if_changed,ld) + +OBJCOPYFLAGS_jailhouse$(1).bin := -O binary -R .eh_frame + +targets += jailhouse$(1).bin +$$(obj)/jailhouse$(1).bin: $$(obj)/hypervisor$(1).o FORCE + $$(call if_changed,objcopy) +endef + +ifneq ($(BUILD_VARIANTS),) +$(foreach variant,$(BUILD_VARIANTS),\ + $(eval $(call BUILD_JAILHOUSE_template,-$(variant)))) +else +$(eval $(call BUILD_JAILHOUSE_template,)) +endif diff --git a/hypervisor/arch/arm-common/Kbuild b/hypervisor/arch/arm-common/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..885eecd49585cfd01c639fbf59a9266735894cd6 --- /dev/null +++ b/hypervisor/arch/arm-common/Kbuild @@ -0,0 +1,24 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2017 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +ccflags-$(CONFIG_JAILHOUSE_GCOV) += -fprofile-arcs -ftest-coverage + +objs-y += dbg-write.o lib.o psci.o control.o paging.o mmu_cell.o setup.o +objs-y += irqchip.o pci.o ivshmem.o uart-pl011.o uart-xuartps.o uart-mvebu.o +objs-y += uart-hscif.o uart-scifa.o uart-imx.o uart-imx-lpuart.o uart-scif.o +objs-y += gic-v2.o gic-v3.o smccc.o + +common-objs-y = $(addprefix ../arm-common/,$(objs-y)) diff --git a/hypervisor/arch/arm-common/control.c b/hypervisor/arch/arm-common/control.c new file mode 100644 index 0000000000000000000000000000000000000000..9fc42761bebc1b26e4d60f8799e56e703a018f0f --- /dev/null +++ b/hypervisor/arch/arm-common/control.c @@ -0,0 +1,232 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +static void enter_cpu_off(struct public_per_cpu *cpu_public) +{ + cpu_public->park = false; + cpu_public->wait_for_poweron = true; +} + +void arm_cpu_park(void) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + + spin_lock(&cpu_public->control_lock); + enter_cpu_off(cpu_public); + spin_unlock(&cpu_public->control_lock); + + arm_cpu_reset(0, + !!(this_cell()->config->flags & JAILHOUSE_CELL_AARCH32)); + + arm_paging_vcpu_init(&parking_pt); +} + +void arch_send_event(struct public_per_cpu *target_data) +{ + if (sdei_available) + smc_arg2(SDEI_EVENT_SIGNAL, 0, target_data->mpidr); + else + irqchip_send_sgi(target_data->cpu_id, SGI_EVENT); +} + +void arch_reset_cpu(unsigned int cpu_id) +{ + public_per_cpu(cpu_id)->reset = true; + + resume_cpu(cpu_id); +} + +void arch_park_cpu(unsigned int cpu_id) +{ + public_per_cpu(cpu_id)->park = true; + + resume_cpu(cpu_id); +} + +static void check_events(struct public_per_cpu *cpu_public) +{ + bool reset = false; + + spin_lock(&cpu_public->control_lock); + + while (cpu_public->suspend_cpu) { + cpu_public->cpu_suspended = true; + + spin_unlock(&cpu_public->control_lock); + + while (cpu_public->suspend_cpu) + cpu_relax(); + + spin_lock(&cpu_public->control_lock); + } + + cpu_public->cpu_suspended = false; + + if (cpu_public->park) { + enter_cpu_off(cpu_public); + } else if (cpu_public->reset) { + cpu_public->reset = false; + if (cpu_public->cpu_on_entry != PSCI_INVALID_ADDRESS) { + cpu_public->wait_for_poweron = false; + reset = true; + } else { + enter_cpu_off(cpu_public); + } + } + + if (cpu_public->flush_vcpu_caches) { + cpu_public->flush_vcpu_caches = false; + arm_paging_vcpu_flush_tlbs(); + } + + spin_unlock(&cpu_public->control_lock); + + /* + * wait_for_poweron is only modified on this CPU, so checking outside of + * control_lock is fine. + */ + if (cpu_public->wait_for_poweron) + arm_cpu_park(); + else if (reset) + arm_cpu_reset(cpu_public->cpu_on_entry, + !!(this_cell()->config->flags & + JAILHOUSE_CELL_AARCH32)); +} + +void arch_handle_sgi(u32 irqn, unsigned int count_event) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + + switch (irqn) { + case SGI_INJECT: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_VSGI] += + count_event; + irqchip_inject_pending(); + break; + case SGI_EVENT: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT] += + count_event; + check_events(cpu_public); + break; + default: + printk("WARN: unknown SGI received %d\n", irqn); + } +} + +/* + * Handle the maintenance interrupt, the rest is injected into the cell. + * Return true when the IRQ has been handled by the hyp. + */ +bool arch_handle_phys_irq(u32 irqn, unsigned int count_event) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + + if (irqn == system_config->platform_info.arm.maintenance_irq) { + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE] += + count_event; + irqchip_inject_pending(); + + return true; + } + + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_VIRQ] += count_event; + irqchip_set_pending(cpu_public, irqn); + + return false; +} + +int arch_cell_create(struct cell *cell) +{ + return arm_paging_cell_init(cell); +} + +void arch_cell_reset(struct cell *cell) +{ + unsigned int first = first_cpu(cell->cpu_set); + unsigned int cpu; + struct jailhouse_comm_region *comm_region = + &cell->comm_page.comm_region; + + /* Place platform specific information inside comm_region */ + comm_region->gic_version = system_config->platform_info.arm.gic_version; + comm_region->gicd_base = system_config->platform_info.arm.gicd_base; + comm_region->gicc_base = system_config->platform_info.arm.gicc_base; + comm_region->gicr_base = system_config->platform_info.arm.gicr_base; + comm_region->vpci_irq_base = cell->config->vpci_irq_base; + + /* + * All CPUs but the first are initially suspended. The first CPU + * starts at cpu_reset_address, defined in the cell configuration. + */ + public_per_cpu(first)->cpu_on_entry = cell->config->cpu_reset_address; + for_each_cpu_except(cpu, cell->cpu_set, first) + public_per_cpu(cpu)->cpu_on_entry = PSCI_INVALID_ADDRESS; + + arm_cell_dcaches_flush(cell, DCACHE_INVALIDATE); + + irqchip_cell_reset(cell); +} + +void arch_cell_destroy(struct cell *cell) +{ + unsigned int cpu; + + arm_cell_dcaches_flush(cell, DCACHE_INVALIDATE); + + /* All CPUs are handed back to the root cell in suspended mode. */ + for_each_cpu(cpu, cell->cpu_set) + public_per_cpu(cpu)->cpu_on_entry = PSCI_INVALID_ADDRESS; + + arm_paging_cell_destroy(cell); +} + +/* Note: only supports synchronous flushing as triggered by config_commit! */ +void arch_flush_cell_vcpu_caches(struct cell *cell) +{ + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + if (cpu == this_cpu_id()) + arm_paging_vcpu_flush_tlbs(); + else + public_per_cpu(cpu)->flush_vcpu_caches = true; +} + +void arch_config_commit(struct cell *cell_added_removed) +{ + irqchip_config_commit(cell_added_removed); + iommu_config_commit(cell_added_removed); +} + +void __attribute__((noreturn)) arch_panic_stop(void) +{ + asm volatile ("1: wfi; b 1b"); + __builtin_unreachable(); +} + +#ifndef CONFIG_CRASH_CELL_ON_PANIC +void arch_panic_park(void) __attribute__((alias("arm_cpu_park"))); +#endif + +void arch_prepare_shutdown(void) +{ +} diff --git a/hypervisor/arch/arm-common/dbg-write.c b/hypervisor/arch/arm-common/dbg-write.c new file mode 100644 index 0000000000000000000000000000000000000000..0a758b09030610e8ffee0fb9bab5fbffcbe239b4 --- /dev/null +++ b/hypervisor/arch/arm-common/dbg-write.c @@ -0,0 +1,52 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) OTH Regensburg, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +void arch_dbg_write_init(void) +{ + unsigned char con_type = system_config->debug_console.type; + + if (!CON_IS_MMIO(system_config->debug_console.flags)) + return; + + if (con_type == JAILHOUSE_CON_TYPE_PL011) + uart = &uart_pl011_ops; + else if (con_type == JAILHOUSE_CON_TYPE_8250) + uart = &uart_8250_ops; + else if (con_type == JAILHOUSE_CON_TYPE_XUARTPS) + uart = &uart_xuartps_ops; + else if (con_type == JAILHOUSE_CON_TYPE_MVEBU) + uart = &uart_mvebu_ops; + else if (con_type == JAILHOUSE_CON_TYPE_HSCIF) + uart = &uart_hscif_ops; + else if (con_type == JAILHOUSE_CON_TYPE_SCIF) + uart = &uart_scif_ops; + else if (con_type == JAILHOUSE_CON_TYPE_SCIFA) + uart = &uart_scifa_ops; + else if (con_type == JAILHOUSE_CON_TYPE_IMX) + uart = &uart_imx_ops; + else if (con_type == JAILHOUSE_CON_TYPE_IMX_LPUART) + uart = &uart_imx_lpuart_ops; + + if (uart) { + uart->debug_console = &system_config->debug_console; + uart->virt_base = hypervisor_header.debug_console_base; + uart->init(uart); + arch_dbg_write = uart_write; + } +} diff --git a/hypervisor/arch/arm-common/gic-v2.c b/hypervisor/arch/arm-common/gic-v2.c new file mode 100644 index 0000000000000000000000000000000000000000..8a9f6201602a37327da7d384d992f3ff2fd6bb8d --- /dev/null +++ b/hypervisor/arch/arm-common/gic-v2.c @@ -0,0 +1,540 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +/* The GICv2 interface numbering does not necessarily match the logical map */ +static u8 gicv2_target_cpu_map[8]; +static unsigned int gic_num_lr; + +static void *gicc_base; +static void *gich_base; + +static u32 gicv2_read_lr(unsigned int n) +{ + return mmio_read32(gich_base + GICH_LR_BASE + n * 4); +} + +static void gicv2_write_lr(unsigned int n, u32 value) +{ + mmio_write32(gich_base + GICH_LR_BASE + n * 4, value); +} + +/* Check that the targeted interface belongs to the cell */ +static bool gicv2_targets_in_cell(struct cell *cell, u8 targets) +{ + unsigned int cpu; + + for (cpu = 0; cpu < ARRAY_SIZE(gicv2_target_cpu_map); cpu++) + if (targets & gicv2_target_cpu_map[cpu] && + public_per_cpu(cpu)->cell != cell) + return false; + + return true; +} + +static int gicv2_init(void) +{ + /* Probe the GICD version */ + if (GICD_PIDR2_ARCH(mmio_read32(gicd_base + GICDv2_PIDR2)) != 2) + return trace_error(-ENODEV); + + gicc_base = paging_map_device( + system_config->platform_info.arm.gicc_base, GICC_SIZE); + if (!gicc_base) + return -ENOMEM; + + gich_base = paging_map_device( + system_config->platform_info.arm.gich_base, GICH_SIZE); + if (!gich_base) + return -ENOMEM; + + return 0; +} + +static void gicv2_clear_pending_irqs(void) +{ + unsigned int n; + + /* Clear list registers. */ + for (n = 0; n < gic_num_lr; n++) + gicv2_write_lr(n, 0); + + /* Clear active priority bits. */ + mmio_write32(gich_base + GICH_APR, 0); +} + +static void gicv2_cpu_reset(struct per_cpu *cpu_data) +{ + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + + gicv2_clear_pending_irqs(); + + /* Ensure all IPIs and the maintenance PPI are enabled */ + mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff | (1 << mnt_irq)); + + /* Disable PPIs, except for the maintenance interrupt. */ + mmio_write32(gicd_base + GICD_ICENABLER, 0xffff0000 & ~(1 << mnt_irq)); + + /* Deactivate all active PPIs */ + mmio_write32(gicd_base + GICD_ICACTIVER, 0xffff0000); + + mmio_write32(gich_base + GICH_VMCR, 0); +} + +static int gicv2_cpu_init(struct per_cpu *cpu_data) +{ + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + u32 vtr, vmcr; + u32 cell_gicc_ctlr, cell_gicc_pmr; + u32 gicd_isacter; + unsigned int n; + + /* + * Get the CPU interface ID for this cpu. It can be discovered by + * reading the banked value of the PPI and IPI TARGET registers + * Patch 2bb3135 in Linux explains why the probe may need to scans the + * first 8 registers: some early implementation returned 0 for the first + * ITARGETSR registers. + * Since those didn't have virtualization extensions, we can safely + * ignore that case. + */ + if (cpu_data->public.cpu_id >= ARRAY_SIZE(gicv2_target_cpu_map)) + return trace_error(-EINVAL); + + gicv2_target_cpu_map[cpu_data->public.cpu_id] = + mmio_read32(gicd_base + GICD_ITARGETSR); + + if (gicv2_target_cpu_map[cpu_data->public.cpu_id] == 0) + return trace_error(-ENODEV); + + if (sdei_available) + return 0; + + /* Ensure all IPIs and the maintenance PPI are enabled. */ + mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff | (1 << mnt_irq)); + + cell_gicc_ctlr = mmio_read32(gicc_base + GICC_CTLR); + cell_gicc_pmr = mmio_read32(gicc_base + GICC_PMR); + + mmio_write32(gicc_base + GICC_CTLR, + GICC_CTLR_GRPEN1 | GICC_CTLR_EOImode); + mmio_write32(gicc_base + GICC_PMR, GICC_PMR_DEFAULT); + + vtr = mmio_read32(gich_base + GICH_VTR); + gic_num_lr = (vtr & 0x3f) + 1; + + /* VMCR only contains 5 bits of priority */ + vmcr = (cell_gicc_pmr >> GICV_PMR_SHIFT) << GICH_VMCR_PMR_SHIFT; + /* + * All virtual interrupts are group 0 in this driver since the GICV + * layout seen by the guest corresponds to GICC without security + * extensions: + * - A read from GICV_IAR doesn't acknowledge group 1 interrupts + * (GICV_AIAR does it, but the guest never attempts to accesses it) + * - A write to GICV_CTLR.GRP0EN corresponds to the GICC_CTLR.GRP1EN bit + * Since the guest's driver thinks that it is accessing a GIC with + * security extensions, a write to GPR1EN will enable group 0 + * interrups. + * - Group 0 interrupts are presented as virtual IRQs (FIQEn = 0) + */ + if (cell_gicc_ctlr & GICC_CTLR_GRPEN1) + vmcr |= GICH_VMCR_EN0; + if (cell_gicc_ctlr & GICC_CTLR_EOImode) + vmcr |= GICH_VMCR_EOImode; + + mmio_write32(gich_base + GICH_VMCR, vmcr); + mmio_write32(gich_base + GICH_HCR, GICH_HCR_EN); + + /* + * Clear pending virtual IRQs in case anything is left from previous + * use. Physically pending IRQs will be forwarded to Linux once we + * enable interrupts for the hypervisor, except for SGIs, see below. + */ + gicv2_clear_pending_irqs(); + + cpu_data->public.gicc_initialized = true; + + /* Deactivate all active SGIs */ + gicd_isacter = mmio_read32(gicd_base + GICD_ISACTIVER); + mmio_write32(gicd_base + GICD_ICACTIVER, gicd_isacter & 0xffff); + + /* + * Forward any pending physical SGIs to the virtual queue. + * We will convert them into self-inject SGIs, ignoring the original + * source. But Linux doesn't care about that anyway. + */ + for (n = 0; n < 16; n++) { + if (mmio_read8(gicd_base + GICD_CPENDSGIR + n)) { + mmio_write8(gicd_base + GICD_CPENDSGIR + n, 0xff); + irqchip_set_pending(this_cpu_public(), n); + } + } + + return 0; +} + +static int gicv2_cpu_shutdown(struct public_per_cpu *cpu_public) +{ + u32 gicc_ctlr = 0; + u32 gich_vmcr; + + if (!cpu_public->gicc_initialized) + return -ENODEV; + + mmio_write32(gich_base + GICH_HCR, 0); + + /* Disable the maintenance interrupt - not used by Linux. */ + mmio_write32(gicd_base + GICD_ICENABLER, + 1 << system_config->platform_info.arm.maintenance_irq); + + gich_vmcr = mmio_read32(gich_base + GICH_VMCR); + if (gich_vmcr & GICH_VMCR_EN0) + gicc_ctlr |= GICC_CTLR_GRPEN1; + if (gich_vmcr & GICH_VMCR_EOImode) + gicc_ctlr |= GICC_CTLR_EOImode; + + mmio_write32(gicc_base + GICC_CTLR, gicc_ctlr); + mmio_write32(gicc_base + GICC_PMR, + (gich_vmcr >> GICH_VMCR_PMR_SHIFT) << GICV_PMR_SHIFT); + + return 0; +} + +static u32 gicv2_read_iar_irqn(void) +{ + return mmio_read32(gicc_base + GICC_IAR) & 0x3ff; +} + +static void gicv2_eoi_irq(u32 irq_id, bool deactivate) +{ + /* + * The GIC doesn't seem to care about the CPUID value written to EOIR, + * which is rather convenient... + */ + mmio_write32(gicc_base + GICC_EOIR, irq_id); + if (deactivate) + mmio_write32(gicc_base + GICC_DIR, irq_id); +} + +static int gicv2_cell_init(struct cell *cell) +{ + /* + * Without SDEI management interrrupts, let the guest access the + * virtual CPU interface instead of the physical. + * + * WARN: some SoCs (EXYNOS4) use a modified GIC which doesn't have any + * banked CPU interface, so we should map per-CPU physical addresses + * here. + * As for now, none of them seem to have virtualization extensions. + */ + u64 gic_source = sdei_available ? + system_config->platform_info.arm.gicc_base : + system_config->platform_info.arm.gicv_base; + + return paging_create(&cell->arch.mm, gic_source, GICC_SIZE, + system_config->platform_info.arm.gicc_base, + (PTE_FLAG_VALID | PTE_ACCESS_FLAG | + S2_PTE_ACCESS_RW | S2_PTE_FLAG_DEVICE), + PAGING_COHERENT | PAGING_NO_HUGE); +} + +static void gicv2_cell_exit(struct cell *cell) +{ + paging_destroy(&cell->arch.mm, + system_config->platform_info.arm.gicc_base, GICC_SIZE, + PAGING_COHERENT); +} + +static void gicv2_adjust_irq_target(struct cell *cell, u16 irq_id) +{ + void *itargetsr = gicd_base + GICD_ITARGETSR + (irq_id & ~0x3); + u32 targets = mmio_read32(itargetsr); + unsigned int shift = (irq_id % 4) * 8; + + if (gicv2_targets_in_cell(cell, (u8)(targets >> shift))) + return; + + targets &= ~(0xff << shift); + targets |= gicv2_target_cpu_map[first_cpu(cell->cpu_set)] << shift; + + mmio_write32(itargetsr, targets); +} + +static void gicv2_send_sgi(struct sgi *sgi) +{ + u32 val; + + val = (sgi->routing_mode & 0x3) << 24 + | (sgi->targets & 0xff) << 16 + | (sgi->id & 0xf); + + mmio_write32(gicd_base + GICD_SGIR, val); +} + +static int gicv2_inject_irq(u16 irq_id, u16 sender) +{ + unsigned int n; + int first_free = -1; + u32 lr; + unsigned long elsr[2]; + + elsr[0] = mmio_read32(gich_base + GICH_ELSR0); + elsr[1] = mmio_read32(gich_base + GICH_ELSR1); + for (n = 0; n < gic_num_lr; n++) { + if (test_bit(n, elsr)) { + /* Entry is available */ + if (first_free == -1) + first_free = n; + continue; + } + + /* Check that there is no overlapping */ + lr = gicv2_read_lr(n); + if ((lr & GICH_LR_VIRT_ID_MASK) == irq_id) + return -EEXIST; + } + + if (first_free == -1) + return -EBUSY; + + /* Inject group 0 interrupt (seen as IRQ by the guest) */ + lr = irq_id; + lr |= GICH_LR_PENDING_BIT; + + if (is_sgi(irq_id)) { + lr |= (sender & 0x7) << GICH_LR_CPUID_SHIFT; + } else { + lr |= GICH_LR_HW_BIT; + lr |= (u32)irq_id << GICH_LR_PHYS_ID_SHIFT; + } + + gicv2_write_lr(first_free, lr); + + return 0; +} + +static void gicv2_enable_maint_irq(bool enable) +{ + u32 hcr; + + hcr = mmio_read32(gich_base + GICH_HCR); + if (enable) + hcr |= GICH_HCR_UIE; + else + hcr &= ~GICH_HCR_UIE; + mmio_write32(gich_base + GICH_HCR, hcr); +} + +static bool gicv2_has_pending_irqs(void) +{ + unsigned int n; + + for (n = 0; n < gic_num_lr; n++) + if (gicv2_read_lr(n) & GICH_LR_PENDING_BIT) + return true; + + return false; +} + +static int gicv2_get_pending_irq(void) +{ + unsigned int n; + u64 lr; + + for (n = 0; n < gic_num_lr; n++) { + lr = gicv2_read_lr(n); + if (lr & GICH_LR_PENDING_BIT) { + gicv2_write_lr(n, 0); + return lr & GICH_LR_VIRT_ID_MASK; + } + } + + return -ENOENT; +} + +static void gicv2_inject_phys_irq(u16 irq_id) +{ + unsigned int offset = (irq_id / 32) * 4; + unsigned int mask = 1 << (irq_id % 32); + + if (is_sgi(irq_id)) { + /* Inject with CPU 0 as source - we don't track the origin. */ + mmio_write8(gicd_base + GICD_SPENDSGIR + irq_id, 1); + } else { + /* + * Hardware interrupts are physically active until they are + * processed by the cell. Deactivate them first so that we can + * reinject. + */ + mmio_write32(gicd_base + GICD_ICACTIVER + offset, mask); + + /* inject via GICD */ + mmio_write32(gicd_base + GICD_ISPENDR + offset, mask); + } +} + +static enum mmio_result gicv2_handle_irq_route(struct mmio_access *mmio, + unsigned int irq) +{ + /* doesn't exist in v2 - ignore access */ + return MMIO_HANDLED; +} + +/* + * GICv2 uses 8bit values for each IRQ in the ITARGETSR registers + */ +static enum mmio_result gicv2_handle_irq_target(struct mmio_access *mmio, + unsigned int irq) +{ + /* + * ITARGETSR contain one byte per IRQ, so the first one affected by this + * access corresponds to the reg index + */ + unsigned int irq_base = irq & ~0x3; + struct cell *cell = this_cell(); + unsigned int offset; + u32 access_mask = 0; + unsigned int n; + u8 targets; + + /* + * Let the guest freely access its SGIs and PPIs, which may be used to + * fill its CPU interface map. + */ + if (!is_spi(irq)) { + mmio_perform_access(gicd_base, mmio); + return MMIO_HANDLED; + } + + /* + * The registers are byte-accessible, but we always do word accesses. + */ + offset = irq % 4; + mmio->address &= ~0x3; + mmio->value <<= 8 * offset; + + for (n = offset; n < mmio->size + offset; n++) { + if (irqchip_irq_in_cell(cell, irq_base + n)) + access_mask |= 0xff << (8 * n); + else + continue; + + if (!mmio->is_write) + continue; + + targets = (mmio->value >> (8 * n)) & 0xff; + + if (!gicv2_targets_in_cell(cell, targets)) { + printk("Attempt to route IRQ%d outside of cell\n", + irq_base + n); + return MMIO_ERROR; + } + } + + mmio->size = 4; + + if (mmio->is_write) { + spin_lock(&dist_lock); + u32 itargetsr = + mmio_read32(gicd_base + GICD_ITARGETSR + irq_base); + mmio->value &= access_mask; + /* Combine with external SPIs */ + mmio->value |= (itargetsr & ~access_mask); + /* And do the access */ + mmio_perform_access(gicd_base, mmio); + spin_unlock(&dist_lock); + } else { + mmio_perform_access(gicd_base, mmio); + mmio->value &= access_mask; + mmio->value >>= 8 * offset; + } + + return MMIO_HANDLED; +} + +static enum mmio_result gicv2_handle_dist_access(struct mmio_access *mmio) +{ + unsigned long val = mmio->value; + struct sgi sgi; + + switch (mmio->address) { + case GICD_SGIR: + if (!mmio->is_write) + return MMIO_HANDLED; + + sgi.targets = (val >> 16) & 0xff; + sgi.routing_mode = (val >> 24) & 0x3; + sgi.cluster_id = 0; + sgi.id = val & 0xf; + + gic_handle_sgir_write(&sgi); + return MMIO_HANDLED; + + case GICD_CTLR: + case GICD_TYPER: + case GICD_IIDR: + case REG_RANGE(GICDv2_PIDR0, 4, 4): + case REG_RANGE(GICDv2_PIDR4, 4, 4): + case REG_RANGE(GICDv2_CIDR0, 4, 4): + /* Allow read access, ignore write */ + if (!mmio->is_write) + mmio_perform_access(gicd_base, mmio); + /* fall through */ + default: + /* Ignore access. */ + return MMIO_HANDLED; + } +} + +static int gicv2_get_cpu_target(unsigned int cpu_id) +{ + return gicv2_target_cpu_map[cpu_id]; +} + +static u64 gicv2_get_cluster_target(unsigned int cpu_id) +{ + return 0; +} + +const struct irqchip gicv2_irqchip = { + .init = gicv2_init, + .cpu_init = gicv2_cpu_init, + .cpu_reset = gicv2_cpu_reset, + .cpu_shutdown = gicv2_cpu_shutdown, + .cell_init = gicv2_cell_init, + .cell_exit = gicv2_cell_exit, + .adjust_irq_target = gicv2_adjust_irq_target, + + .send_sgi = gicv2_send_sgi, + .inject_irq = gicv2_inject_irq, + .enable_maint_irq = gicv2_enable_maint_irq, + .has_pending_irqs = gicv2_has_pending_irqs, + .read_iar_irqn = gicv2_read_iar_irqn, + .eoi_irq = gicv2_eoi_irq, + + .get_pending_irq = gicv2_get_pending_irq, + .inject_phys_irq = gicv2_inject_phys_irq, + + .handle_irq_route = gicv2_handle_irq_route, + .handle_irq_target = gicv2_handle_irq_target, + .handle_dist_access = gicv2_handle_dist_access, + .get_cpu_target = gicv2_get_cpu_target, + .get_cluster_target = gicv2_get_cluster_target, + + .gicd_size = 0x1000, +}; diff --git a/hypervisor/arch/arm-common/gic-v3.c b/hypervisor/arch/arm-common/gic-v3.c new file mode 100644 index 0000000000000000000000000000000000000000..af92034f1a2e3e6aaa30a89bd3628db55d98e298 --- /dev/null +++ b/hypervisor/arch/arm-common/gic-v3.c @@ -0,0 +1,724 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GIC_V3_REDIST_SIZE 0x20000 +#define GIC_V4_REDIST_SIZE 0x40000 + +/* + * This implementation assumes that the kernel driver already initialised most + * of the GIC. + * There is almost no instruction barrier, since IRQs are always disabled in the + * hyp, and ERET serves as the context synchronization event. + */ + +static unsigned int gic_num_lr; +static unsigned int gic_num_priority_bits; +static unsigned int last_gicr; +static u32 gic_version; + +static void *gicr_base; + +static u64 gicv3_read_lr(unsigned int reg) +{ + u64 val; + + switch (reg) { +#define __READ_LR0_7(n) \ + case n: \ + ARM_GIC_READ_LR0_7(n, val) \ + break; + + __READ_LR0_7(0) + __READ_LR0_7(1) + __READ_LR0_7(2) + __READ_LR0_7(3) + __READ_LR0_7(4) + __READ_LR0_7(5) + __READ_LR0_7(6) + __READ_LR0_7(7) +#undef __READ_LR0_7 + +#define __READ_LR8_15(n) \ + case n+8: \ + ARM_GIC_READ_LR8_15(n, val) \ + break; + + __READ_LR8_15(0) + __READ_LR8_15(1) + __READ_LR8_15(2) + __READ_LR8_15(3) + __READ_LR8_15(4) + __READ_LR8_15(5) + __READ_LR8_15(6) + __READ_LR8_15(7) +#undef __READ_LR8_15 + + default: + return (u64)(-1); + } + + return val; +} + +static void gicv3_write_lr(unsigned int reg, u64 val) +{ + switch (reg) { +#define __WRITE_LR0_7(n) \ + case n: \ + ARM_GIC_WRITE_LR0_7(n, val) \ + break; + + __WRITE_LR0_7(0) + __WRITE_LR0_7(1) + __WRITE_LR0_7(2) + __WRITE_LR0_7(3) + __WRITE_LR0_7(4) + __WRITE_LR0_7(5) + __WRITE_LR0_7(6) + __WRITE_LR0_7(7) +#undef __WRITE_LR0_7 + +#define __WRITE_LR8_15(n) \ + case n+8: \ + ARM_GIC_WRITE_LR8_15(n, val) \ + break; + __WRITE_LR8_15(0) + __WRITE_LR8_15(1) + __WRITE_LR8_15(2) + __WRITE_LR8_15(3) + __WRITE_LR8_15(4) + __WRITE_LR8_15(5) + __WRITE_LR8_15(6) + __WRITE_LR8_15(7) +#undef __WRITE_LR8_15 + } + + /* + * Ensure the write to the LR is visible to the GIC (so that ICH_ELRSR + * is updated to indicate that the just-written LR is no longer empty) + */ + isb(); +} + +static int gicv3_init(void) +{ + unsigned long redist_size = GIC_V3_REDIST_SIZE; + unsigned int gicr_size; + + /* Probe the GICD version */ + gic_version = GICD_PIDR2_ARCH(mmio_read32(gicd_base + GICDv3_PIDR2)); + if (gic_version != 3 && gic_version != 4) + return trace_error(-ENODEV); + + /* TODO: need to validate more? */ + if (!(mmio_read32(gicd_base + GICD_CTLR) & GICD_CTLR_ARE_NS)) + return trace_error(-EIO); + + last_gicr = system_config->root_cell.cpu_set_size * 8 - 1; + while (!cpu_id_valid(last_gicr)) + last_gicr--; + + /* + * Let the per-cpu code access the redistributors. This makes the + * assumption, that redistributors can be found in a sequence. + */ + if (gic_version == 4) + redist_size = GIC_V4_REDIST_SIZE; + + gicr_size = redist_size * (last_gicr + 1); + gicr_base = paging_map_device( + system_config->platform_info.arm.gicr_base, gicr_size); + if (!gicr_base) + return -ENOMEM; + + return 0; +} + +static void gicv3_clear_pending_irqs(void) +{ + unsigned int n; + + /* Clear list registers. */ + for (n = 0; n < gic_num_lr; n++) + gicv3_write_lr(n, 0); + + /* Clear active priority bits */ + if (gic_num_priority_bits >= 5) + arm_write_sysreg(ICH_AP1R0_EL2, 0); + if (gic_num_priority_bits >= 6) + arm_write_sysreg(ICH_AP1R1_EL2, 0); + if (gic_num_priority_bits > 6) { + arm_write_sysreg(ICH_AP1R2_EL2, 0); + arm_write_sysreg(ICH_AP1R3_EL2, 0); + } +} + +static void gicv3_cpu_reset(struct per_cpu *cpu_data) +{ + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + void *gicr = cpu_data->public.gicr.base + GICR_SGI_BASE; + + gicv3_clear_pending_irqs(); + + /* Ensure all IPIs and the maintenance PPI are enabled. */ + mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff | (1 << mnt_irq)); + + /* Disable PPIs, except for the maintenance interrupt. */ + mmio_write32(gicr + GICR_ICENABLER, 0xffff0000 & ~(1 << mnt_irq)); + + /* Deactivate all active PPIs */ + mmio_write32(gicr + GICR_ICACTIVER, 0xffff0000); + + arm_write_sysreg(ICH_VMCR_EL2, 0); +} + +static int gicv3_cpu_init(struct per_cpu *cpu_data) +{ + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + unsigned long redist_addr = system_config->platform_info.arm.gicr_base; + unsigned long redist_size = GIC_V3_REDIST_SIZE; + void *redist_base = gicr_base; + unsigned long gicr_ispendr, gicr_isacter; + unsigned int n; + void *gicr; + u64 typer, mpidr; + u32 pidr, aff; + u32 cell_icc_ctlr, cell_icc_pmr, cell_icc_igrpen1; + u32 ich_vtr; + u32 ich_vmcr; + + if (gic_version == 4) + redist_size = GIC_V4_REDIST_SIZE; + + mpidr = cpu_data->public.mpidr; + aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 | + MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | + MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | + MPIDR_AFFINITY_LEVEL(mpidr, 0)); + + /* Find redistributor */ + do { + pidr = mmio_read32(redist_base + GICR_PIDR2); + if (GICR_PIDR2_ARCH(pidr) != gic_version) + break; + + typer = mmio_read64(redist_base + GICR_TYPER); + if ((typer >> 32) == aff) { + cpu_data->public.gicr.base = redist_base; + cpu_data->public.gicr.phys_addr = redist_addr; + break; + } + + redist_base += redist_size; + redist_addr += redist_size; + } while (!(typer & GICR_TYPER_Last)); + + if (!cpu_data->public.gicr.base) { + printk("GIC: No redist found for CPU%d\n", + cpu_data->public.cpu_id); + return -ENODEV; + } + + /* Make sure we can handle Aff0 with the TargetList of ICC_SGI1R_EL1. */ + if ((cpu_data->public.mpidr & MPIDR_AFF0_MASK) >= 16) + return trace_error(-EIO); + + if (sdei_available) + return 0; + + /* Ensure all IPIs and the maintenance PPI are enabled. */ + gicr = redist_base + GICR_SGI_BASE; + mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff | (1 << mnt_irq)); + + /* + * Set EOIMode to 1 + * This allow to drop the priority of level-triggered interrupts without + * deactivating them, and thus ensure that they won't be immediately + * re-triggered. (e.g. timer) + * They can then be injected into the guest using the LR.HW bit, and + * will be deactivated once the guest does an EOI after handling the + * interrupt source. + */ + arm_read_sysreg(ICC_CTLR_EL1, cell_icc_ctlr); + arm_write_sysreg(ICC_CTLR_EL1, ICC_CTLR_EOImode); + + arm_read_sysreg(ICC_PMR_EL1, cell_icc_pmr); + arm_write_sysreg(ICC_PMR_EL1, ICC_PMR_DEFAULT); + + arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1); + arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN); + + arm_read_sysreg(ICH_VTR_EL2, ich_vtr); + gic_num_lr = (ich_vtr & 0xf) + 1; + gic_num_priority_bits = (ich_vtr >> 29) + 1; + + /* + * Clear pending virtual IRQs in case anything is left from previous + * use. Physically pending IRQs will be forwarded to Linux once we + * enable interrupts for the hypervisor. + */ + gicv3_clear_pending_irqs(); + + ich_vmcr = (cell_icc_pmr & ICC_PMR_MASK) << ICH_VMCR_VPMR_SHIFT; + if (cell_icc_igrpen1 & ICC_IGRPEN1_EN) + ich_vmcr |= ICH_VMCR_VENG1; + if (cell_icc_ctlr & ICC_CTLR_EOImode) + ich_vmcr |= ICH_VMCR_VEOIM; + arm_write_sysreg(ICH_VMCR_EL2, ich_vmcr); + + /* After this, the cells access the virtual interface of the GIC. */ + arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN); + + /* Deactivate all active SGIs */ + gicr_isacter = mmio_read32(gicr + GICR_ISACTIVER); + mmio_write32(gicr + GICR_ICACTIVER, gicr_isacter & 0xffff); + + /* Forward any pending physical SGIs to the virtual queue. */ + gicr_ispendr = mmio_read32(gicr + GICR_ISPENDR); + for (n = 0; n < 16; n++) { + if (test_bit(n, &gicr_ispendr)) { + mmio_write32(gicr + GICR_ICPENDR, 1UL << n); + irqchip_set_pending(&cpu_data->public, n); + } + } + + return 0; +} + +static int gicv3_cpu_shutdown(struct public_per_cpu *cpu_public) +{ + u32 ich_vmcr, icc_ctlr, cell_icc_igrpen1; + + if (sdei_available || !cpu_public->gicr.base) + return -ENODEV; + + arm_write_sysreg(ICH_HCR_EL2, 0); + + /* Disable the maintenance interrupt - not used by Linux. */ + mmio_write32(cpu_public->gicr.base + GICR_SGI_BASE + GICR_ICENABLER, + 1 << system_config->platform_info.arm.maintenance_irq); + + /* Restore the root config */ + arm_read_sysreg(ICH_VMCR_EL2, ich_vmcr); + + if (!(ich_vmcr & ICH_VMCR_VEOIM)) { + arm_read_sysreg(ICC_CTLR_EL1, icc_ctlr); + icc_ctlr &= ~ICC_CTLR_EOImode; + arm_write_sysreg(ICC_CTLR_EL1, icc_ctlr); + } + if (!(ich_vmcr & ICH_VMCR_VENG1)) { + arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1); + cell_icc_igrpen1 &= ~ICC_IGRPEN1_EN; + arm_write_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1); + } + + return 0; +} + +static void gicv3_adjust_irq_target(struct cell *cell, u16 irq_id) +{ + void *irouter = gicd_base + GICD_IROUTER + 8 * irq_id; + u64 mpidr = public_per_cpu(first_cpu(cell->cpu_set))->mpidr; + u32 route = arm_cpu_by_mpidr(cell, + mmio_read64(irouter) & MPIDR_CPUID_MASK); + + if (!cell_owns_cpu(cell, route)) + mmio_write64(irouter, mpidr); +} + +static enum mmio_result gicv3_handle_redist_access(void *arg, + struct mmio_access *mmio) +{ + struct public_per_cpu *cpu_public = arg; + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + + switch (mmio->address) { + case GICR_TYPER: + mmio_perform_access(cpu_public->gicr.base, mmio); + if (cpu_public->cpu_id == last_gicr) + mmio->value |= GICR_TYPER_Last; + return MMIO_HANDLED; + case GICR_TYPER + 4: + mmio_perform_access(cpu_public->gicr.base, mmio); + return MMIO_HANDLED; + case GICR_IIDR: + case 0xffd0 ... 0xfffc: /* ID registers */ + /* + * Read-only registers that might be used by a cell to find the + * redistributor corresponding to a CPU. Keep them accessible. + */ + break; + case GICR_SYNCR: + mmio->value = 0; + return MMIO_HANDLED; + case GICR_SGI_BASE + GICR_ISENABLER: + case GICR_SGI_BASE + GICR_ICENABLER: + case GICR_SGI_BASE + GICR_ISPENDR: + case GICR_SGI_BASE + GICR_ICPENDR: + case GICR_SGI_BASE + GICR_ISACTIVER: + case GICR_SGI_BASE + GICR_ICACTIVER: + mmio->value &= ~(SGI_MASK | (1 << mnt_irq)); + /* fall through */ + case GICR_CTLR: + case GICR_STATUSR: + case GICR_WAKER: + case REG_RANGE(GICR_SGI_BASE + GICR_IPRIORITYR, 8, 4): + case REG_RANGE(GICR_SGI_BASE + GICR_ICFGR, 2, 4): + if (this_cell() != cpu_public->cell) { + /* ignore access to foreign redistributors */ + return MMIO_HANDLED; + } + break; + default: + /* ignore access */ + return MMIO_HANDLED; + } + + mmio_perform_access(cpu_public->gicr.base, mmio); + + return MMIO_HANDLED; +} + +static int gicv3_cell_init(struct cell *cell) +{ + unsigned int cpu; + + /* + * We register all regions so that the cell can iterate over the + * original range in order to find corresponding redistributors. + */ + for (cpu = 0; cpu < system_config->root_cell.cpu_set_size * 8; cpu++) { + if (!cpu_id_valid(cpu)) + continue; + mmio_region_register(cell, public_per_cpu(cpu)->gicr.phys_addr, + gic_version == 4 ? 0x40000 : 0x20000, + gicv3_handle_redist_access, + public_per_cpu(cpu)); + } + + return 0; +} + +#define MPIDR_TO_SGIR_AFFINITY(cluster_id, level) \ + (MPIDR_AFFINITY_LEVEL((cluster_id), (level)) \ + << ICC_SGIR_AFF## level ##_SHIFT) + +static void gicv3_send_sgi(struct sgi *sgi) +{ + u64 val; + u16 targets = sgi->targets; + + if (sgi->routing_mode == 2) + targets = 1 << phys_processor_id(); + + val = (MPIDR_TO_SGIR_AFFINITY(sgi->cluster_id, 3) + | MPIDR_TO_SGIR_AFFINITY(sgi->cluster_id, 2) + | MPIDR_TO_SGIR_AFFINITY(sgi->cluster_id, 1) + | (targets & ICC_SGIR_TARGET_MASK) + | (sgi->id & 0xf) << ICC_SGIR_IRQN_SHIFT); + + if (sgi->routing_mode == 1) + val |= ICC_SGIR_ROUTING_BIT; + + /* + * Ensure the targets see our modifications to their per-cpu + * structures. + */ + dsb(ish); + + arm_write_sysreg(ICC_SGI1R_EL1, val); + isb(); +} + +#define SGIR_TO_AFFINITY(sgir, level) \ + ((sgir) >> ICC_SGIR_AFF## level ##_SHIFT & 0xff) + +#define SGIR_TO_MPIDR_AFFINITY(sgir, level) \ + (SGIR_TO_AFFINITY(sgir, level) << MPIDR_LEVEL_SHIFT(level)) + +bool gicv3_handle_sgir_write(u64 sgir) +{ + struct sgi sgi; + unsigned long routing_mode = !!(sgir & ICC_SGIR_ROUTING_BIT); + + if (gic_version < 3) + return false; + + sgi.targets = sgir & ICC_SGIR_TARGET_MASK; + sgi.routing_mode = routing_mode; + sgi.cluster_id = (SGIR_TO_MPIDR_AFFINITY(sgir, 3) + | SGIR_TO_MPIDR_AFFINITY(sgir, 2) + | SGIR_TO_MPIDR_AFFINITY(sgir, 1)); + sgi.id = sgir >> ICC_SGIR_IRQN_SHIFT & 0xf; + + gic_handle_sgir_write(&sgi); + + return true; +} + +/* + * GICv3 uses a 64bit register IROUTER for each IRQ + */ +static enum mmio_result gicv3_handle_irq_route(struct mmio_access *mmio, + unsigned int irq) +{ + struct cell *cell = this_cell(); + unsigned int cpu; + + /* Ignore aff3 on AArch32 (return 0) */ + if (mmio->size == 4 && (mmio->address % 8)) + return MMIO_HANDLED; + + /* SGIs and PPIs are res0 */ + if (!is_spi(irq)) + return MMIO_HANDLED; + + /* + * Ignore accesses to SPIs that do not belong to the cell. This isn't + * forbidden, because the guest driver may simply iterate over all + * registers at initialisation + */ + if (!irqchip_irq_in_cell(cell, irq)) + return MMIO_HANDLED; + + if (mmio->is_write) { + /* + * Validate that the target CPU is part of the cell. + * Note that we do not support Interrupt Routing Mode = 1. + */ + if( !cell->config->use_virt_cpuid ) + { + for_each_cpu(cpu, cell->cpu_set) + { + if ((public_per_cpu(cpu)->mpidr & MPIDR_CPUID_MASK) == + mmio->value) { + mmio_perform_access(gicd_base, mmio); + return MMIO_HANDLED; + } + } + } else { + cpu = arm_cpu_by_virt_cpuid(cell, mmio->value); + mmio->value = public_per_cpu(cpu)->mpidr; + mmio_perform_access(gicd_base, mmio); + return MMIO_HANDLED; + } + + printk("Attempt to route IRQ%d outside of cell\n", irq); + return MMIO_ERROR; + } else { + mmio->value = mmio_read64(gicd_base + GICD_IROUTER + 8 * irq); + return MMIO_HANDLED; + } +} + +static u32 gicv3_read_iar_irqn(void) +{ + u32 iar; + + arm_read_sysreg(ICC_IAR1_EL1, iar); + return iar & 0xffffff; +} + +static void gicv3_eoi_irq(u32 irq_id, bool deactivate) +{ + arm_write_sysreg(ICC_EOIR1_EL1, irq_id); + if (deactivate) + arm_write_sysreg(ICC_DIR_EL1, irq_id); +} + +static int gicv3_inject_irq(u16 irq_id, u16 sender) +{ + unsigned int n; + int free_lr = -1; + u32 elsr; + u64 lr; + + arm_read_sysreg(ICH_ELSR_EL2, elsr); + for (n = 0; n < gic_num_lr; n++) { + if ((elsr >> n) & 1) { + /* Entry is invalid, candidate for injection */ + if (free_lr == -1) + free_lr = n; + continue; + } + + /* + * Entry is in use, check that it doesn't match the one we want + * to inject. + */ + lr = gicv3_read_lr(n); + + /* + * A strict phys->virt id mapping is used for SPIs, so this test + * should be sufficient. + */ + if ((u32)lr == irq_id) + return -EEXIST; + } + + if (free_lr == -1) + /* All list registers are in use */ + return -EBUSY; + + lr = irq_id; + /* Only group 1 interrupts */ + lr |= ICH_LR_GROUP_BIT; + lr |= ICH_LR_PENDING; + if (!is_sgi(irq_id)) { + lr |= ICH_LR_HW_BIT; + lr |= (u64)irq_id << ICH_LR_PHYS_ID_SHIFT; + } + /* GICv3 doesn't support the injection of the calling CPU ID */ + + gicv3_write_lr(free_lr, lr); + + return 0; +} + +static void gicv3_enable_maint_irq(bool enable) +{ + u32 hcr; + + arm_read_sysreg(ICH_HCR_EL2, hcr); + if (enable) + hcr |= ICH_HCR_UIE; + else + hcr &= ~ICH_HCR_UIE; + arm_write_sysreg(ICH_HCR_EL2, hcr); +} + +static bool gicv3_has_pending_irqs(void) +{ + unsigned int n; + + for (n = 0; n < gic_num_lr; n++) + if (gicv3_read_lr(n) & ICH_LR_PENDING) + return true; + + return false; +} + +static int gicv3_get_pending_irq(void) +{ + unsigned int n; + u64 lr; + + for (n = 0; n < gic_num_lr; n++) { + lr = gicv3_read_lr(n); + if (lr & ICH_LR_PENDING) { + gicv3_write_lr(n, 0); + return (u32)lr; + } + } + + return -ENOENT; +} + +static void gicv3_inject_phys_irq(u16 irq_id) +{ + void *gicr = this_cpu_public()->gicr.base + GICR_SGI_BASE; + unsigned int offset = (irq_id / 32) * 4; + unsigned int mask = 1 << (irq_id % 32); + + if (!is_spi(irq_id)) { + /* + * Hardware interrupts are physically active until they are + * processed by the cell. Deactivate them first so that we can + * reinject. + * For simplicity reasons, we also issue deactivation for SGIs + * although they don't need this. + */ + mmio_write32(gicr + GICR_ICACTIVER, mask); + + /* inject via GICR */ + mmio_write32(gicr + GICR_ISPENDR, mask); + } else { + /* see above */ + mmio_write32(gicd_base + GICD_ICACTIVER + offset, mask); + + /* injet via GICD */ + mmio_write32(gicd_base + GICD_ISPENDR + offset, mask); + } +} + +static enum mmio_result gicv3_handle_irq_target(struct mmio_access *mmio, + unsigned int irq) +{ + /* ignore writes, we are in affinity routing mode */ + return MMIO_HANDLED; +} + +static enum mmio_result gicv3_handle_dist_access(struct mmio_access *mmio) +{ + switch (mmio->address) { + case GICD_CTLR: + case GICD_TYPER: + case GICD_IIDR: + case REG_RANGE(GICDv3_PIDR0, 4, 4): + case REG_RANGE(GICDv3_PIDR4, 4, 4): + case REG_RANGE(GICDv3_CIDR0, 4, 4): + /* Allow read access, ignore write */ + if (!mmio->is_write) + mmio_perform_access(gicd_base, mmio); + /* fall through */ + default: + /* Ignore access. */ + return MMIO_HANDLED; + } +} + +static int gicv3_get_cpu_target(unsigned int cpu_id) +{ + return 1 << (public_per_cpu(cpu_id)->mpidr & MPIDR_AFF0_MASK); +} + +static u64 gicv3_get_cluster_target(unsigned int cpu_id) +{ + return public_per_cpu(cpu_id)->mpidr & MPIDR_CLUSTERID_MASK; +} + +const struct irqchip gicv3_irqchip = { + .init = gicv3_init, + .cpu_init = gicv3_cpu_init, + .cpu_reset = gicv3_cpu_reset, + .cpu_shutdown = gicv3_cpu_shutdown, + .cell_init = gicv3_cell_init, + .adjust_irq_target = gicv3_adjust_irq_target, + .send_sgi = gicv3_send_sgi, + .inject_irq = gicv3_inject_irq, + .enable_maint_irq = gicv3_enable_maint_irq, + .has_pending_irqs = gicv3_has_pending_irqs, + .get_pending_irq = gicv3_get_pending_irq, + .inject_phys_irq = gicv3_inject_phys_irq, + .read_iar_irqn = gicv3_read_iar_irqn, + .eoi_irq = gicv3_eoi_irq, + .handle_irq_route = gicv3_handle_irq_route, + .handle_irq_target = gicv3_handle_irq_target, + .handle_dist_access = gicv3_handle_dist_access, + .get_cpu_target = gicv3_get_cpu_target, + .get_cluster_target = gicv3_get_cluster_target, + + .gicd_size = 0x10000, +}; diff --git a/hypervisor/arch/arm-common/include/asm/bitops.h b/hypervisor/arch/arm-common/include/asm/bitops.h new file mode 100644 index 0000000000000000000000000000000000000000..808c9a0f2fed8c14054af2d55cec5377c49f56a5 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/bitops.h @@ -0,0 +1,43 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2020 + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jan Kiszka + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +static inline __attribute__((always_inline)) int +test_bit(unsigned int nr, const volatile unsigned long *addr) +{ + return ((1UL << (nr % BITS_PER_LONG)) & + (addr[nr / BITS_PER_LONG])) != 0; +} + +/* Count leading zeroes */ +static inline unsigned long clz(unsigned long word) +{ + unsigned long val; + + asm volatile ("clz %0, %1" : "=r" (val) : "r" (word)); + return val; +} + +/* Returns the position of the least significant 1, MSB=31, LSB=0*/ +static inline unsigned long ffsl(unsigned long word) +{ + if (!word) + return 0; + asm volatile ("rbit %0, %0" : "+r" (word)); + return clz(word); +} + +static inline unsigned long ffzl(unsigned long word) +{ + return ffsl(~word); +} diff --git a/hypervisor/arch/arm-common/include/asm/cell.h b/hypervisor/arch/arm-common/include/asm/cell.h new file mode 100644 index 0000000000000000000000000000000000000000..9c6e8c6f3fe2a874bcf8e87d087ba0c1a470a91b --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/cell.h @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_CELL_H +#define _JAILHOUSE_ASM_CELL_H + +#include + +struct pvu_tlb_entry; + +struct arch_cell { + struct paging_structures mm; + + u32 irq_bitmap[1024/32]; + + struct { + u8 ent_count; + struct pvu_tlb_entry *entries; + } iommu_pvu; /**< ARM PVU specific fields. */ +}; + +#endif /* !_JAILHOUSE_ASM_CELL_H */ diff --git a/hypervisor/arch/arm-common/include/asm/control.h b/hypervisor/arch/arm-common/include/asm/control.h new file mode 100644 index 0000000000000000000000000000000000000000..81ff723cb43e40550121451e27075e4551e704b4 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/control.h @@ -0,0 +1,41 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_CONTROL_H +#define _JAILHOUSE_ASM_CONTROL_H + +#define SGI_INJECT 0 +#define SGI_EVENT 1 +#define SGI_MASK ((1 << SGI_EVENT) | (1 << SGI_INJECT)) + +#ifndef __ASSEMBLY__ + +#include + +void arch_handle_sgi(u32 irqn, unsigned int count_event); +bool arch_handle_phys_irq(u32 irqn, unsigned int count_event); + +union registers* arch_handle_exit(union registers *regs); + +void arch_shutdown_self(struct per_cpu *cpu_data); + +unsigned int arm_cpu_by_mpidr(struct cell *cell, unsigned long mpidr); + +unsigned int arm_cpu_by_virt_cpuid( struct cell *cell, unsigned long virt_cpuid ); + +void arm_cpu_reset(unsigned long pc, bool aarch32); +void arm_cpu_park(void); +void arm_cpu_passthru_suspend(void); + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_CONTROL_H */ diff --git a/hypervisor/arch/arm-common/include/asm/dcaches.h b/hypervisor/arch/arm-common/include/asm/dcaches.h new file mode 100644 index 0000000000000000000000000000000000000000..87c316dcc4a84a766965114ef00f3e7985a428b2 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/dcaches.h @@ -0,0 +1,28 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef __ASSEMBLY__ + +struct cell; + +enum dcache_flush { + DCACHE_CLEAN, + DCACHE_INVALIDATE, + DCACHE_CLEAN_AND_INVALIDATE, +}; + +void arm_dcaches_flush(void *addr, unsigned long size, enum dcache_flush flush); +void arm_cell_dcaches_flush(struct cell *cell, enum dcache_flush flush); + +#endif /* !__ASSEMBLY__ */ diff --git a/hypervisor/arch/arm-common/include/asm/gic.h b/hypervisor/arch/arm-common/include/asm/gic.h new file mode 100644 index 0000000000000000000000000000000000000000..e851d37509fe57b9c2892fa1fd546012b25335f4 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/gic.h @@ -0,0 +1,55 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_GIC_COMMON_H +#define _JAILHOUSE_ASM_GIC_COMMON_H + +#include + +#define GICD_CTLR 0x0000 +# define GICD_CTLR_ARE_NS (1 << 4) +#define GICD_TYPER 0x0004 +#define GICD_IIDR 0x0008 +#define GICD_IGROUPR 0x0080 +#define GICD_ISENABLER 0x0100 +#define GICD_ICENABLER 0x0180 +#define GICD_ISPENDR 0x0200 +#define GICD_ICPENDR 0x0280 +#define GICD_ISACTIVER 0x0300 +#define GICD_ICACTIVER 0x0380 +#define GICD_IPRIORITYR 0x0400 +#define GICD_ITARGETSR 0x0800 +#define GICD_ICFGR 0x0c00 +#define GICD_NSACR 0x0e00 +#define GICD_SGIR 0x0f00 +#define GICD_CPENDSGIR 0x0f10 +#define GICD_SPENDSGIR 0x0f20 +#define GICD_IROUTER 0x6000 + +#define GICD_PIDR2_ARCH(pidr) (((pidr) & 0xf0) >> 4) + +#define is_sgi(irqn) ((u32)(irqn) < 16) +#define is_ppi(irqn) ((irqn) > 15 && (irqn) < 32) +#define is_spi(irqn) ((irqn) > 31 && (irqn) < 1020) + +#define REG_RANGE(base, n, size) (base)...((base) + (n - 1) * (size)) + +#ifndef __ASSEMBLY__ +extern const struct irqchip gicv2_irqchip, gicv3_irqchip; + +extern void *gicd_base; +extern spinlock_t dist_lock; + +void gic_handle_sgir_write(struct sgi *sgi); +bool gicv3_handle_sgir_write(u64 sgir); +#endif /* !__ASSEMBLY__ */ +#endif /* !_JAILHOUSE_ASM_GIC_COMMON_H */ diff --git a/hypervisor/arch/arm-common/include/asm/gic_v2.h b/hypervisor/arch/arm-common/include/asm/gic_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..77230cc7dfddec1236b255ae34049a0b84fe46e7 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/gic_v2.h @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_GIC_V2_H +#define _JAILHOUSE_ASM_GIC_V2_H + +#define GICC_SIZE 0x2000 +#define GICH_SIZE 0x2000 + +#define GICDv2_CIDR0 0xff0 +#define GICDv2_PIDR0 0xfe0 +#define GICDv2_PIDR2 0xfe8 +#define GICDv2_PIDR4 0xfd0 + +#define GICC_CTLR 0x0000 +#define GICC_PMR 0x0004 +#define GICC_IAR 0x000c +#define GICC_EOIR 0x0010 +#define GICC_DIR 0x1000 + +#define GICC_CTLR_GRPEN1 (1 << 0) +#define GICC_CTLR_EOImode (1 << 9) + +#define GICC_PMR_DEFAULT 0xf0 + +#define GICH_HCR 0x000 +#define GICH_VTR 0x004 +#define GICH_VMCR 0x008 +#define GICH_ELSR0 0x030 +#define GICH_ELSR1 0x034 +#define GICH_APR 0x0f0 +#define GICH_LR_BASE 0x100 + +#define GICV_PMR_SHIFT 3 +#define GICH_VMCR_PMR_SHIFT 27 +#define GICH_VMCR_EN0 (1 << 0) +#define GICH_VMCR_EN1 (1 << 1) +#define GICH_VMCR_ACKCtl (1 << 2) +#define GICH_VMCR_EOImode (1 << 9) + +#define GICH_HCR_EN (1 << 0) +#define GICH_HCR_UIE (1 << 1) +#define GICH_HCR_LRENPIE (1 << 2) +#define GICH_HCR_NPIE (1 << 3) +#define GICH_HCR_VGRP0EIE (1 << 4) +#define GICH_HCR_VGRP0DIE (1 << 5) +#define GICH_HCR_VGRP1EIE (1 << 6) +#define GICH_HCR_VGRP1DIE (1 << 7) +#define GICH_HCR_EOICOUNT_SHIFT 27 + +#define GICH_LR_HW_BIT (1 << 31) +#define GICH_LR_GRP1_BIT (1 << 30) +#define GICH_LR_ACTIVE_BIT (1 << 29) +#define GICH_LR_PENDING_BIT (1 << 28) +#define GICH_LR_PRIORITY_SHIFT 23 +#define GICH_LR_SGI_EOI_BIT (1 << 19) +#define GICH_LR_CPUID_SHIFT 10 +#define GICH_LR_PHYS_ID_SHIFT 10 +#define GICH_LR_VIRT_ID_MASK 0x3ff +#endif /* _JAILHOUSE_ASM_GIC_V2_H */ diff --git a/hypervisor/arch/arm-common/include/asm/gic_v3.h b/hypervisor/arch/arm-common/include/asm/gic_v3.h new file mode 100644 index 0000000000000000000000000000000000000000..853721d6e3af6b7006be7053cfce680e618ec4d7 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/gic_v3.h @@ -0,0 +1,128 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_GIC_V3_H +#define _JAILHOUSE_ASM_GIC_V3_H + +#include +#include + +#define GICDv3_CIDR0 0xfff0 +#define GICDv3_PIDR0 0xffe0 +#define GICDv3_PIDR2 0xffe8 +#define GICDv3_PIDR4 0xffd0 + +#define GICR_CTLR 0x0000 +#define GICR_IIDR 0x0004 +#define GICR_TYPER 0x0008 +#define GICR_STATUSR 0x0010 +#define GICR_WAKER 0x0014 +#define GICR_SYNCR 0x00c0 +#define GICR_PIDR2 0xffe8 + +#define GICR_SGI_BASE 0x10000 +#define GICR_ISENABLER GICD_ISENABLER +#define GICR_ICENABLER GICD_ICENABLER +#define GICR_ISPENDR GICD_ISPENDR +#define GICR_ICPENDR GICD_ICPENDR +#define GICR_ISACTIVER GICD_ISACTIVER +#define GICR_ICACTIVER GICD_ICACTIVER +#define GICR_IPRIORITYR GICD_IPRIORITYR +#define GICR_ICFGR GICD_ICFGR + +#define GICR_TYPER_Last (1 << 4) +#define GICR_PIDR2_ARCH GICD_PIDR2_ARCH + +#define ICC_IAR1_EL1 SYSREG_32(0, c12, c12, 0) +#define ICC_EOIR1_EL1 SYSREG_32(0, c12, c12, 1) +#define ICC_HPPIR1_EL1 SYSREG_32(0, c12, c12, 2) +#define ICC_BPR1_EL1 SYSREG_32(0, c12, c12, 3) +#define ICC_DIR_EL1 SYSREG_32(0, c12, c11, 1) +#define ICC_PMR_EL1 SYSREG_32(0, c4, c6, 0) +#define ICC_RPR_EL1 SYSREG_32(0, c12, c11, 3) +#define ICC_CTLR_EL1 SYSREG_32(0, c12, c12, 4) +#define ICC_SRE_EL1 SYSREG_32(0, c12, c12, 5) +#define ICC_SRE_EL2 SYSREG_32(4, c12, c9, 5) +#define ICC_IGRPEN1_EL1 SYSREG_32(0, c12, c12, 7) +#define ICC_AP1R0_EL1 SYSREG_32(0, c12, c9, 0) +#define ICC_AP1R1_EL1 SYSREG_32(0, c12, c9, 1) +#define ICC_AP1R2_EL1 SYSREG_32(0, c12, c9, 2) +#define ICC_AP1R3_EL1 SYSREG_32(0, c12, c9, 3) + +#define ICH_HCR_EL2 SYSREG_32(4, c12, c11, 0) +#define ICH_VTR_EL2 SYSREG_32(4, c12, c11, 1) +#define ICH_MISR_EL2 SYSREG_32(4, c12, c11, 2) +#define ICH_EISR_EL2 SYSREG_32(4, c12, c11, 3) +#define ICH_ELSR_EL2 SYSREG_32(4, c12, c11, 5) +#define ICH_VMCR_EL2 SYSREG_32(4, c12, c11, 7) +#define ICH_AP1R0_EL2 SYSREG_32(4, c12, c9, 0) +#define ICH_AP1R1_EL2 SYSREG_32(4, c12, c9, 1) +#define ICH_AP1R2_EL2 SYSREG_32(4, c12, c9, 2) +#define ICH_AP1R3_EL2 SYSREG_32(4, c12, c9, 3) + +#define ICC_CTLR_EOImode 0x2 +#define ICC_PMR_MASK 0xff +#define ICC_PMR_DEFAULT 0xf0 +#define ICC_IGRPEN1_EN 0x1 + +#define ICC_SGIR_AFF3_SHIFT 48 +#define ICC_SGIR_AFF2_SHIFT 32 +#define ICC_SGIR_AFF1_SHIFT 16 +#define ICC_SGIR_TARGET_MASK 0xffff +#define ICC_SGIR_IRQN_SHIFT 24 +#define ICC_SGIR_ROUTING_BIT (1ULL << 40) + +#define ICH_HCR_EN (1 << 0) +#define ICH_HCR_UIE (1 << 1) +#define ICH_HCR_LRENPIE (1 << 2) +#define ICH_HCR_NPIE (1 << 3) +#define ICH_HCR_VGRP0EIE (1 << 4) +#define ICH_HCR_VGRP0DIE (1 << 5) +#define ICH_HCR_VGRP1EIE (1 << 6) +#define ICH_HCR_VGRP1DIE (1 << 7) +#define ICH_HCR_VARE (1 << 9) +#define ICH_HCR_TC (1 << 10) +#define ICH_HCR_TALL0 (1 << 11) +#define ICH_HCR_TALL1 (1 << 12) +#define ICH_HCR_TSEI (1 << 13) +#define ICH_HCR_EOICount (0x1f << 27) + +#define ICH_MISR_EOI (1 << 0) +#define ICH_MISR_U (1 << 1) +#define ICH_MISR_LRENP (1 << 2) +#define ICH_MISR_NP (1 << 3) +#define ICH_MISR_VGRP0E (1 << 4) +#define ICH_MISR_VGRP0D (1 << 5) +#define ICH_MISR_VGRP1E (1 << 6) +#define ICH_MISR_VGRP1D (1 << 7) + +#define ICH_VMCR_VENG0 (1 << 0) +#define ICH_VMCR_VENG1 (1 << 1) +#define ICH_VMCR_VACKCTL (1 << 2) +#define ICH_VMCR_VFIQEN (1 << 3) +#define ICH_VMCR_VCBPR (1 << 4) +#define ICH_VMCR_VEOIM (1 << 9) +#define ICH_VMCR_VBPR1_SHIFT 18 +#define ICH_VMCR_VBPR0_SHIFT 21 +#define ICH_VMCR_VPMR_SHIFT 24 + +/* List registers upper bits */ +#define ICH_LR_INVALID (0x0ULL << 62) +#define ICH_LR_PENDING (0x1ULL << 62) +#define ICH_LR_ACTIVE (0x2ULL << 62) +#define ICH_LR_PENDACTIVE (0x3ULL << 62) +#define ICH_LR_HW_BIT (0x1ULL << 61) +#define ICH_LR_GROUP_BIT (0x1ULL << 60) +#define ICH_LR_PRIORITY_SHIFT 48 +#define ICH_LR_SGI_EOI (0x1ULL << 41) +#define ICH_LR_PHYS_ID_SHIFT 32 +#endif /* _JAILHOUSE_ASM_GIC_V3_H */ diff --git a/hypervisor/arch/arm-common/include/asm/iommu.h b/hypervisor/arch/arm-common/include/asm/iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..dde762c0fabd1f7eacb79e05263014d4e2cacd50 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/iommu.h @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_IOMMU_H +#define _JAILHOUSE_ASM_IOMMU_H + +#include +#include +#include + +#define for_each_stream_id(sid, config, counter) \ + for ((sid) = (jailhouse_cell_stream_ids(config)[0]), (counter) = 0; \ + (counter) < (config)->num_stream_ids; \ + (sid) = (jailhouse_cell_stream_ids(config)[++(counter)])) + +unsigned int iommu_count_units(void); +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +void iommu_config_commit(struct cell *cell); +#endif diff --git a/hypervisor/arch/arm-common/include/asm/irqchip.h b/hypervisor/arch/arm-common/include/asm/irqchip.h new file mode 100644 index 0000000000000000000000000000000000000000..06401f91bcbb9103f38520178e78957117c7a6f5 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/irqchip.h @@ -0,0 +1,105 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_IRQCHIP_H +#define _JAILHOUSE_ASM_IRQCHIP_H + +#define MAX_PENDING_IRQS 256 + +#include +#include + +#ifndef __ASSEMBLY__ + +struct per_cpu; +struct public_per_cpu; + +struct sgi { + /* + * Routing mode values: + * 0: use aff3.aff2.aff1.targets + * 1: all processors in the cell except this CPU + * 2: only this CPU + */ + u8 routing_mode; + /* cluster_id: mpidr & MPIDR_CLUSTERID_MASK */ + u64 cluster_id; + u16 targets; + u16 id; +}; + +struct irqchip { + int (*init)(void); + int (*cpu_init)(struct per_cpu *cpu_data); + void (*cpu_reset)(struct per_cpu *cpu_data); + int (*cpu_shutdown)(struct public_per_cpu *cpu_public); + int (*cell_init)(struct cell *cell); + void (*cell_exit)(struct cell *cell); + void (*adjust_irq_target)(struct cell *cell, u16 irq_id); + + void (*send_sgi)(struct sgi *sgi); + u32 (*read_iar_irqn)(void); + void (*eoi_irq)(u32 irqn, bool deactivate); + int (*inject_irq)(u16 irq_id, u16 sender); + void (*enable_maint_irq)(bool enable); + bool (*has_pending_irqs)(void); + int (*get_pending_irq)(void); + void (*inject_phys_irq)(u16 irq_id); + + int (*get_cpu_target)(unsigned int cpu_id); + u64 (*get_cluster_target)(unsigned int cpu_id); + + enum mmio_result (*handle_irq_route)(struct mmio_access *mmio, + unsigned int irq); + enum mmio_result (*handle_irq_target)(struct mmio_access *mmio, + unsigned int irq); + enum mmio_result (*handle_dist_access)(struct mmio_access *mmio); + + unsigned long gicd_size; +}; + +struct pending_irqs { + /* synchronizes parallel insertions of SGIs into the pending ring */ + spinlock_t lock; + u16 irqs[MAX_PENDING_IRQS]; + /* contains the calling CPU ID in case of a SGI */ + u16 sender[MAX_PENDING_IRQS]; + unsigned int head; + /* removal from the ring happens lockless, thus tail is volatile */ + volatile unsigned int tail; +}; + +int irqchip_cpu_init(struct per_cpu *cpu_data); +int irqchip_get_cpu_target(unsigned int cpu_id); +u64 irqchip_get_cluster_target(unsigned int cpu_id); +void irqchip_cpu_reset(struct per_cpu *cpu_data); + +void irqchip_cpu_shutdown(struct public_per_cpu *cpu_public); + +void irqchip_cell_reset(struct cell *cell); + +void irqchip_config_commit(struct cell *cell_added_removed); + +void irqchip_send_sgi(unsigned int cpu_id, u16 sgi_id); +void irqchip_handle_irq(void); + +bool irqchip_has_pending_irqs(void); + +void irqchip_inject_pending(void); +void irqchip_set_pending(struct public_per_cpu *cpu_public, u16 irq_id); + +void irqchip_trigger_external_irq(u16 irq_id); + +bool irqchip_irq_in_cell(struct cell *cell, unsigned int irq_id); + +#endif /* __ASSEMBLY__ */ +#endif /* _JAILHOUSE_ASM_IRQCHIP_H */ diff --git a/hypervisor/arch/arm-common/include/asm/ivshmem.h b/hypervisor/arch/arm-common/include/asm/ivshmem.h new file mode 100644 index 0000000000000000000000000000000000000000..655ad704f139435e3fdb27be32e9487700830321 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/ivshmem.h @@ -0,0 +1,15 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +struct arch_ivshmem_irq_cache { + u16 id[IVSHMEM_MSIX_VECTORS]; +}; diff --git a/hypervisor/arch/arm-common/include/asm/mmio.h b/hypervisor/arch/arm-common/include/asm/mmio.h new file mode 100644 index 0000000000000000000000000000000000000000..09cbc044211546a97ea8aad303fe5438eb253d53 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/mmio.h @@ -0,0 +1 @@ +/* nothing to do here */ diff --git a/hypervisor/arch/arm-common/include/asm/paging_modes.h b/hypervisor/arch/arm-common/include/asm/paging_modes.h new file mode 100644 index 0000000000000000000000000000000000000000..2ccd0da33bc549dc44074f24d5d3e9b31c2d2d29 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/paging_modes.h @@ -0,0 +1,20 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef __ASSEMBLY__ + +#include + +/* Long-descriptor paging */ +extern const struct paging *cell_paging; + +#endif /* !__ASSEMBLY__ */ diff --git a/hypervisor/arch/arm-common/include/asm/percpu.h b/hypervisor/arch/arm-common/include/asm/percpu.h new file mode 100644 index 0000000000000000000000000000000000000000..a369764122c8b416e74fd7c047d2c489f71b1224 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/percpu.h @@ -0,0 +1,64 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define STACK_SIZE PAGE_SIZE + +#define ARM_PERCPU_FIELDS \ + int smccc_feat_workaround_1; \ + int smccc_feat_workaround_2; + +#define ARCH_PUBLIC_PERCPU_FIELDS \ + unsigned long mpidr; \ + \ + union { \ + /** Only GICv2: per-cpu initialization completed. */ \ + bool gicc_initialized; \ + /** Only GICv3: Redistributor parameters. */ \ + struct { \ + /** Mapped redistributor base. When non-NULL, \ + * per-cpu initialization completed. */ \ + void *base; \ + /** Physical redistributor address. */ \ + unsigned long phys_addr; \ + } gicr; \ + }; \ + \ + struct pending_irqs pending_irqs; \ + \ + /** \ + * Lock protecting CPU state changes done for control tasks. \ + * \ + * The lock protects the following fields (unless CPU is \ + * suspended): \ + * @li public_per_cpu::suspend_cpu \ + * @li public_per_cpu::cpu_suspended (except for spinning on it \ + * to become true) \ + * @li public_per_cpu::flush_vcpu_caches \ + * @li public_per_cpu::wait_for_poweron (except for CPU-local \ + * tests) \ + * @li public_per_cpu::reset \ + * @li public_per_cpu::park \ + */ \ + spinlock_t control_lock; \ + \ + /** True if CPU is waiting for power-on. */ \ + volatile bool wait_for_poweron; \ + /** Set to true for pending reset. */ \ + bool reset; \ + /** Set to true for pending park. */ \ + bool park; \ + \ + unsigned long cpu_on_entry; \ + unsigned long cpu_on_context; diff --git a/hypervisor/arch/arm-common/include/asm/processor.h b/hypervisor/arch/arm-common/include/asm/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..710bf1979ada472cd8a50bcf130e1c932cea3fe1 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/processor.h @@ -0,0 +1,34 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define dmb(domain) asm volatile("dmb " #domain ::: "memory") +#define dsb(domain) asm volatile("dsb " #domain ::: "memory") +#define isb() asm volatile("isb") + +#ifndef __ASSEMBLY__ + +static inline void cpu_relax(void) +{ + asm volatile("" : : : "memory"); +} + +static inline void memory_barrier(void) +{ + dmb(ish); +} + +static inline void memory_load_barrier(void) +{ + dmb(ish); +} + +#endif /* !__ASSEMBLY__ */ diff --git a/hypervisor/arch/arm-common/include/asm/psci.h b/hypervisor/arch/arm-common/include/asm/psci.h new file mode 100644 index 0000000000000000000000000000000000000000..a24c0cb8f949ed4eee16f67a49002e7f9f06e43b --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/psci.h @@ -0,0 +1,52 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* PSCI v0.2 interface */ +#define PSCI_0_2_FN(n) (0x84000000 + (n)) +#define PSCI_0_2_FN64(n) (0xc4000000 + (n)) + +#define PSCI_0_2_FN_VERSION PSCI_0_2_FN(0) +#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) +#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) +#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) +#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) + +#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) +#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) +#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) + +/* PSCI v1.0 interface */ +#define PSCI_1_0_FN_FEATURES PSCI_0_2_FN(10) + +/* v0.1 function IDs as used by U-Boot */ +#define PSCI_CPU_OFF_V0_1_UBOOT 0x95c1ba5f +#define PSCI_CPU_ON_V0_1_UBOOT 0x95c1ba60 + +#define PSCI_SUCCESS 0 +#define PSCI_NOT_SUPPORTED (-1) +#define PSCI_INVALID_PARAMETERS (-2) +#define PSCI_DENIED (-3) +#define PSCI_ALREADY_ON (-4) + +#define PSCI_CPU_IS_ON 0 +#define PSCI_CPU_IS_OFF 1 + +#define IS_PSCI_UBOOT(hvc) (((hvc) >> 8) == 0x95c1ba) + +#define PSCI_INVALID_ADDRESS ~(0UL) + +#define PSCI_VERSION_MAJOR(ver) (u16)((ver) >> 16) +#define PSCI_VERSION(major, minor) (((major) << 16) | (minor)) + +struct trap_context; + +long psci_dispatch(struct trap_context *ctx); diff --git a/hypervisor/arch/arm-common/include/asm/setup.h b/hypervisor/arch/arm-common/include/asm/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..4860880535de5f8439ebc6fd7a14524da39d40da --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/setup.h @@ -0,0 +1,16 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +int arm_init_early(void); +int arm_cpu_init(struct per_cpu *cpu_data); diff --git a/hypervisor/arch/arm-common/include/asm/smccc.h b/hypervisor/arch/arm-common/include/asm/smccc.h new file mode 100644 index 0000000000000000000000000000000000000000..871244c1f152678e8e4294e089a3e89671198dbd --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/smccc.h @@ -0,0 +1,62 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define SMCCC_VERSION 0x80000000 +#define SMCCC_ARCH_FEATURES 0x80000001 +#define SMCCC_ARCH_WORKAROUND_1 0x80008000 +#define SMCCC_ARCH_WORKAROUND_2 0x80007fff + +#define SDEI_VERSION 0xc4000020 +#define SDEI_EVENT_REGISTER 0xc4000021 +#define SDEI_EVENT_ENABLE 0xc4000022 +#define SDEI_EVENT_COMPLETE 0xc4000025 +#define SDEI_EVENT_UNREGISTER 0xc4000027 +#define SDEI_PE_MASK 0xc400002b +#define SDEI_PE_UNMASK 0xc400002c +#define SDEI_EVENT_SIGNAL 0xc400002f + +#define ARM_SMCCC_VERSION_1_0 0x1000000000000L + +#define SDEI_EV_HANDLED 0 + +#define ARM_SMCCC_OWNER_MASK BIT_MASK(29, 24) +#define ARM_SMCCC_OWNER_SHIFT 24 + +#define ARM_SMCCC_OWNER_ARCH 0 +#define ARM_SMCCC_OWNER_SIP 2 +#define ARM_SMCCC_OWNER_STANDARD 4 + +#define ARM_SMCCC_CONV_32 0 +#define ARM_SMCCC_CONV_64 1 + +#define ARM_SMCCC_NOT_SUPPORTED (-1) +#define ARM_SMCCC_SUCCESS 0 + +#define ARM_SMCCC_VERSION_1_1 0x10001 + +#define SMCCC_GET_OWNER(id) ((id & ARM_SMCCC_OWNER_MASK) >> \ + ARM_SMCCC_OWNER_SHIFT) + +#define SMCCC_IS_CONV_64(function_id) !!(function_id & (1 << 30)) + +#ifndef __ASSEMBLY__ + +struct trap_context; + +extern bool sdei_available; + +int smccc_discover(void); +enum trap_return handle_smc(struct trap_context *ctx); + +#endif /* !__ASSEMBLY__ */ diff --git a/hypervisor/arch/arm-common/include/asm/traps.h b/hypervisor/arch/arm-common/include/asm/traps.h new file mode 100644 index 0000000000000000000000000000000000000000..65d4cbd24daa66109b2668a96fb2a696b9a2bc13 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/traps.h @@ -0,0 +1,23 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +enum trap_return { + TRAP_HANDLED = 1, + TRAP_UNHANDLED = 0, + TRAP_FORBIDDEN = -1, +}; + +typedef enum trap_return (*trap_handler)(struct trap_context *ctx); + +void arch_skip_instruction(struct trap_context *ctx); + +enum trap_return arch_handle_dabt(struct trap_context *ctx); diff --git a/hypervisor/arch/arm-common/include/asm/uart.h b/hypervisor/arch/arm-common/include/asm/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..8a505aa3d0f4469808c557d2e0f7880573514530 --- /dev/null +++ b/hypervisor/arch/arm-common/include/asm/uart.h @@ -0,0 +1,15 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +extern struct uart_chip uart_pl011_ops, uart_xuartps_ops, uart_mvebu_ops, + uart_hscif_ops, uart_scifa_ops, uart_imx_ops, + uart_imx_lpuart_ops, uart_scif_ops; diff --git a/hypervisor/arch/arm-common/irqchip.c b/hypervisor/arch/arm-common/irqchip.c new file mode 100644 index 0000000000000000000000000000000000000000..256af1146c2ab6ca695e295efb9cbf903b6005ad --- /dev/null +++ b/hypervisor/arch/arm-common/irqchip.c @@ -0,0 +1,547 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define for_each_irqchip(chip, config, counter) \ + for ((chip) = jailhouse_cell_irqchips(config), (counter) = 0; \ + (counter) < (config)->num_irqchips; \ + (chip)++, (counter)++) + +spinlock_t dist_lock; + +void *gicd_base; + +/* + * The init function must be called after the MMU setup, and whilst in the + * per-cpu setup, which means that a bool must be set by the master CPU + */ +static bool irqchip_is_init; + +static struct irqchip irqchip; + +/* + * Most of the GIC distributor writes only reconfigure the IRQs corresponding to + * the bits of the written value, by using separate `set' and `clear' registers. + * Such registers can be handled by setting the `is_poke' boolean, which allows + * to simply restrict the mmio->value with the cell configuration mask. + * Others, such as the priority registers, will need to be read and written back + * with a restricted value, by using the distributor lock. + */ +static enum mmio_result +restrict_bitmask_access(struct mmio_access *mmio, unsigned int reg_index, + unsigned int bits_per_irq, bool is_poke) +{ + struct cell *cell = this_cell(); + unsigned int irq; + unsigned long access_mask = 0; + /* + * In order to avoid division, the number of bits per irq is limited + * to powers of 2 for the moment. + */ + unsigned long irqs_per_reg = 32 >> ffsl(bits_per_irq); + unsigned long irq_bits = (1 << bits_per_irq) - 1; + /* First, extract the first interrupt affected by this access */ + unsigned int first_irq = reg_index * irqs_per_reg; + + for (irq = 0; irq < irqs_per_reg; irq++) + if (irqchip_irq_in_cell(cell, first_irq + irq)) + access_mask |= irq_bits << (irq * bits_per_irq); + + if (!mmio->is_write) { + /* Restrict the read value */ + mmio_perform_access(gicd_base, mmio); + mmio->value &= access_mask; + return MMIO_HANDLED; + } + + if (!is_poke) { + /* + * Modify the existing value of this register by first reading + * it into mmio->value + * Relies on a spinlock since we need two mmio accesses. + */ + unsigned long access_val = mmio->value; + + spin_lock(&dist_lock); + + mmio->is_write = false; + mmio_perform_access(gicd_base, mmio); + mmio->is_write = true; + + mmio->value &= ~access_mask; + mmio->value |= access_val & access_mask; + mmio_perform_access(gicd_base, mmio); + + spin_unlock(&dist_lock); + } else { + mmio->value &= access_mask; + mmio_perform_access(gicd_base, mmio); + } + return MMIO_HANDLED; +} + +void gic_handle_sgir_write(struct sgi *sgi) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + unsigned int cpu, target; + u64 cluster; + + if (sgi->routing_mode == 2) + /* Route to the caller itself */ + irqchip_set_pending(cpu_public, sgi->id); + else + for_each_cpu(cpu, this_cell()->cpu_set) { + if (sgi->routing_mode == 1) { + /* Route to all (cell) CPUs but the caller. */ + if (cpu == cpu_public->cpu_id) + continue; + } else { + target = irqchip_get_cpu_target(cpu); + cluster = irqchip_get_cluster_target(cpu); + + /* Route to target CPUs in cell */ + if ((sgi->cluster_id != cluster) || + !(sgi->targets & target)) + continue; + } + + irqchip_set_pending(public_per_cpu(cpu), sgi->id); + } +} + +static enum mmio_result gic_handle_dist_access(void *arg, + struct mmio_access *mmio) +{ + unsigned long reg = mmio->address; + enum mmio_result ret; + + switch (reg) { + case REG_RANGE(GICD_IROUTER, 1024, 8): + ret = irqchip.handle_irq_route(mmio, (reg - GICD_IROUTER) / 8); + break; + + case REG_RANGE(GICD_ITARGETSR, 1024, 1): + ret = irqchip.handle_irq_target(mmio, reg - GICD_ITARGETSR); + break; + + case REG_RANGE(GICD_ICENABLER, 32, 4): + case REG_RANGE(GICD_ISENABLER, 32, 4): + case REG_RANGE(GICD_ICPENDR, 32, 4): + case REG_RANGE(GICD_ISPENDR, 32, 4): + case REG_RANGE(GICD_ICACTIVER, 32, 4): + case REG_RANGE(GICD_ISACTIVER, 32, 4): + ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true); + break; + + case REG_RANGE(GICD_IGROUPR, 32, 4): + ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, false); + break; + + case REG_RANGE(GICD_ICFGR, 64, 4): + ret = restrict_bitmask_access(mmio, (reg & 0xff) / 4, 2, false); + break; + + case REG_RANGE(GICD_IPRIORITYR, 255, 4): + ret = restrict_bitmask_access(mmio, (reg & 0x3ff) / 4, 8, + false); + break; + + default: + ret = irqchip.handle_dist_access(mmio); + } + + return ret; +} + +void irqchip_handle_irq(void) +{ + unsigned int count_event = 1; + bool handled = false; + u32 irq_id; + + while (1) { + /* Read IAR1: set 'active' state */ + irq_id = irqchip.read_iar_irqn(); + + if (irq_id == 0x3ff) /* Spurious IRQ */ + break; + + /* Handle IRQ */ + if (is_sgi(irq_id)) { + arch_handle_sgi(irq_id, count_event); + handled = true; + } else { + isb(); + handled = arch_handle_phys_irq(irq_id, count_event); + } + count_event = 0; + + /* + * Write EOIR1: drop priority, but stay active if handled is + * false. + * This allows to not be re-interrupted by a level-triggered + * interrupt that needs handling in the guest (e.g. timer) + */ + irqchip.eoi_irq(irq_id, handled); + } +} + +bool irqchip_irq_in_cell(struct cell *cell, unsigned int irq_id) +{ + if (irq_id >= sizeof(cell->arch.irq_bitmap) * 8) + return false; + + return (cell->arch.irq_bitmap[irq_id / 32] & (1 << (irq_id % 32))) != 0; +} + +bool irqchip_has_pending_irqs(void) +{ + return irqchip.has_pending_irqs(); +} + +void irqchip_set_pending(struct public_per_cpu *cpu_public, u16 irq_id) +{ + struct pending_irqs *pending = &cpu_public->pending_irqs; + bool local_injection = (this_cpu_public() == cpu_public); + const u16 sender = this_cpu_id(); + unsigned int new_tail; + + if (sdei_available) { + irqchip_send_sgi(cpu_public->cpu_id, irq_id); + return; + } + + if (local_injection && irqchip.inject_irq(irq_id, sender) != -EBUSY) + return; + + spin_lock(&pending->lock); + + new_tail = (pending->tail + 1) % MAX_PENDING_IRQS; + + /* Queue space available? */ + if (new_tail != pending->head) { + pending->irqs[pending->tail] = irq_id; + pending->sender[pending->tail] = sender; + /* + * Make the entry content is visible before updating the tail + * index. + */ + memory_barrier(); + pending->tail = new_tail; + } + + /* + * The unlock has memory barrier semantic on ARM v7 and v8. Therefore + * the change to tail will be visible when sending SGI_INJECT later on. + */ + spin_unlock(&pending->lock); + + /* + * The list registers are full, trigger maintenance interrupt if we are + * on the target CPU. In the other case, send SGI_INJECT to the target + * CPU. + */ + if (local_injection) + irqchip.enable_maint_irq(true); + else + irqchip_send_sgi(cpu_public->cpu_id, SGI_INJECT); +} + +void irqchip_inject_pending(void) +{ + struct pending_irqs *pending = &this_cpu_public()->pending_irqs; + u16 irq_id, sender; + + while (pending->head != pending->tail) { + irq_id = pending->irqs[pending->head]; + sender = pending->sender[pending->head]; + + if (irqchip.inject_irq(irq_id, sender) == -EBUSY) { + /* + * The list registers are full, trigger maintenance + * interrupt and leave. + */ + irqchip.enable_maint_irq(true); + return; + } + + /* + * Ensure that the entry was read before updating the head + * index. + */ + memory_barrier(); + pending->head = (pending->head + 1) % MAX_PENDING_IRQS; + } + + /* + * The software interrupt queue is empty - turn off the maintenance + * interrupt. + */ + irqchip.enable_maint_irq(false); +} + +void irqchip_trigger_external_irq(u16 irq_id) +{ + /* Injection via GICD */ + mmio_write32(gicd_base + GICD_ISPENDR + (irq_id / 32) * 4, + 1 << (irq_id % 32)); +} + +void irqchip_send_sgi(unsigned int cpu_id, u16 sgi_id) +{ + struct sgi sgi; + + sgi.targets = irqchip_get_cpu_target(cpu_id); + sgi.cluster_id = irqchip_get_cluster_target(cpu_id); + sgi.routing_mode = 0; + sgi.id = sgi_id; + irqchip.send_sgi(&sgi); +} + +int irqchip_cpu_init(struct per_cpu *cpu_data) +{ + int err; + + /* Only execute once, on master CPU */ + if (!irqchip_is_init) { + switch (system_config->platform_info.arm.gic_version) { + case 2: + irqchip = gicv2_irqchip; + break; + case 3: + irqchip = gicv3_irqchip; + break; + default: + return trace_error(-EINVAL); + } + + gicd_base = paging_map_device( + system_config->platform_info.arm.gicd_base, + irqchip.gicd_size); + if (!gicd_base) + return -ENOMEM; + + err = irqchip.init(); + if (err) + return err; + + irqchip_is_init = true; + } + + return irqchip.cpu_init(cpu_data); +} + +int irqchip_get_cpu_target(unsigned int cpu_id) +{ + return irqchip.get_cpu_target(cpu_id); +} + +u64 irqchip_get_cluster_target(unsigned int cpu_id) +{ + return irqchip.get_cluster_target(cpu_id); +} + +void irqchip_cpu_reset(struct per_cpu *cpu_data) +{ + cpu_data->public.pending_irqs.head = 0; + cpu_data->public.pending_irqs.tail = 0; + + irqchip.cpu_reset(cpu_data); +} + +void irqchip_cpu_shutdown(struct public_per_cpu *cpu_public) +{ + struct pending_irqs *pending = &cpu_public->pending_irqs; + int irq_id; + + /* + * The GIC implementation must take care of only resetting the hyp + * interface if it has been initialized because this function may be + * executed during the setup phase. It returns an error if the + * initialization do not take place yet. + */ + if (irqchip.cpu_shutdown(cpu_public) < 0) + return; + + /* + * Migrate interrupts queued in the GICV. + * No locking required at this stage because no other CPU is able to + * inject anymore. + */ + do { + irq_id = irqchip.get_pending_irq(); + if (irq_id >= 0) + irqchip.inject_phys_irq(irq_id); + } while (irq_id >= 0); + + /* Migrate interrupts queued in software. */ + while (pending->head != pending->tail) { + irq_id = pending->irqs[pending->head]; + + irqchip.inject_phys_irq(irq_id); + + /* + * Ensure that the entry was read before updating the head + * index. + */ + memory_barrier(); + pending->head = (pending->head + 1) % MAX_PENDING_IRQS; + } +} + +static int irqchip_cell_init(struct cell *cell) +{ + unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq; + const struct jailhouse_irqchip *chip; + unsigned int n, pos; + int err; + + for_each_irqchip(chip, cell->config, n) { + if (chip->address != system_config->platform_info.arm.gicd_base) + continue; + if (chip->pin_base % 32 != 0 || + chip->pin_base + sizeof(chip->pin_bitmap) * 8 > + sizeof(cell->arch.irq_bitmap) * 8) + return trace_error(-EINVAL); + for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++) { + cell->arch.irq_bitmap[chip->pin_base / 32 + pos] |= + chip->pin_bitmap[pos]; + } + } + /* + * Permit direct access to all SGIs and PPIs except for those used by + * the hypervisor. + */ + cell->arch.irq_bitmap[0] = ~((1 << SGI_INJECT) | (1 << SGI_EVENT) | + (1 << mnt_irq)); + + err = irqchip.cell_init(cell); + if (err) + return err; + + mmio_region_register(cell, system_config->platform_info.arm.gicd_base, + irqchip.gicd_size, gic_handle_dist_access, NULL); + + if (cell == &root_cell) + return 0; + + for_each_irqchip(chip, cell->config, n) { + if (chip->address != system_config->platform_info.arm.gicd_base) + continue; + for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++) + root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] &= + ~chip->pin_bitmap[pos]; + } + + return 0; +} + +void irqchip_cell_reset(struct cell *cell) +{ + unsigned int n; + u32 mask; + + /* mask and deactivate all SPIs belonging to the cell */ + for (n = 1; n < ARRAY_SIZE(cell->arch.irq_bitmap); n++) { + mask = cell->arch.irq_bitmap[n]; + mmio_write32(gicd_base + GICD_ICENABLER + n * 4, mask); + mmio_write32(gicd_base + GICD_ICACTIVER + n * 4, mask); + } +} + +static void irqchip_cell_exit(struct cell *cell) +{ + const struct jailhouse_irqchip *chip; + unsigned int n, pos; + + /* might be called by arch_shutdown while rolling back + * a failed setup */ + if (!irqchip_is_init) + return; + + /* ensure all SPIs of the cell are masked and deactivated */ + irqchip_cell_reset(cell); + + /* set all pins of the old cell in the root cell */ + for_each_irqchip(chip, cell->config, n) { + if (chip->address != system_config->platform_info.arm.gicd_base) + continue; + for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++) + root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] |= + chip->pin_bitmap[pos]; + } + + /* mask out pins again that actually didn't belong to the root cell */ + for_each_irqchip(chip, root_cell.config, n) { + if (chip->address != system_config->platform_info.arm.gicd_base) + continue; + for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++) + root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] &= + chip->pin_bitmap[pos]; + } + + if (irqchip.cell_exit) + irqchip.cell_exit(cell); +} + +void irqchip_config_commit(struct cell *cell_added_removed) +{ + unsigned int n; + + if (!cell_added_removed) + return; + + for (n = 32; n < sizeof(cell_added_removed->arch.irq_bitmap) * 8; n++) { + if (irqchip_irq_in_cell(cell_added_removed, n) && + (cell_added_removed != &root_cell)) + irqchip.adjust_irq_target(cell_added_removed, n); + + if (irqchip_irq_in_cell(&root_cell, n)) + irqchip.adjust_irq_target(&root_cell, n); + } +} + +static unsigned int irqchip_mmio_count_regions(struct cell *cell) +{ + unsigned int regions = 1; /* GICD */ + + if (system_config->platform_info.arm.gic_version >= 3) + /* 1 GICR per CPU */ + regions += hypervisor_header.online_cpus; + + return regions; +} + +static int irqchip_init(void) +{ + if (sdei_available) + printk("Using SDEI-based management interrupt\n"); + + /* Setup the SPI bitmap */ + return irqchip_cell_init(&root_cell); +} + +DEFINE_UNIT_SHUTDOWN_STUB(irqchip); +DEFINE_UNIT(irqchip, "irqchip"); diff --git a/hypervisor/arch/arm-common/ivshmem.c b/hypervisor/arch/arm-common/ivshmem.c new file mode 100644 index 0000000000000000000000000000000000000000..9f0a11dc8dc1b30a8eb94f8a51b1355406e993e6 --- /dev/null +++ b/hypervisor/arch/arm-common/ivshmem.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016-2019 + * + * Author: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +void arch_ivshmem_trigger_interrupt(struct ivshmem_endpoint *ive, + unsigned int vector) +{ + unsigned int irq_id = ive->irq_cache.id[vector]; + + if (irq_id) { + /* + * Ensure that all data written by the sending guest is visible + * to the target before triggering the interrupt. + */ + memory_barrier(); + + irqchip_trigger_external_irq(irq_id); + } +} + +int arch_ivshmem_update_msix(struct ivshmem_endpoint *ive, unsigned int vector, + bool enabled) +{ + struct pci_device *device = ive->device; + unsigned int irq_id = 0; + + if (enabled) { + /* FIXME: validate MSI-X target address */ + irq_id = device->msix_vectors[vector].data; + if (irq_id < 32 || !irqchip_irq_in_cell(device->cell, irq_id)) + return -EPERM; + } + + /* + * Lock used as barrier, ensuring all interrupts triggered after return + * use the new setting. + */ + spin_lock(&ive->irq_lock); + ive->irq_cache.id[vector] = irq_id; + spin_unlock(&ive->irq_lock); + + return 0; +} + +void arch_ivshmem_update_intx(struct ivshmem_endpoint *ive, bool enabled) +{ + u8 pin = ive->cspace[PCI_CFG_INT/4] >> 8; + struct pci_device *device = ive->device; + + /* + * Lock used as barrier, ensuring all interrupts triggered after return + * use the new setting. + */ + spin_lock(&ive->irq_lock); + ive->irq_cache.id[0] = enabled ? + (32 + device->cell->config->vpci_irq_base + pin - 1) : 0; + spin_unlock(&ive->irq_lock); +} diff --git a/hypervisor/arch/arm-common/lib.c b/hypervisor/arch/arm-common/lib.c new file mode 100644 index 0000000000000000000000000000000000000000..12a4d811617eaee6286bfb50b5c230b116115928 --- /dev/null +++ b/hypervisor/arch/arm-common/lib.c @@ -0,0 +1,51 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +unsigned long phys_processor_id(void) +{ + unsigned long mpidr; + + arm_read_sysreg(MPIDR_EL1, mpidr); + return mpidr & MPIDR_CPUID_MASK; +} + +unsigned int arm_cpu_by_mpidr(struct cell *cell, unsigned long mpidr) +{ + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + if (mpidr == (public_per_cpu(cpu)->mpidr & MPIDR_CPUID_MASK)) + return cpu; + + return INVALID_CPU_ID; +} + +unsigned int arm_cpu_by_virt_cpuid( struct cell *cell, unsigned long virt_cpuid ) +{ + unsigned int cpu; + unsigned int cpuid = 0; + + for_each_cpu(cpu, cell->cpu_set) + { + if( cpuid == virt_cpuid ) + { + return cpu; + } + cpuid++; + } + return INVALID_CPU_ID; +} diff --git a/hypervisor/arch/arm-common/mmu_cell.c b/hypervisor/arch/arm-common/mmu_cell.c new file mode 100644 index 0000000000000000000000000000000000000000..7f9bb10a39e548bad66bdbe55f4df49314ddde0d --- /dev/null +++ b/hypervisor/arch/arm-common/mmu_cell.c @@ -0,0 +1,149 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +int arch_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + u64 phys_start = mem->phys_start; + unsigned long access_flags = PTE_FLAG_VALID | PTE_ACCESS_FLAG; + unsigned long paging_flags = PAGING_COHERENT | PAGING_HUGE; + int err = 0; + + if (mem->flags & JAILHOUSE_MEM_READ) + access_flags |= S2_PTE_ACCESS_RO; + if (mem->flags & JAILHOUSE_MEM_WRITE) + access_flags |= S2_PTE_ACCESS_WO; + if (mem->flags & JAILHOUSE_MEM_IO) + access_flags |= S2_PTE_FLAG_DEVICE; + else + access_flags |= S2_PTE_FLAG_NORMAL; + if (mem->flags & JAILHOUSE_MEM_COMM_REGION) + phys_start = paging_hvirt2phys(&cell->comm_page); + /* + if (!(mem->flags & JAILHOUSE_MEM_EXECUTE)) + flags |= S2_PAGE_ACCESS_XN; + */ + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_HUGE; + + err = iommu_map_memory_region(cell, mem); + if (err) + return err; + + err = paging_create(&cell->arch.mm, phys_start, mem->size, + mem->virt_start, access_flags, paging_flags); + if (err) + iommu_unmap_memory_region(cell, mem); + + return err; +} + +int arch_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + int err = 0; + + err = iommu_unmap_memory_region(cell, mem); + if (err) + return err; + + return paging_destroy(&cell->arch.mm, mem->virt_start, mem->size, + PAGING_COHERENT); +} + +unsigned long arch_paging_gphys2phys(unsigned long gphys, unsigned long flags) +{ + /* Translate IPA->PA */ + return paging_virt2phys(&this_cell()->arch.mm, gphys, flags); +} + +void arm_cell_dcaches_flush(struct cell *cell, enum dcache_flush flush) +{ + unsigned long region_addr, region_size, size; + struct jailhouse_memory const *mem; + unsigned int n; + + for_each_mem_region(mem, cell->config, n) { + if (mem->flags & (JAILHOUSE_MEM_IO | JAILHOUSE_MEM_COMM_REGION)) + continue; + + region_addr = mem->phys_start; + region_size = mem->size; + + while (region_size > 0) { + size = MIN(region_size, + NUM_TEMPORARY_PAGES * PAGE_SIZE); + + /* cannot fail, mapping area is preallocated */ + paging_create(&this_cpu_data()->pg_structs, region_addr, + size, TEMPORARY_MAPPING_BASE, + PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + + arm_dcaches_flush((void *)TEMPORARY_MAPPING_BASE, size, + flush); + + region_addr += size; + region_size -= size; + } + } + + /* ensure completion of the flush */ + dmb(ish); +} + +int arm_paging_cell_init(struct cell *cell) +{ + if (cell->config->id > 0xff) + return trace_error(-E2BIG); + + cell->arch.mm.root_paging = cell_paging; + cell->arch.mm.root_table = + page_alloc_aligned(&mem_pool, CELL_ROOT_PT_PAGES); + + if (!cell->arch.mm.root_table) + return -ENOMEM; + + return 0; +} + +void arm_paging_cell_destroy(struct cell *cell) +{ + page_free(&mem_pool, cell->arch.mm.root_table, CELL_ROOT_PT_PAGES); +} + +void arm_paging_vcpu_init(struct paging_structures *pg_structs) +{ + unsigned long cell_table = paging_hvirt2phys(pg_structs->root_table); + u64 vttbr = 0; + + vttbr |= (u64)this_cell()->config->id << VTTBR_VMID_SHIFT; + vttbr |= (u64)(cell_table & TTBR_MASK); + + arm_write_sysreg(VTTBR_EL2, vttbr); + + /* Ensure that the new VMID is present before flushing the caches */ + isb(); + /* + * At initialisation, arch_config_commit does not act on other CPUs, + * since they register themselves to the root cpu_set afterwards. It + * means that this unconditionnal flush is redundant on master CPU. + */ + arm_paging_vcpu_flush_tlbs(); +} diff --git a/hypervisor/arch/arm-common/paging.c b/hypervisor/arch/arm-common/paging.c new file mode 100644 index 0000000000000000000000000000000000000000..e2bc374b34c64263ed58c71ee073347e8ac31000 --- /dev/null +++ b/hypervisor/arch/arm-common/paging.c @@ -0,0 +1,230 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +unsigned int cpu_parange = 0; + +static bool arm_entry_valid(pt_entry_t entry, unsigned long flags) +{ + // FIXME: validate flags! + return *entry & 1; +} + +static unsigned long arm_get_entry_flags(pt_entry_t entry) +{ + /* Upper flags (contiguous hint and XN are currently ignored */ + return *entry & 0xfff; +} + +static void arm_clear_entry(pt_entry_t entry) +{ + *entry = 0; +} + +static bool arm_page_table_empty(page_table_t page_table) +{ + unsigned long n; + pt_entry_t pte; + + for (n = 0, pte = page_table; n < PAGE_SIZE / sizeof(u64); n++, pte++) + if (arm_entry_valid(pte, PTE_FLAG_VALID)) + return false; + return true; +} + +#if MAX_PAGE_TABLE_LEVELS > 3 +static pt_entry_t arm_get_l0_entry(page_table_t page_table, unsigned long virt) +{ + return &page_table[(virt & L0_VADDR_MASK) >> 39]; +} + +static unsigned long arm_get_l0_phys(pt_entry_t pte, unsigned long virt) +{ + if ((*pte & PTE_TABLE_FLAGS) == PTE_TABLE_FLAGS) + return INVALID_PHYS_ADDR; + return (*pte & PTE_L0_BLOCK_ADDR_MASK) | (virt & BLOCK_512G_VADDR_MASK); +} +#endif + +#if MAX_PAGE_TABLE_LEVELS > 2 +static pt_entry_t arm_get_l1_entry(page_table_t page_table, unsigned long virt) +{ + return &page_table[(virt & L1_VADDR_MASK) >> 30]; +} + +static void arm_set_l1_block(pt_entry_t pte, unsigned long phys, unsigned long flags) +{ + *pte = ((u64)phys & PTE_L1_BLOCK_ADDR_MASK) | flags; +} + +static unsigned long arm_get_l1_phys(pt_entry_t pte, unsigned long virt) +{ + if ((*pte & PTE_TABLE_FLAGS) == PTE_TABLE_FLAGS) + return INVALID_PHYS_ADDR; + return (*pte & PTE_L1_BLOCK_ADDR_MASK) | (virt & BLOCK_1G_VADDR_MASK); +} +#endif + +static pt_entry_t arm_get_l1_alt_entry(page_table_t page_table, unsigned long virt) +{ + return &page_table[(virt & BIT_MASK(48,30)) >> 30]; +} + +static unsigned long arm_get_l1_alt_phys(pt_entry_t pte, unsigned long virt) +{ + if ((*pte & PTE_TABLE_FLAGS) == PTE_TABLE_FLAGS) + return INVALID_PHYS_ADDR; + return (*pte & BIT_MASK(48,30)) | (virt & BIT_MASK(29,0)); +} + +static pt_entry_t arm_get_l2_entry(page_table_t page_table, unsigned long virt) +{ + return &page_table[(virt & L2_VADDR_MASK) >> 21]; +} + +static pt_entry_t arm_get_l3_entry(page_table_t page_table, unsigned long virt) +{ + return &page_table[(virt & L3_VADDR_MASK) >> 12]; +} + +static void arm_set_l2_block(pt_entry_t pte, unsigned long phys, unsigned long flags) +{ + *pte = ((u64)phys & PTE_L2_BLOCK_ADDR_MASK) | flags; +} + +static void arm_set_l3_page(pt_entry_t pte, unsigned long phys, unsigned long flags) +{ + *pte = ((u64)phys & PTE_PAGE_ADDR_MASK) | flags | PTE_FLAG_TERMINAL; +} + +static void arm_set_l12_table(pt_entry_t pte, unsigned long next_pt) +{ + *pte = ((u64)next_pt & PTE_TABLE_ADDR_MASK) | PTE_TABLE_FLAGS; +} + +static unsigned long arm_get_l12_table(pt_entry_t pte) +{ + return *pte & PTE_TABLE_ADDR_MASK; +} + +static unsigned long arm_get_l2_phys(pt_entry_t pte, unsigned long virt) +{ + if ((*pte & PTE_TABLE_FLAGS) == PTE_TABLE_FLAGS) + return INVALID_PHYS_ADDR; + return (*pte & PTE_L2_BLOCK_ADDR_MASK) | (virt & BLOCK_2M_VADDR_MASK); +} + +static unsigned long arm_get_l3_phys(pt_entry_t pte, unsigned long virt) +{ + if (!(*pte & PTE_FLAG_TERMINAL)) + return INVALID_PHYS_ADDR; + return (*pte & PTE_PAGE_ADDR_MASK) | (virt & PAGE_OFFS_MASK); +} + +#define ARM_PAGING_COMMON \ + .entry_valid = arm_entry_valid, \ + .get_flags = arm_get_entry_flags, \ + .clear_entry = arm_clear_entry, \ + .page_table_empty = arm_page_table_empty, + +static const struct paging arm_paging[] = { +#if MAX_PAGE_TABLE_LEVELS > 3 + { + ARM_PAGING_COMMON + /* No block entries for level 0, so no need to set page_size */ + .get_entry = arm_get_l0_entry, + .get_phys = arm_get_l0_phys, + + .set_next_pt = arm_set_l12_table, + .get_next_pt = arm_get_l12_table, + }, +#endif +#if MAX_PAGE_TABLE_LEVELS > 2 + { + ARM_PAGING_COMMON + /* Block entry: 1GB */ + .page_size = 1024 * 1024 * 1024, + .get_entry = arm_get_l1_entry, + .set_terminal = arm_set_l1_block, + .get_phys = arm_get_l1_phys, + + .set_next_pt = arm_set_l12_table, + .get_next_pt = arm_get_l12_table, + }, +#endif + { + ARM_PAGING_COMMON + /* Block entry: 2MB */ + .page_size = 2 * 1024 * 1024, + .get_entry = arm_get_l2_entry, + .set_terminal = arm_set_l2_block, + .get_phys = arm_get_l2_phys, + + .set_next_pt = arm_set_l12_table, + .get_next_pt = arm_get_l12_table, + }, + { + ARM_PAGING_COMMON + /* Page entry: 4kB */ + .page_size = 4 * 1024, + .get_entry = arm_get_l3_entry, + .set_terminal = arm_set_l3_page, + .get_phys = arm_get_l3_phys, + } +}; + +static const struct paging arm_s2_paging_alt[] = { + { + ARM_PAGING_COMMON + .get_entry = arm_get_l1_alt_entry, + .get_phys = arm_get_l1_alt_phys, + + .set_next_pt = arm_set_l12_table, + .get_next_pt = arm_get_l12_table, + }, + { + ARM_PAGING_COMMON + /* Block entry: 2MB */ + .page_size = 2 * 1024 * 1024, + .get_entry = arm_get_l2_entry, + .set_terminal = arm_set_l2_block, + .get_phys = arm_get_l2_phys, + + .set_next_pt = arm_set_l12_table, + .get_next_pt = arm_get_l12_table, + }, + { + ARM_PAGING_COMMON + /* Page entry: 4kB */ + .page_size = 4 * 1024, + .get_entry = arm_get_l3_entry, + .set_terminal = arm_set_l3_page, + .get_phys = arm_get_l3_phys, + } +}; + +const struct paging *cell_paging; + +void arch_paging_init(void) +{ + cpu_parange = get_cpu_parange(); + + if (cpu_parange < 44) + /* 4 level page tables not supported for stage 2. + * We need to use multiple consecutive pages for L1 */ + cell_paging = arm_s2_paging_alt; + else + cell_paging = arm_paging; + + hv_paging_structs.root_paging = arm_paging; +} diff --git a/hypervisor/arch/arm-common/pci.c b/hypervisor/arch/arm-common/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..8daccee54c56d5be7ac0ecd61345c9873d91904c --- /dev/null +++ b/hypervisor/arch/arm-common/pci.c @@ -0,0 +1,66 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +u32 arch_pci_read_config(u16 bdf, u16 address, unsigned int size) +{ + return -1; +} + +void arch_pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size) +{ +} + +int arch_pci_add_physical_device(struct cell *cell, struct pci_device *device) +{ + return 0; +} + +void arch_pci_remove_physical_device(struct pci_device *device) +{ +} + +void arch_pci_set_suppress_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap, + bool suppress) +{ +} + +int arch_pci_update_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + const struct jailhouse_pci_device *info = device->info; + unsigned int n; + + /* + * NOTE: We don't have interrupt remapping yet. So we write the values + * the cell passed without modifications. Probably not safe on all + * platforms. + */ + for (n = 1; n < (info->msi_64bits ? 4 : 3); n++) + pci_write_config(info->bdf, cap->start + n * 4, + device->msi_registers.raw[n], 4); + + return 0; +} + +int arch_pci_update_msix_vector(struct pci_device *device, unsigned int index) +{ + /* NOTE: See arch_pci_update_msi. */ + mmio_write64_split(&device->msix_table[index].address, + device->msix_vectors[index].address); + mmio_write32(&device->msix_table[index].data, + device->msix_vectors[index].data); + return 0; +} diff --git a/hypervisor/arch/arm-common/psci.c b/hypervisor/arch/arm-common/psci.c new file mode 100644 index 0000000000000000000000000000000000000000..ab4124b03fce53b160d082a6c7f8f100056e89b0 --- /dev/null +++ b/hypervisor/arch/arm-common/psci.c @@ -0,0 +1,150 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +static long psci_emulate_cpu_on(struct trap_context *ctx) +{ + u64 mask = SMCCC_IS_CONV_64(ctx->regs[0]) ? (u64)-1L : (u32)-1; + struct cell *cell = this_cell(); + struct public_per_cpu *target_data; + bool kick_cpu = false; + unsigned int cpu; + long result; + + if( !cell->config->use_virt_cpuid ){ + cpu = arm_cpu_by_mpidr(cell, ctx->regs[1] & mask); + } + else{ + cpu = arm_cpu_by_virt_cpuid(cell, ctx->regs[1] & mask); + } + + if (cpu == INVALID_CPU_ID) + /* Virtual id not in set */ + return PSCI_DENIED; + + target_data = public_per_cpu(cpu); + + spin_lock(&target_data->control_lock); + + if (target_data->wait_for_poweron) { + target_data->cpu_on_entry = ctx->regs[2] & mask; + target_data->cpu_on_context = ctx->regs[3] & mask; + target_data->reset = true; + kick_cpu = true; + + result = PSCI_SUCCESS; + } else { + result = PSCI_ALREADY_ON; + } + + /* + * The unlock has memory barrier semantic on ARM v7 and v8. Therefore + * the changes to target_data will be visible when sending the kick + * below. + */ + spin_unlock(&target_data->control_lock); + + if (kick_cpu) + arch_send_event(target_data); + + return result; +} + +static long psci_emulate_affinity_info(struct trap_context *ctx) +{ + unsigned int cpu = 0; + struct cell *cell = this_cell(); + if( !cell->config->use_virt_cpuid ){ + cpu = arm_cpu_by_mpidr(cell, ctx->regs[1]); + } else { + cpu = arm_cpu_by_virt_cpuid(cell, ctx->regs[1]); + } + + if (cpu == INVALID_CPU_ID) + /* Virtual id not in set */ + return PSCI_DENIED; + + return public_per_cpu(cpu)->wait_for_poweron ? + PSCI_CPU_IS_OFF : PSCI_CPU_IS_ON; +} + +static long psci_emulate_features_info(struct trap_context *ctx) +{ + switch (ctx->regs[1]) { + case PSCI_0_2_FN_VERSION: + case PSCI_0_2_FN_CPU_SUSPEND: + case PSCI_0_2_FN64_CPU_SUSPEND: + case PSCI_0_2_FN_CPU_OFF: + case PSCI_0_2_FN_CPU_ON: + case PSCI_0_2_FN64_CPU_ON: + case PSCI_0_2_FN_AFFINITY_INFO: + case PSCI_0_2_FN64_AFFINITY_INFO: + case PSCI_1_0_FN_FEATURES: + case SMCCC_VERSION: + return PSCI_SUCCESS; + + default: + return PSCI_NOT_SUPPORTED; + } +} + +long psci_dispatch(struct trap_context *ctx) +{ + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_PSCI]++; + + switch (ctx->regs[0]) { + case PSCI_0_2_FN_VERSION: + return PSCI_VERSION(1, 1); + + case PSCI_0_2_FN_CPU_SUSPEND: + case PSCI_0_2_FN64_CPU_SUSPEND: + /* + * Note: We ignore the power_state parameter and always perform + * a context-preserving suspend. This is legal according to + * PSCI. + */ + if (sdei_available) { + arm_cpu_passthru_suspend(); + } else if (!irqchip_has_pending_irqs()) { + asm volatile("wfi" : : : "memory"); + irqchip_handle_irq(); + } + return PSCI_SUCCESS; + + case PSCI_0_2_FN_CPU_OFF: + case PSCI_CPU_OFF_V0_1_UBOOT: + arm_cpu_park(); + return 0; /* never returned to the PSCI caller */ + + case PSCI_0_2_FN_CPU_ON: + case PSCI_0_2_FN64_CPU_ON: + case PSCI_CPU_ON_V0_1_UBOOT: + return psci_emulate_cpu_on(ctx); + + case PSCI_0_2_FN_AFFINITY_INFO: + case PSCI_0_2_FN64_AFFINITY_INFO: + return psci_emulate_affinity_info(ctx); + + case PSCI_1_0_FN_FEATURES: + return psci_emulate_features_info(ctx); + + default: + return PSCI_NOT_SUPPORTED; + } +} diff --git a/hypervisor/arch/arm-common/setup.c b/hypervisor/arch/arm-common/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..9ff03250291413141ad9b12a868a36f6f8f7a548 --- /dev/null +++ b/hypervisor/arch/arm-common/setup.c @@ -0,0 +1,54 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +static u32 __attribute__((aligned(PAGE_SIZE))) parking_code[PAGE_SIZE / 4] = { + ARM_PARKING_CODE +}; + +int arm_init_early(void) +{ + int err; + + parking_pt.root_paging = cell_paging; + + err = paging_create(&parking_pt, paging_hvirt2phys(parking_code), + PAGE_SIZE, 0, + (PTE_FLAG_VALID | PTE_ACCESS_FLAG | + S2_PTE_ACCESS_RO | S2_PTE_FLAG_NORMAL), + PAGING_COHERENT | PAGING_NO_HUGE); + if (err) + return err; + + return arm_paging_cell_init(&root_cell); +} + +int arm_cpu_init(struct per_cpu *cpu_data) +{ + int err; + + cpu_data->public.mpidr = phys_processor_id(); + + arm_write_sysreg(VTCR_EL2, VTCR_CELL); + arm_paging_vcpu_init(&root_cell.arch.mm); + + err = smccc_discover(); + if (err) + return err; + + return irqchip_cpu_init(cpu_data); +} diff --git a/hypervisor/arch/arm-common/smccc.c b/hypervisor/arch/arm-common/smccc.c new file mode 100644 index 0000000000000000000000000000000000000000..65639b59c703f08a5a33fba38425d7d5081fceb4 --- /dev/null +++ b/hypervisor/arch/arm-common/smccc.c @@ -0,0 +1,145 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +bool sdei_available; + +static bool sdei_probed __attribute__((__unused__)); + +int smccc_discover(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + long ret; + + cpu_data->smccc_feat_workaround_1 = ARM_SMCCC_NOT_SUPPORTED; + cpu_data->smccc_feat_workaround_2 = ARM_SMCCC_NOT_SUPPORTED; + + ret = smc(PSCI_0_2_FN_VERSION); + + /* We need >=PSCIv1.0 for SMCCC. Against the spec, U-Boot may also + * return a negative error code. */ + if (ret < 0 || PSCI_VERSION_MAJOR(ret) < 1) + return sdei_available ? trace_error(-EIO) : 0; + + /* Check if PSCI supports SMCCC version call */ + ret = smc_arg1(PSCI_1_0_FN_FEATURES, SMCCC_VERSION); + if (ret != ARM_SMCCC_SUCCESS) + return sdei_available ? trace_error(-EIO) : 0; + +#ifdef __aarch64__ + /* Check if we have SDEI (ARMv8 only) */ + ret = smc(SDEI_VERSION); + if (ret >= ARM_SMCCC_VERSION_1_0) { + if (sdei_probed && !sdei_available) + return trace_error(-EIO); + sdei_available = true; + } + sdei_probed = true; +#endif + + /* We need to have at least SMCCC v1.1 */ + ret = smc(SMCCC_VERSION); + if (ret < ARM_SMCCC_VERSION_1_1) + return 0; + + /* check if SMCCC_ARCH_FEATURES is actually available */ + ret = smc_arg1(SMCCC_ARCH_FEATURES, SMCCC_ARCH_FEATURES); + if (ret != ARM_SMCCC_SUCCESS) + return 0; + + cpu_data->smccc_feat_workaround_1 = + smc_arg1(SMCCC_ARCH_FEATURES, SMCCC_ARCH_WORKAROUND_1); + + cpu_data->smccc_feat_workaround_2 = + smc_arg1(SMCCC_ARCH_FEATURES, SMCCC_ARCH_WORKAROUND_2); + + return 0; +} + +static inline long handle_arch_features(u32 id) +{ + switch (id) { + case SMCCC_ARCH_FEATURES: + return ARM_SMCCC_SUCCESS; + + case SMCCC_ARCH_WORKAROUND_1: + return this_cpu_data()->smccc_feat_workaround_1; + case SMCCC_ARCH_WORKAROUND_2: + return this_cpu_data()->smccc_feat_workaround_2; + + default: + return ARM_SMCCC_NOT_SUPPORTED; + } +} + +static enum trap_return handle_arch(struct trap_context *ctx) +{ + u32 function_id = ctx->regs[0]; + unsigned long *ret = &ctx->regs[0]; + + switch (function_id) { + case SMCCC_VERSION: + *ret = ARM_SMCCC_VERSION_1_1; + break; + + case SMCCC_ARCH_FEATURES: + *ret = handle_arch_features(ctx->regs[1]); + break; + + case SMCCC_ARCH_WORKAROUND_2: + if (this_cpu_data()->smccc_feat_workaround_2 < 0) + return ARM_SMCCC_NOT_SUPPORTED; + return smc_arg1(SMCCC_ARCH_WORKAROUND_2, ctx->regs[1]); + + default: + panic_printk("Unhandled SMC arch trap %lx\n", *ret); + return TRAP_UNHANDLED; + } + + return TRAP_HANDLED; +} + +enum trap_return handle_smc(struct trap_context *ctx) +{ + unsigned long *regs = ctx->regs; + enum trap_return ret = TRAP_HANDLED; + u32 *stats = this_cpu_public()->stats; + + switch (SMCCC_GET_OWNER(regs[0])) { + case ARM_SMCCC_OWNER_ARCH: + stats[JAILHOUSE_CPU_STAT_VMEXITS_SMCCC]++; + ret = handle_arch(ctx); + break; + + case ARM_SMCCC_OWNER_SIP: + stats[JAILHOUSE_CPU_STAT_VMEXITS_SMCCC]++; + regs[0] = ARM_SMCCC_NOT_SUPPORTED; + break; + + case ARM_SMCCC_OWNER_STANDARD: + regs[0] = psci_dispatch(ctx); + break; + + default: + ret = TRAP_UNHANDLED; + } + + arch_skip_instruction(ctx); + + return ret; +} diff --git a/hypervisor/arch/arm-common/uart-hscif.c b/hypervisor/arch/arm-common/uart-hscif.c new file mode 100644 index 0000000000000000000000000000000000000000..4eb75341afd9aacf4b24f4ab20c72e5b1ba9c260 --- /dev/null +++ b/hypervisor/arch/arm-common/uart-hscif.c @@ -0,0 +1,66 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define HSCIF_HSBRR 0x04 +#define HSCIF_HSSCR 0x08 +#define HSCIF_HSFTDR 0x0C +#define HSCIF_HSFSR 0x10 +#define HSCIF_HSTTRGR 0x58 + +#define HSCIF_HSSCR_RE 0x0010 +#define HSCIF_HSSCR_TE 0x0020 + +#define HSCIF_HSFSR_TDFE 0x0020 +#define HSCIF_HSFSR_TEND 0x0040 + +#define HSCIF_FIFO_SIZE 128 + +static void uart_init(struct uart_chip *chip) +{ + u16 hsscr; + + if (chip->debug_console->divider) { + hsscr = mmio_read16(chip->virt_base + HSCIF_HSSCR); + mmio_write16(chip->virt_base + HSCIF_HSSCR, + hsscr & ~(HSCIF_HSSCR_TE | HSCIF_HSSCR_RE)); + mmio_write8(chip->virt_base + HSCIF_HSBRR, + chip->debug_console->divider); + mmio_write16(chip->virt_base + HSCIF_HSTTRGR, + HSCIF_FIFO_SIZE / 2); + mmio_write16(chip->virt_base + HSCIF_HSSCR, + hsscr | HSCIF_HSSCR_TE); + } +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read16(chip->virt_base + HSCIF_HSFSR) & + HSCIF_HSFSR_TDFE); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write8(chip->virt_base + HSCIF_HSFTDR, c); + mmio_write16(chip->virt_base + HSCIF_HSFSR, + mmio_read16(chip->virt_base + HSCIF_HSFSR) & + ~(HSCIF_HSFSR_TDFE | HSCIF_HSFSR_TEND)); +} + +struct uart_chip uart_hscif_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-imx-lpuart.c b/hypervisor/arch/arm-common/uart-imx-lpuart.c new file mode 100644 index 0000000000000000000000000000000000000000..29943de7ba3c7abe426a5ec095ba59565a8a1c6f --- /dev/null +++ b/hypervisor/arch/arm-common/uart-imx-lpuart.c @@ -0,0 +1,38 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright 2018 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define UART_DATA 0x1c +#define UART_STAT 0x14 +#define STAT_TDRE (1 << 23) + +static void uart_init(struct uart_chip *chip) +{ +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->virt_base + UART_STAT) & STAT_TDRE); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write32(chip->virt_base + UART_DATA, c); +} + +struct uart_chip uart_imx_lpuart_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-imx.c b/hypervisor/arch/arm-common/uart-imx.c new file mode 100644 index 0000000000000000000000000000000000000000..b6fc27eea8935bf5fa6beb3caf3a92d983d90d0c --- /dev/null +++ b/hypervisor/arch/arm-common/uart-imx.c @@ -0,0 +1,48 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright 2017 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define UTS 0xb4 +#define UTXD 0x40 +#define UCR1 0x80 +#define UCR1_UARTEN (1<<0) +#define UTS_TXEMPTY (1 << 6) + +static void uart_init(struct uart_chip *chip) +{ + /* Initialization currently done by Linux */ +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->virt_base + UTS) & UTS_TXEMPTY); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + /* + * When Jailhouse sharing the same uart with root cell linux, + * the uart maybe disabled by linux, so add a check to avoid + * hardware exceptions + */ + if (!(mmio_read32(chip->virt_base + UCR1) & UCR1_UARTEN)) + return; + mmio_write32(chip->virt_base + UTXD, c); +} + +struct uart_chip uart_imx_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-mvebu.c b/hypervisor/arch/arm-common/uart-mvebu.c new file mode 100644 index 0000000000000000000000000000000000000000..9602ea2cbc6f4e8560d5df34bd01a80fa686451d --- /dev/null +++ b/hypervisor/arch/arm-common/uart-mvebu.c @@ -0,0 +1,38 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define UART_TSH 0x4 +#define UART_STAT 0xc +#define UART_STAT_TX_FULL (1 << 11) + +static void uart_init(struct uart_chip *chip) +{ +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !!(mmio_read32(chip->virt_base + UART_STAT) & UART_STAT_TX_FULL); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write32(chip->virt_base + UART_TSH, c); +} + +struct uart_chip uart_mvebu_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-pl011.c b/hypervisor/arch/arm-common/uart-pl011.c new file mode 100644 index 0000000000000000000000000000000000000000..68e8f857310eceb2a9bb4ae74e0ff8423c49b0e0 --- /dev/null +++ b/hypervisor/arch/arm-common/uart-pl011.c @@ -0,0 +1,68 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define UART_CLK 24000000 + +#define UARTDR 0x00 +#define UARTFR 0x18 +#define UARTIBRD 0x24 +#define UARTLCR_H 0x2c +#define UARTCR 0x30 + +#define UARTFR_TXFF (1 << 5) +#define UARTFR_BUSY (1 << 3) + +#define UARTCR_Out2 (1 << 13) +#define UARTCR_Out1 (1 << 12) +#define UARTCR_RXE (1 << 9) +#define UARTCR_TXE (1 << 8) +#define UARTCR_EN (1 << 0) + +#define UARTLCR_H_WLEN (3 << 5) + +static void uart_init(struct uart_chip *chip) +{ + unsigned int divider = chip->debug_console->divider; + void *base = chip->virt_base; + + if (divider) { + mmio_write16(base + UARTCR, 0); + while (mmio_read8(base + UARTFR) & UARTFR_BUSY) + cpu_relax(); + mmio_write16(base + UARTIBRD, divider); + mmio_write8(base + UARTLCR_H, UARTLCR_H_WLEN); + mmio_write16(base + UARTCR, UARTCR_EN | UARTCR_TXE | + UARTCR_Out1 | UARTCR_Out2); + } +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + /* FIFO full or busy */ + return (mmio_read32(chip->virt_base + UARTFR) & + (UARTFR_TXFF | UARTFR_BUSY)) != 0; +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write32(chip->virt_base + UARTDR, c); +} + +struct uart_chip uart_pl011_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-scif.c b/hypervisor/arch/arm-common/uart-scif.c new file mode 100644 index 0000000000000000000000000000000000000000..e3e3372d28101036fb3a2161fccf8720c5152679 --- /dev/null +++ b/hypervisor/arch/arm-common/uart-scif.c @@ -0,0 +1,44 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2022 Renesas Electronics Corp. + * + * Authors: + * Lad Prabhakar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define SCIF_SCFTDR 0x0c /* Transmit FIFO data register */ +#define SCIF_SCFSR 0x10 /* Serial status register */ +#define SCIF_SCFSR_TDFE 0x20 +#define SCIF_SCFSR_TEND 0x40 + +static void uart_init(struct uart_chip *chip) +{ +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return (!((SCIF_SCFSR_TDFE | SCIF_SCFSR_TEND) & + mmio_read16(chip->virt_base + SCIF_SCFSR))); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write8(chip->virt_base + SCIF_SCFTDR, c); + mmio_write16(chip->virt_base + SCIF_SCFSR, + mmio_read16(chip->virt_base + SCIF_SCFSR) & + ~(SCIF_SCFSR_TDFE | SCIF_SCFSR_TEND)); +} + +struct uart_chip uart_scif_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-scifa.c b/hypervisor/arch/arm-common/uart-scifa.c new file mode 100644 index 0000000000000000000000000000000000000000..7d0f8cda8f3c535f5f251d2a71dbe47bae2fc143 --- /dev/null +++ b/hypervisor/arch/arm-common/uart-scifa.c @@ -0,0 +1,67 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) emtrion GmbH, 2018 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define SCIFA_SCABRR 0x04 +#define SCIFA_SCASCR 0x08 +#define SCIFA_SCASSR 0x14 +#define SCIFA_SCAFCR 0x18 +#define SCIFA_SCAFTDR 0x20 + +#define SCIFA_SCASCR_RE 0x0010 +#define SCIFA_SCASCR_TE 0x0020 + +#define SCIFA_SCASSR_TDFE 0x0020 +#define SCIFA_SCASSR_TEND 0x0040 + +#define SCIFA_FIFO_SIZE 64 +#define SCIFA_TTRG_32BYTES 0 + +static void uart_init(struct uart_chip *chip) +{ + u16 scascr; + + if (chip->debug_console->divider) { + scascr = mmio_read16(chip->virt_base + SCIFA_SCASCR); + mmio_write16(chip->virt_base + SCIFA_SCASCR, + scascr & ~(SCIFA_SCASCR_TE | SCIFA_SCASCR_RE)); + mmio_write8(chip->virt_base + SCIFA_SCABRR, + chip->debug_console->divider); + mmio_write16(chip->virt_base + SCIFA_SCAFCR, + SCIFA_TTRG_32BYTES); + mmio_write16(chip->virt_base + SCIFA_SCASCR, + scascr | SCIFA_SCASCR_TE); + } +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read16(chip->virt_base + SCIFA_SCASSR) & + SCIFA_SCASSR_TDFE); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write8(chip->virt_base + SCIFA_SCAFTDR, c); + mmio_write16(chip->virt_base + SCIFA_SCASSR, + mmio_read16(chip->virt_base + SCIFA_SCASSR) & + ~(SCIFA_SCASSR_TDFE | SCIFA_SCASSR_TEND)); +} + +struct uart_chip uart_scifa_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm-common/uart-xuartps.c b/hypervisor/arch/arm-common/uart-xuartps.c new file mode 100644 index 0000000000000000000000000000000000000000..66c554726600260694c13b3931350a8b0bd34be2 --- /dev/null +++ b/hypervisor/arch/arm-common/uart-xuartps.c @@ -0,0 +1,38 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define UART_SR 0x2c +#define UART_SR_TXEMPTY 0x8 +#define UART_FIFO 0x30 + +static void uart_init(struct uart_chip *chip) +{ +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->virt_base + UART_SR) & UART_SR_TXEMPTY); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + mmio_write32(chip->virt_base + UART_FIFO, c); +} + +struct uart_chip uart_xuartps_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, +}; diff --git a/hypervisor/arch/arm/Kbuild b/hypervisor/arch/arm/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..3d7bd614ecdc288037eea8cd083f90727d0cb327 --- /dev/null +++ b/hypervisor/arch/arm/Kbuild @@ -0,0 +1,28 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(src)/../arm-common/Kbuild + +always-y := lib.a + +# units initialization order as defined by linking order: +# irqchip (common-objs-y), + +lib-y := $(common-objs-y) +lib-y += entry.o setup.o control.o traps.o mmio.o lib.o +lib-y += mmu_hyp.o caches.o iommu.o + +# in here we switch of the MMU and stuff, cant profile such code +# NOTE +# gcc7 will bring a new function attribute "no_profile_instrument_function" +# should switch to that for higher granularity, but gcc7 is not even there +CFLAGS_mmu_hyp.o += -fno-profile-arcs -fno-test-coverage diff --git a/hypervisor/arch/arm/Makefile b/hypervisor/arch/arm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a54370fcaf4b298d447ef66fede6232955baab67 --- /dev/null +++ b/hypervisor/arch/arm/Makefile @@ -0,0 +1,16 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +LINUXINCLUDE += -I$(src)/arch/arm-common/include + +KBUILD_CFLAGS += -marm -march=armv7ve -msoft-float +KBUILD_AFLAGS += -march=armv7ve -msoft-float diff --git a/hypervisor/arch/arm/asm-defines.c b/hypervisor/arch/arm/asm-defines.c new file mode 100644 index 0000000000000000000000000000000000000000..b601983b923e33d1e338bc4196b4110f34fb1f0c --- /dev/null +++ b/hypervisor/arch/arm/asm-defines.c @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +void common(void); + +void common(void) +{ + OFFSET(PERCPU_LINUX_SP, per_cpu, linux_sp); + BLANK(); + + /* GCC evaluates constant expressions involving built-ins + * at compilation time, so this yields computed value. + */ + DEFINE(PERCPU_STACK_END, + __builtin_offsetof(struct per_cpu, stack) + \ + FIELD_SIZEOF(struct per_cpu, stack)); + DEFINE(PERCPU_SIZE_ASM, sizeof(struct per_cpu)); +} diff --git a/hypervisor/arch/arm/caches.S b/hypervisor/arch/arm/caches.S new file mode 100644 index 0000000000000000000000000000000000000000..44b1fa3aec9936e74770be34b10d19f3e60fe915 --- /dev/null +++ b/hypervisor/arch/arm/caches.S @@ -0,0 +1,72 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +/* + * Clean the whole data cache + * Taken from the ARM ARM example code (B2.2.7) + */ + .global arm_dcaches_clean_by_sw +arm_dcaches_clean_by_sw: + push {r0-r10} + + dsb + arm_read_sysreg(CLIDR_EL1, r0) + ands r3, r0, #0x07000000 + lsr r3, #23 @ Extract level of coherency + beq finish + + mov r9, #0 @ Cache level - 1 + @ Loop caches +loop_caches: + add r2, r9, r9, lsr #1 + lsr r1, r0, r2 @ Extract current level type + and r1, r1, #7 + cmp r1, #2 + blt next_cache @ No cache or instruction only + + arm_write_sysreg(CSSELR_EL1, r9) + isb @ sync selector change + arm_read_sysreg(CSSIDR_EL1, r1) + + and r2, r1, #7 @ extract log2(line size - 4) + add r2, #4 + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 + clz r5, r4 @ Max way size + mov r8, r5 @ Working copy of the way size + +loop_sets: + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ Max number of index size +loop_ways: + orr r10, r9, r8, lsl r5 @ Factor in the way and cache numbers + orr r10, r10, r7, lsl r2 @ Factor in the index number + + arm_write_sysreg(DCCSW, r10) + + subs r7, r7, #1 @ decrement index + bge loop_ways + subs r8, r8, #1 @ decrement way + bge loop_sets + +next_cache: + add r9, r9, #2 @ increment cache number + cmp r3, r9 + bgt loop_caches + dsb + +finish: isb + pop {r0-r10} + bx lr diff --git a/hypervisor/arch/arm/control.c b/hypervisor/arch/arm/control.c new file mode 100644 index 0000000000000000000000000000000000000000..46125e1aac8a69db379d151989ba4767cc76c46c --- /dev/null +++ b/hypervisor/arch/arm/control.c @@ -0,0 +1,108 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +void arm_cpu_reset(unsigned long pc, bool aarch32) +{ + u32 sctlr; + + /* Wipe all banked and usr regs */ + memset(&this_cpu_data()->guest_regs, 0, sizeof(union registers)); + + arm_write_banked_reg(SP_usr, 0); + arm_write_banked_reg(SP_svc, 0); + arm_write_banked_reg(SP_abt, 0); + arm_write_banked_reg(SP_und, 0); + arm_write_banked_reg(SP_irq, 0); + arm_write_banked_reg(SP_fiq, 0); + arm_write_banked_reg(LR_svc, 0); + arm_write_banked_reg(LR_abt, 0); + arm_write_banked_reg(LR_und, 0); + arm_write_banked_reg(LR_irq, 0); + arm_write_banked_reg(LR_fiq, 0); + arm_write_banked_reg(R8_fiq, 0); + arm_write_banked_reg(R9_fiq, 0); + arm_write_banked_reg(R10_fiq, 0); + arm_write_banked_reg(R11_fiq, 0); + arm_write_banked_reg(R12_fiq, 0); + arm_write_banked_reg(SPSR_svc, 0); + arm_write_banked_reg(SPSR_abt, 0); + arm_write_banked_reg(SPSR_und, 0); + arm_write_banked_reg(SPSR_irq, 0); + arm_write_banked_reg(SPSR_fiq, 0); + + /* Wipe the system registers */ + arm_read_sysreg(SCTLR_EL1, sctlr); + sctlr = sctlr & ~SCTLR_MASK; + arm_write_sysreg(SCTLR_EL1, sctlr); + arm_write_sysreg(CPACR_EL1, 0); + arm_write_sysreg(CONTEXTIDR_EL1, 0); + arm_write_sysreg(PAR_EL1, 0); + arm_write_sysreg(TTBR0_EL1, 0); + arm_write_sysreg(TTBR1_EL1, 0); + arm_write_sysreg(CSSELR_EL1, 0); + + arm_write_sysreg(CNTKCTL_EL1, 0); + arm_write_sysreg(CNTP_CTL_EL0, 0); + arm_write_sysreg(CNTP_CVAL_EL0, 0); + arm_write_sysreg(CNTV_CTL_EL0, 0); + arm_write_sysreg(CNTV_CVAL_EL0, 0); + + /* AArch32 specific */ + arm_write_sysreg(TTBCR, 0); + arm_write_sysreg(DACR, 0); + arm_write_sysreg(VBAR, 0); + arm_write_sysreg(DFSR, 0); + arm_write_sysreg(DFAR, 0); + arm_write_sysreg(IFSR, 0); + arm_write_sysreg(IFAR, 0); + arm_write_sysreg(ADFSR, 0); + arm_write_sysreg(AIFSR, 0); + arm_write_sysreg(MAIR0, 0); + arm_write_sysreg(MAIR1, 0); + arm_write_sysreg(AMAIR0, 0); + arm_write_sysreg(AMAIR1, 0); + arm_write_sysreg(TPIDRURW, 0); + arm_write_sysreg(TPIDRURO, 0); + arm_write_sysreg(TPIDRPRW, 0); + + arm_write_banked_reg(SPSR_fsxc, RESET_PSR); + arm_write_banked_reg(ELR_hyp, pc); + + /* transfer the context that may have been passed to PSCI_CPU_ON */ + this_cpu_data()->guest_regs.usr[1] = this_cpu_public()->cpu_on_context; + + arm_paging_vcpu_init(&this_cell()->arch.mm); + + irqchip_cpu_reset(this_cpu_data()); +} + +#ifdef CONFIG_CRASH_CELL_ON_PANIC +void arch_panic_park(void) +{ + arm_write_banked_reg(ELR_hyp, 0); +} +#endif + +void arm_cpu_passthru_suspend(void) +{ + /* never called */ +} diff --git a/hypervisor/arch/arm/entry.S b/hypervisor/arch/arm/entry.S new file mode 100644 index 0000000000000000000000000000000000000000..814772ca1e53798b35e3f25f5f44941a9eb44666 --- /dev/null +++ b/hypervisor/arch/arm/entry.S @@ -0,0 +1,144 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + + .arch_extension virt + +/* Entry point for Linux loader module on JAILHOUSE_ENABLE */ + .text + .globl arch_entry +arch_entry: + /* r0: cpuid */ + push {r0 - r12} + + ldr r1, =__page_pool + mov r4, #PERCPU_SIZE_ASM + /* + * percpu data = pool + cpuid * shift + * TODO: handle aff1 and aff2 + */ + mla r1, r4, r0, r1 + movw r2, #PERCPU_LINUX_SP + add r4, r1, r2 + + /* + * Save SP, LR, CPSR + * r4 is used so that they can be easily retrieved on failure. + */ + str sp, [r4], #4 + str lr, [r4], #4 + mrs r3, cpsr + str r3, [r4] + + mov sp, r1 + add sp, #PERCPU_STACK_END + /* + * Keep space for a union registers, in case setup fails and needs + * to return to the driver through the arch_shutdown_self path. + * Also align the stack on double-words. + */ + sub sp, #(((NUM_USR_REGS + 1) * 4) + 7) & ~7 + /* Call entry(cpuid, struct per_cpu*) */ + bl entry + + /* + * entry only returns here when there is an error before setting up EL2 + */ + ldr lr, [r4], #-4 + ldr sp, [r4] + + /* Keep the return value in r0 */ + pop {r1} + pop {r1 - r12} + subs pc, lr, #0 + + + .globl bootstrap_vectors + .align 5 +bootstrap_vectors: + b . + b . + b . + b . + b . + b setup_el2 + b . + b . + +setup_el2: + /* + * Load the physical values of lr and sp, and continue execution at EL2. + */ + mov lr, r0 + mov sp, r1 + + bx lr + + + .globl hyp_vectors + .align 5 +hyp_vectors: + b . + b hyp_undef + b hyp_hvc + b hyp_pabt + b hyp_dabt + b hyp_trap + b hyp_irq + b hyp_fiq + +.macro handle_vmexit exit_reason + /* Fill the union registers. Should comply with NUM_USR_REGS */ + push {r0-r12, lr} + mov r0, #\exit_reason + b vmexit_common +.endm + +hyp_undef: + handle_vmexit EXIT_REASON_UNDEF +hyp_hvc: + handle_vmexit EXIT_REASON_HVC +hyp_pabt: + handle_vmexit EXIT_REASON_PABT +hyp_dabt: + handle_vmexit EXIT_REASON_DABT + +hyp_irq: + handle_vmexit EXIT_REASON_IRQ +hyp_fiq: + handle_vmexit EXIT_REASON_FIQ +hyp_trap: + handle_vmexit EXIT_REASON_TRAP + +vmexit_common: + push {r0} + + mov r0, sp + /* align the stack on double-words */ + bic sp, #7 + bl arch_handle_exit + + + /* + * Because the hypervisor may call vmreturn to reset the stack, + * arch_handle_exit has to return with the guest registers in r0 + */ + .globl vmreturn +vmreturn: + /* skip exit reason */ + add sp, r0, #4 + + /* Restore usr regs */ + pop {r0-r12, lr} + eret diff --git a/hypervisor/arch/arm/include/asm/arch_gicv3.h b/hypervisor/arch/arm/include/asm/arch_gicv3.h new file mode 100644 index 0000000000000000000000000000000000000000..558bc0470bfb89d9beba037187ceddbcc6312b1e --- /dev/null +++ b/hypervisor/arch/arm/include/asm/arch_gicv3.h @@ -0,0 +1,53 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_ARM_GIC_V3_H +#define _JAILHOUSE_ASM_ARM_GIC_V3_H + +#include + +#define ICH_LR0_7(x) SYSREG_32(4, c12, c12, x) +#define ICH_LR8_15(x) SYSREG_32(4, c12, c13, x) +#define ICH_LRC0_7(x) SYSREG_32(4, c12, c14, x) +#define ICH_LRC8_15(x) SYSREG_32(4, c12, c15, x) + +#define ICC_SGI1R_EL1 SYSREG_64(0, c12) + +#define ARM_GIC_READ_LR0_7(n, val) do { \ + u32 lr##n, lrc##n; \ + \ + arm_read_sysreg(ICH_LR0_7(n), lr##n); \ + arm_read_sysreg(ICH_LRC0_7(n), lrc##n); \ + \ + val = ((u64)lrc##n << 32) | lr##n; \ +} while (0); + +#define ARM_GIC_WRITE_LR0_7(n, val) do { \ + arm_write_sysreg(ICH_LR0_7(n), (u32)val); \ + arm_write_sysreg(ICH_LRC0_7(n), val >> 32); \ +} while (0); + +#define ARM_GIC_READ_LR8_15(n, val) do { \ + u32 lr_##n, lrc_##n; \ + \ + arm_read_sysreg(ICH_LR8_15(n), lr_##n); \ + arm_read_sysreg(ICH_LRC8_15(n), lrc_##n); \ + \ + val = ((u64)lrc_##n << 32) | lr_##n; \ +} while (0); + +#define ARM_GIC_WRITE_LR8_15(n, val) do { \ + arm_write_sysreg(ICH_LR8_15(n), (u32)val); \ + arm_write_sysreg(ICH_LRC8_15(n), val >> 32); \ +} while (0); + +#endif /* _JAILHOUSE_ASM_ARM_GIC_V3_H */ diff --git a/hypervisor/arch/arm/include/asm/bitops.h b/hypervisor/arch/arm/include/asm/bitops.h new file mode 100644 index 0000000000000000000000000000000000000000..67aee7814479e14a804c39ec9efe983ec3cd28c7 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/bitops.h @@ -0,0 +1,44 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2020 + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jan Kiszka + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* also include from arm-common */ +#include_next + +static inline int atomic_test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long ret, val, test; + + /* word-align */ + addr = (unsigned long *)((u32)addr & ~0x3) + nr / BITS_PER_LONG; + nr %= BITS_PER_LONG; + + /* Load the cacheline in exclusive state */ + asm volatile ( + ".arch_extension mp\n\t" + "pldw %0\n\t" + : "+Qo" (*(volatile unsigned long *)addr)); + do { + asm volatile ( + "ldrex %1, %3\n\t" + "ands %2, %1, %4\n\t" + "it eq\n\t" + "orreq %1, %4\n\t" + "strex %0, %1, %3\n\t" + : "=r" (ret), "=r" (val), "=r" (test), + "+Qo" (*(volatile unsigned long *)addr) + : "r" (1 << nr)); + } while (ret); + + return !!(test); +} diff --git a/hypervisor/arch/arm/include/asm/entry.h b/hypervisor/arch/arm/include/asm/entry.h new file mode 100644 index 0000000000000000000000000000000000000000..390632db9a4d9e0d236d34d5f5354594253187fd --- /dev/null +++ b/hypervisor/arch/arm/include/asm/entry.h @@ -0,0 +1,20 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +extern unsigned long bootstrap_vectors; +extern unsigned long hyp_vectors; + +void __attribute__((noreturn)) vmreturn(union registers *guest_regs); diff --git a/hypervisor/arch/arm/include/asm/jailhouse_header.h b/hypervisor/arch/arm/include/asm/jailhouse_header.h new file mode 100644 index 0000000000000000000000000000000000000000..eee94d3f4d7c13ac1efe8a2006f8a07f9eca294a --- /dev/null +++ b/hypervisor/arch/arm/include/asm/jailhouse_header.h @@ -0,0 +1,14 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define JAILHOUSE_BASE 0xf0000000 +#define JAILHOUSE_BORROW_ROOT_PT 1 diff --git a/hypervisor/arch/arm/include/asm/mmu_hyp.h b/hypervisor/arch/arm/include/asm/mmu_hyp.h new file mode 100644 index 0000000000000000000000000000000000000000..a2f0f05d71929aca454d786e3d099958036ac8ba --- /dev/null +++ b/hypervisor/arch/arm/include/asm/mmu_hyp.h @@ -0,0 +1,17 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +int switch_exception_level(struct per_cpu *cpu_data); + +void __attribute__((noreturn)) arch_shutdown_mmu(struct per_cpu *cpu_data); diff --git a/hypervisor/arch/arm/include/asm/paging.h b/hypervisor/arch/arm/include/asm/paging.h new file mode 100644 index 0000000000000000000000000000000000000000..08bed5cf202bd1fc42fd9327960ad40335abdf1e --- /dev/null +++ b/hypervisor/arch/arm/include/asm/paging.h @@ -0,0 +1,232 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PAGING_H +#define _JAILHOUSE_ASM_PAGING_H + +#include +#include +#include +#include +#include + +#define PAGE_SHIFT 12 + +#define MAX_PAGE_TABLE_LEVELS 3 + +/* + * When T0SZ == 0 and SL0 == 0, the EL2 MMU starts the IPA->PA translation at + * the level 2 table. The second table is indexed by IPA[31:21], the third one + * by IPA[20:12]. + * This would allows to cover a 4GB memory map by using 4 concatenated level-2 + * page tables and thus provide better table walk performances. + * For the moment, we will implement the first level for AArch32 using only + * one level. + * + * TODO: implement larger PARange support for AArch32 + */ +#define CELL_ROOT_PT_PAGES 1 + +#if MAX_PAGE_TABLE_LEVELS < 3 +#define T0SZ 0 +#define SL0 0 +#define PADDR_OFF (14 - T0SZ) +#define L2_VADDR_MASK BIT_MASK(21, 17 + PADDR_OFF) +#else +#define T0SZ 0 +#define SL0 1 +#define PADDR_OFF (5 - T0SZ) +#define L1_VADDR_MASK BIT_MASK(26 + PADDR_OFF, 30) +#define L2_VADDR_MASK BIT_MASK(29, 21) +#endif + +#define L3_VADDR_MASK BIT_MASK(20, 12) + +/* + * Stage-1 and Stage-2 lower attributes. + * FIXME: The upper attributes (contiguous hint and XN) are not currently in + * use. If needed in the future, they should be shifted towards the lower word, + * since the core uses unsigned long to pass the flags. + * An arch-specific typedef for the flags as well as the addresses would be + * useful. + * The contiguous bit is a hint that allows the PE to store blocks of 16 pages + * in the TLB. This may be a useful optimisation. + */ +#define PTE_ACCESS_FLAG (0x1 << 10) +/* + * When combining shareability attributes, the stage-1 ones prevail. So we can + * safely leave everything non-shareable at stage 2. + */ +#define PTE_NON_SHAREABLE (0x0 << 8) +#define PTE_OUTER_SHAREABLE (0x2 << 8) +#define PTE_INNER_SHAREABLE (0x3 << 8) + +#define PTE_MEMATTR(val) ((val) << 2) +#define PTE_FLAG_TERMINAL (0x1 << 1) +#define PTE_FLAG_VALID (0x1 << 0) + +/* These bits differ in stage 1 and 2 translations */ +#define S1_PTE_NG (0x1 << 11) +#define S1_PTE_ACCESS_RW (0x0 << 7) +#define S1_PTE_ACCESS_RO (0x1 << 7) +/* Res1 for EL2 stage-1 tables */ +#define S1_PTE_ACCESS_EL0 (0x1 << 6) + +#define S2_PTE_ACCESS_RO (0x1 << 6) +#define S2_PTE_ACCESS_WO (0x2 << 6) +#define S2_PTE_ACCESS_RW (0x3 << 6) + +/* + * Descriptor pointing to a page table + * (only for L1 and L2. L3 uses this encoding for terminal entries...) + */ +#define PTE_TABLE_FLAGS 0x3 + +#define PTE_L1_BLOCK_ADDR_MASK BIT_MASK(39, 30) +#define PTE_L2_BLOCK_ADDR_MASK BIT_MASK(39, 21) +#define PTE_TABLE_ADDR_MASK BIT_MASK(39, 12) +#define PTE_PAGE_ADDR_MASK BIT_MASK(39, 12) + +#define BLOCK_1G_VADDR_MASK BIT_MASK(29, 0) +#define BLOCK_2M_VADDR_MASK BIT_MASK(20, 0) + +#define TTBR_MASK BIT_MASK(47, PADDR_OFF) +#define VTTBR_VMID_SHIFT 48 + +#define HTCR_RES1 ((1 << 31) | (1 << 23)) +#define VTCR_RES1 ((1 << 31)) +#define TCR_RGN_NON_CACHEABLE 0x0 +#define TCR_RGN_WB_WA 0x1 +#define TCR_RGN_WT 0x2 +#define TCR_RGN_WB 0x3 +#define TCR_NON_SHAREABLE 0x0 +#define TCR_OUTER_SHAREABLE 0x2 +#define TCR_INNER_SHAREABLE 0x3 + +#define TCR_SH0_SHIFT 12 +#define TCR_ORGN0_SHIFT 10 +#define TCR_IRGN0_SHIFT 8 +#define TCR_SL0_SHIFT 6 +#define TCR_S_SHIFT 4 + +#define VTCR_CELL (T0SZ | SL0 << TCR_SL0_SHIFT \ + | (TCR_RGN_WB_WA << TCR_IRGN0_SHIFT) \ + | (TCR_RGN_WB_WA << TCR_ORGN0_SHIFT) \ + | (TCR_INNER_SHAREABLE << TCR_SH0_SHIFT)\ + | VTCR_RES1) + +/* + * Hypervisor memory attribute indexes: + * 0: normal WB, RA, WA, non-transient + * 1: device + * 2: normal non-cacheable + * 3-7: unused + */ +#define DEFAULT_HMAIR0 0x004404ff +#define DEFAULT_HMAIR1 0x00000000 +#define HMAIR_IDX_WBRAWA 0 +#define HMAIR_IDX_DEV 1 +#define HMAIR_IDX_NC 2 + +/* Stage 2 memory attributes (MemAttr[3:0]) */ +#define S2_MEMATTR_OWBIWB 0xf +#define S2_MEMATTR_DEV 0x1 + +#define S1_PTE_FLAG_NORMAL PTE_MEMATTR(HMAIR_IDX_WBRAWA) +#define S1_PTE_FLAG_DEVICE PTE_MEMATTR(HMAIR_IDX_DEV) +#define S1_PTE_FLAG_UNCACHED PTE_MEMATTR(HMAIR_IDX_NC) + +#define S2_PTE_FLAG_NORMAL PTE_MEMATTR(S2_MEMATTR_OWBIWB) +#define S2_PTE_FLAG_DEVICE PTE_MEMATTR(S2_MEMATTR_DEV) + +#define S1_DEFAULT_FLAGS (PTE_FLAG_VALID | PTE_ACCESS_FLAG \ + | S1_PTE_FLAG_NORMAL | PTE_INNER_SHAREABLE\ + | S1_PTE_ACCESS_EL0) + +/* Macros used by the core, only for the EL2 stage-1 mappings */ +#define PAGE_FLAG_FRAMEBUFFER S1_PTE_FLAG_DEVICE +#define PAGE_FLAG_DEVICE S1_PTE_FLAG_DEVICE +#define PAGE_DEFAULT_FLAGS (S1_DEFAULT_FLAGS | S1_PTE_ACCESS_RW) +#define PAGE_READONLY_FLAGS (S1_DEFAULT_FLAGS | S1_PTE_ACCESS_RO) +#define PAGE_PRESENT_FLAGS PTE_FLAG_VALID +#define PAGE_NONPRESENT_FLAGS 0 + +#define INVALID_PHYS_ADDR (~0UL) + +/** + * Location of per-CPU temporary mapping region in hypervisor address space. + */ +#define TEMPORARY_MAPPING_BASE 0x40000000UL +#define NUM_TEMPORARY_PAGES 16 + +#define REMAP_BASE 0xf8000000UL +#define NUM_REMAP_BITMAP_PAGES 4 + +#ifndef __ASSEMBLY__ + +struct cell; +struct paging_structures; + +typedef u64 *pt_entry_t; + +extern unsigned int cpu_parange; +extern unsigned int cache_line_size; + +int arm_paging_cell_init(struct cell *cell); +void arm_paging_cell_destroy(struct cell *cell); + +void arm_paging_vcpu_init(struct paging_structures *pg_structs); + +void arm_dcaches_clean_by_sw(void); + +static inline void arm_paging_vcpu_flush_tlbs(void) +{ + /* + * Invalidate all stage-1 and 2 TLB entries for the current VMID + * ERET will ensure completion of these ops + */ + arm_write_sysreg(TLBIALL, 0); +} + +/* return the bits supported for the physical address range for this + * machine; in arch_paging_init this value will be kept in + * cpu_parange for later reference */ +static inline unsigned int get_cpu_parange(void) +{ + /* TODO: implement proper PARange support on AArch32 */ + return 39; +} + +/* Only executed on hypervisor paging struct changes */ +static inline void arch_paging_flush_page_tlbs(unsigned long page_addr) +{ + /* + * This instruction is UNDEF at EL1, but the whole TLB is invalidated + * before enabling the EL2 stage 1 MMU anyway. + */ + if (is_el2()) { + dsb(); + arm_write_sysreg(TLBIMVAH, page_addr & PAGE_MASK); + dsb(); + isb(); + } +} + +/* Used to clean the PAGING_COHERENT page table changes */ +static inline void arch_paging_flush_cpu_caches(void *addr, long size) +{ + arm_dcaches_flush(addr, size, DCACHE_CLEAN); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PAGING_H */ diff --git a/hypervisor/arch/arm/include/asm/percpu_fields.h b/hypervisor/arch/arm/include/asm/percpu_fields.h new file mode 100644 index 0000000000000000000000000000000000000000..ae1f2fc0f0bebf988d5a0892bb50a3dc068b7024 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/percpu_fields.h @@ -0,0 +1,23 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define NUM_ENTRY_REGS 13 + +#define ARCH_PERCPU_FIELDS \ + ARM_PERCPU_FIELDS \ + /** Linux stack pointer, used for handover to the hypervisor. */ \ + unsigned long linux_sp; \ + unsigned long linux_ret; \ + unsigned long linux_flags; \ + unsigned long linux_reg[NUM_ENTRY_REGS]; \ + \ + bool initialized; diff --git a/hypervisor/arch/arm/include/asm/processor.h b/hypervisor/arch/arm/include/asm/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..cd7c55895e2ba93ef258e9b30aeea191e70dc91a --- /dev/null +++ b/hypervisor/arch/arm/include/asm/processor.h @@ -0,0 +1,57 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PROCESSOR_H +#define _JAILHOUSE_ASM_PROCESSOR_H + +#include +#include + +/* also include from arm-common */ +#include_next + +#define EXIT_REASON_UNDEF 0x1 +#define EXIT_REASON_HVC 0x2 +#define EXIT_REASON_PABT 0x3 +#define EXIT_REASON_DABT 0x4 +#define EXIT_REASON_TRAP 0x5 +#define EXIT_REASON_IRQ 0x6 +#define EXIT_REASON_FIQ 0x7 + +#define NUM_USR_REGS 14 + +#define ARM_PARKING_CODE \ + 0xe320f003, /* 1: wfi */ \ + 0xeafffffd, /* b 1b */ + +#ifndef __ASSEMBLY__ + +union registers { + struct { + unsigned long exit_reason; + /* r0 - r12 and lr. The other registers are banked. */ + unsigned long usr[NUM_USR_REGS]; + }; +}; + +static inline bool is_el2(void) +{ + u32 psr; + + asm volatile ("mrs %0, cpsr" : "=r" (psr)); + + return (psr & PSR_MODE_MASK) == PSR_HYP_MODE; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PROCESSOR_H */ diff --git a/hypervisor/arch/arm/include/asm/sections.h b/hypervisor/arch/arm/include/asm/sections.h new file mode 100644 index 0000000000000000000000000000000000000000..20a71d6c3e9b99f2cd5a1c0ef198d67033d4ec66 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/sections.h @@ -0,0 +1,21 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define ARCH_SECTIONS \ + . = ALIGN(PAGE_SIZE); \ + .trampoline : { \ + trampoline_start = .; \ + *(.trampoline) \ + trampoline_end = .; \ + } diff --git a/hypervisor/arch/arm/include/asm/smc.h b/hypervisor/arch/arm/include/asm/smc.h new file mode 100644 index 0000000000000000000000000000000000000000..b7348627513334f1c151c2b7a059ab39bf2e627f --- /dev/null +++ b/hypervisor/arch/arm/include/asm/smc.h @@ -0,0 +1,51 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2018 OTH Regensburg + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* for gcc < 5 */ +asm (".arch_extension sec\n"); + +static inline long smc(unsigned long id) +{ + register unsigned long __id asm("r0") = id; + + asm volatile ("smc #0\n\t" + : "+r" (__id) + : : "memory", "r1", "r2", "r3"); + + return __id; +} + +static inline int smc_arg1(unsigned long id, unsigned long par1) +{ + register unsigned long __id asm("r0") = id; + register unsigned long __par1 asm("r1") = par1; + + asm volatile ("smc #0\n\t" + : "+r" (__id), "+r" (__par1) + : : "memory", "r2", "r3"); + + return __id; +} + +static inline long smc_arg2(unsigned long id, unsigned long par1, + unsigned long par2) +{ + register unsigned long __id asm("r0") = id; + register unsigned long __par1 asm("r1") = par1; + register unsigned long __par2 asm("r2") = par2; + + asm volatile ("smc #0\n\t" + : "+r" (__id), "+r" (__par1), "+r" (__par2) + : : "memory", "r3"); + + return __id; +} diff --git a/hypervisor/arch/arm/include/asm/spinlock.h b/hypervisor/arch/arm/include/asm/spinlock.h new file mode 100644 index 0000000000000000000000000000000000000000..7fe841d034c8f47091b0c502b389c97c4c8871d4 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/spinlock.h @@ -0,0 +1,78 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Copied from arch/arm/include/asm/spinlock.h in Linux + */ +#ifndef _JAILHOUSE_ASM_SPINLOCK_H +#define _JAILHOUSE_ASM_SPINLOCK_H + +#include + +#ifndef __ASSEMBLY__ + +#define TICKET_SHIFT 16 + +typedef struct { + union { + u32 slock; + struct __raw_tickets { + u16 owner; + u16 next; + } tickets; + }; +} spinlock_t; + +static inline void spin_lock(spinlock_t *lock) +{ + unsigned long tmp; + u32 newval; + spinlock_t lockval; + + /* Take the lock by updating the high part atomically */ + asm volatile ( + ".arch_extension mp\n\t" + "pldw [%3]\n\t" + "1:\n\t" + "ldrex %0, [%3]\n\t" + "add %1, %0, %4\n\t" + "strex %2, %1, [%3]\n\t" + "teq %2, #0\n\t" + "bne 1b\n\t" + : "=&r" (lockval), "=&r" (newval), "=&r" (tmp) + : "r" (&lock->slock), "I" (1 << TICKET_SHIFT) + : "cc"); + + while (lockval.tickets.next != lockval.tickets.owner) + asm volatile ( + "wfe\n\t" + "ldrh %0, [%1]\n\t" + : "=r" (lockval.tickets.owner) + : "r" (&lock->tickets.owner)); + + /* Ensure we have the lock before doing any more memory ops */ + dmb(ish); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + /* Ensure all memory ops are finished before releasing the lock */ + dmb(ish); + + /* No need for an exclusive, since only one CPU can unlock at a time. */ + lock->tickets.owner++; + + /* Ensure the spinlock is updated before notifying other CPUs */ + dsb(ishst); + asm volatile("sev"); +} + +#endif /* !__ASSEMBLY__ */ +#endif /* !_JAILHOUSE_ASM_SPINLOCK_H */ diff --git a/hypervisor/arch/arm/include/asm/sysregs.h b/hypervisor/arch/arm/include/asm/sysregs.h new file mode 100644 index 0000000000000000000000000000000000000000..308278c4a36d852b50afe6cb2819d61153974537 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/sysregs.h @@ -0,0 +1,331 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_SYSREGS_H +#define _JAILHOUSE_ASM_SYSREGS_H + +/* + * Along with some system register names, this header defines the following + * macros for accessing cp15 registers. + * + * C-side: + * - arm_write_sysreg(SYSREG_NAME, var) + * - arm_read_sysreg(SYSREG_NAME, var) + * asm-side: + * - arm_write_sysreg(SYSREG_NAME, reg) + * - arm_read_sysreg(SYSREG_NAME, reg) + */ + +/* Processor Status Register definitions */ +#define PSR_MODE_MASK 0xf +#define PSR_USR_MODE 0x0 +#define PSR_FIQ_MODE 0x1 +#define PSR_IRQ_MODE 0x2 +#define PSR_SVC_MODE 0x3 +#define PSR_MON_MODE 0x6 +#define PSR_ABT_MODE 0x7 +#define PSR_HYP_MODE 0xa +#define PSR_UND_MODE 0xb +#define PSR_SYS_MODE 0xf + +#define PSR_32_BIT (1 << 4) +#define PSR_T_BIT (1 << 5) +#define PSR_F_BIT (1 << 6) +#define PSR_I_BIT (1 << 7) +#define PSR_A_BIT (1 << 8) +#define PSR_E_BIT (1 << 9) +#define PSR_J_BIT (1 << 24) +#define PSR_IT_MASK(it) (((it) & 0x3) << 25 | ((it) & 0xfc) << 8) +#define PSR_IT(psr) (((psr) >> 25 & 0x3) | ((psr) >> 8 & 0xfc)) + +#define RESET_PSR (PSR_I_BIT | PSR_F_BIT | PSR_A_BIT | PSR_SVC_MODE \ + | PSR_32_BIT) + +/* + * 32bit sysregs definitions + * (Use the AArch64 names to ease the compatibility work) + */ +#define CTR_EL0 SYSREG_32(0, c0, c0, 1) +#define MPIDR_EL1 SYSREG_32(0, c0, c0, 5) +#define MPIDR_CPUID_MASK 0x00ffffff +#define MPIDR_CLUSTERID_MASK 0x00ffff00 +#define MPIDR_AFF0_MASK 0x000000ff +#define MPIDR_U_BIT (1 << 30) +#define MPIDR_MP_BIT (1 << 31) +#define ID_PFR0_EL1 SYSREG_32(0, c0, c1, 0) +#define ID_PFR1_EL1 SYSREG_32(0, c0, c1, 1) +#define PFR1_VIRT(pfr) ((pfr) >> 12 & 0xf) +#define SCTLR_EL1 SYSREG_32(0, c1, c0, 0) +#define SCTLR_M_BIT (1 << 0) +#define SCTLR_A_BIT (1 << 1) +#define SCTLR_C_BIT (1 << 2) +#define SCTLR_CP15B_BIT (1 << 5) +#define SCTLR_ITD_BIT (1 << 7) +#define SCTLR_SED_BIT (1 << 8) +#define SCTLR_I_BIT (1 << 12) +#define SCTLR_V_BIT (1 << 13) +#define SCTLR_nTWI (1 << 16) +#define SCTLR_nTWE (1 << 18) +#define SCTLR_WXN_BIT (1 << 19) +#define SCTLR_UWXN_BIT (1 << 20) +#define SCTLR_FI_BIT (1 << 21) +#define SCTLR_EE_BIT (1 << 25) +#define SCTLR_TRE_BIT (1 << 28) +#define SCTLR_AFE_BIT (1 << 29) +#define SCTLR_TE_BIT (1 << 30) +#define SCTLR_C_AND_M_SET(sctlr) \ + (((sctlr) & (SCTLR_C_BIT | SCTLR_M_BIT)) == (SCTLR_C_BIT | SCTLR_M_BIT)) + +#define MPIDR_LEVEL_BITS 8 +#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) +#define MPIDR_LEVEL_SHIFT(level) (MPIDR_LEVEL_BITS * (level)) + +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ + (((mpidr) >> (MPIDR_LEVEL_BITS * (level))) & MPIDR_LEVEL_MASK) + +/* Bits to wipe on cell reset */ +#define SCTLR_MASK (SCTLR_M_BIT | SCTLR_A_BIT | SCTLR_C_BIT \ + | SCTLR_I_BIT | SCTLR_V_BIT | SCTLR_WXN_BIT \ + | SCTLR_UWXN_BIT | SCTLR_FI_BIT | SCTLR_EE_BIT \ + | SCTLR_TRE_BIT | SCTLR_AFE_BIT | SCTLR_TE_BIT) +#define ACTLR_EL1 SYSREG_32(0, c1, c0, 1) +#define CPACR_EL1 SYSREG_32(0, c1, c0, 2) +#define CONTEXTIDR_EL1 SYSREG_32(0, c13, c0, 1) +#define CSSIDR_EL1 SYSREG_32(1, c0, c0, 0) +#define CLIDR_EL1 SYSREG_32(1, c0, c0, 1) +#define CSSELR_EL1 SYSREG_32(2, c0, c0, 0) +#define SCTLR_EL2 SYSREG_32(4, c1, c0, 0) +#define HSR SYSREG_32(4, c5, c2, 0) +/* exception class */ +#define HSR_EC(hsr) GET_FIELD((hsr), 31, 26) +/* instruction length */ +#define HSR_IL(hsr) GET_FIELD((hsr), 25, 25) +/* Instruction specific syndrome */ +#define HSR_ISS(hsr) GET_FIELD((hsr), 24, 0) +/* Exception classes values */ +#define HSR_EC_UNK 0x00 +#define HSR_EC_WFI 0x01 +#define HSR_EC_CP15_32 0x03 +#define HSR_EC_CP15_64 0x04 +#define HSR_EC_CP14_32 0x05 +#define HSR_EC_CP14_LC 0x06 +#define HSR_EC_HCPTR 0x07 +#define HSR_EC_CP10 0x08 +#define HSR_EC_CP14_64 0x0c +#define HSR_EC_SVC_HYP 0x11 +#define HSR_EC_HVC 0x12 +#define HSR_EC_SMC 0x13 +#define HSR_EC_IABT 0x20 +#define HSR_EC_IABT_HYP 0x21 +#define HSR_EC_PCALIGN 0x22 +#define HSR_EC_DABT 0x24 +#define HSR_EC_DABT_HYP 0x25 +/* Condition code */ +#define HSR_ISS_CV_BIT (1 << 24) +#define HSR_ISS_COND(iss) ((iss) >> 20 & 0xf) + +#define HSR_MATCH_MCR_MRC(hsr, crn, opc1, crm, opc2) \ + (((hsr) & (BIT_MASK(19, 10) | BIT_MASK(4, 1))) == \ + (((opc2) << 17) | ((opc1) << 14) | ((crn) << 10) | ((crm) << 1))) + +#define HSR_MATCH_MCRR_MRRC(hsr, opc1, crm) \ + (((hsr) & (BIT_MASK(19, 16) | BIT_MASK(4, 1))) == \ + (((opc1) << 16) | ((crm) << 1))) + +#define TTBR0_EL2 SYSREG_64(4, c2) +#define TCR_EL2 SYSREG_32(4, c2, c0, 2) +#define VTTBR_EL2 SYSREG_64(6, c2) +#define VTCR_EL2 SYSREG_32(4, c2, c1, 2) + +#define TTBR0_EL1 SYSREG_64(0, c2) +#define TTBR1_EL1 SYSREG_64(1, c2) +#define PAR_EL1 SYSREG_64(0, c7) +#define PAR_F_BIT 0x1 +#define PAR_FST_SHIFT 1 +#define PAR_FST_MASK 0x3f +#define PAR_SHA_SHIFT 7 +#define PAR_SHA_MASK 0x3 +#define PAR_NS_BIT (0x1 << 9) +#define PAR_LPAE_BIT (0x1 << 11) +#define PAR_PA_MASK BIT_MASK(39, 12) +#define PAR_ATTR_SHIFT 56 +#define PAR_ATTR_MASK 0xff + +#define CNTKCTL_EL1 SYSREG_32(0, c14, c1, 0) +#define CNTP_TVAL_EL0 SYSREG_32(0, c14, c2, 0) +#define CNTP_CTL_EL0 SYSREG_32(0, c14, c2, 1) +#define CNTP_CVAL_EL0 SYSREG_64(2, c14) +#define CNTV_TVAL_EL0 SYSREG_32(0, c14, c3, 0) +#define CNTV_CTL_EL0 SYSREG_32(0, c14, c3, 1) +#define CNTV_CVAL_EL0 SYSREG_64(3, c14) + +#define CNTPCT_EL0 SYSREG_64(0, c14) + +/* + * AArch32-specific registers: they are 64bit on AArch64, and will need some + * helpers if used frequently. + */ +#define TTBCR SYSREG_32(0, c2, c0, 2) +#define DACR SYSREG_32(0, c3, c0, 0) +#define VBAR SYSREG_32(0, c12, c0, 0) +#define HCR SYSREG_32(4, c1, c1, 0) +#define HCR2 SYSREG_32(4, c1, c1, 4) +#define HCR_TRVM_BIT (1 << 30) +#define HCR_TVM_BIT (1 << 26) +#define HCR_HDC_BIT (1 << 29) +#define HCR_TGE_BIT (1 << 27) +#define HCR_TTLB_BIT (1 << 25) +#define HCR_TPU_BIT (1 << 24) +#define HCR_TPC_BIT (1 << 23) +#define HCR_TSW_BIT (1 << 22) +#define HCR_TAC_BIT (1 << 21) +#define HCR_TIDCP_BIT (1 << 20) +#define HCR_TSC_BIT (1 << 19) +#define HCR_TID3_BIT (1 << 18) +#define HCR_TID2_BIT (1 << 17) +#define HCR_TID1_BIT (1 << 16) +#define HCR_TID0_BIT (1 << 15) +#define HCR_TWE_BIT (1 << 14) +#define HCR_TWI_BIT (1 << 13) +#define HCR_DC_BIT (1 << 12) +#define HCR_BSU_BITS (3 << 10) +#define HCR_BSU_INNER (1 << 10) +#define HCR_BSU_OUTER (2 << 10) +#define HCR_BSU_FULL HCR_BSU_BITS +#define HCR_FB_BIT (1 << 9) +#define HCR_VA_BIT (1 << 8) +#define HCR_VI_BIT (1 << 7) +#define HCR_VF_BIT (1 << 6) +#define HCR_AMO_BIT (1 << 5) +#define HCR_IMO_BIT (1 << 4) +#define HCR_FMO_BIT (1 << 3) +#define HCR_PTW_BIT (1 << 2) +#define HCR_SWIO_BIT (1 << 1) +#define HCR_VM_BIT (1 << 0) +#define HDFAR SYSREG_32(4, c6, c0, 0) +#define HIFAR SYSREG_32(4, c6, c0, 2) +#define HPFAR SYSREG_32(4, c6, c0, 4) +#define HMAIR0 SYSREG_32(4, c10, c2, 0) +#define HMAIR1 SYSREG_32(4, c10, c2, 1) +#define HVBAR SYSREG_32(4, c12, c0, 0) + +/* Mapped to HSR, IFSR32 and FAR in AArch64 */ +#define DFSR SYSREG_32(0, c5, c0, 0) +#define DFAR SYSREG_32(0, c6, c0, 0) +#define IFSR SYSREG_32(0, c5, c0, 1) +#define IFAR SYSREG_32(0, c6, c0, 2) +#define ADFSR SYSREG_32(0, c5, c1, 0) +#define AIFSR SYSREG_32(0, c5, c1, 1) + +/* Mapped to MAIR_EL1 */ +#define MAIR0 SYSREG_32(0, c10, c2, 0) +#define MAIR1 SYSREG_32(0, c10, c2, 1) +#define AMAIR0 SYSREG_32(0, c10, c3, 0) +#define AMAIR1 SYSREG_32(0, c10, c3, 1) + +#define TPIDRURW SYSREG_32(0, c13, c0, 2) +#define TPIDRURO SYSREG_32(0, c13, c0, 3) +#define TPIDRPRW SYSREG_32(0, c13, c0, 4) + +#define CNTFRQ_EL0 SYSREG_32(0, c14, c0, 0) + +#define ATS1HR SYSREG_32(4, c7, c8, 0) + +#define ICIALLUIS SYSREG_32(0, c7, c1, 0) +#define ICIALLU SYSREG_32(0, c7, c5, 0) +#define DCIMVAC SYSREG_32(0, c7, c6, 1) +#define DCCMVAC SYSREG_32(0, c7, c10, 1) +#define DCCSW SYSREG_32(0, c7, c10, 2) +#define DCCIMVAC SYSREG_32(0, c7, c14, 1) +#define DCCISW SYSREG_32(0, c7, c14, 2) + +#define TLBIALL SYSREG_32(0, c8, c7, 0) +#define TLBIALLIS SYSREG_32(0, c8, c3, 0) +#define TLBIASID SYSREG_32(0, c8, c7, 2) +#define TLBIASIDIS SYSREG_32(0, c8, c3, 2) +#define TLBIMVA SYSREG_32(0, c8, c7, 1) +#define TLBIMVAIS SYSREG_32(0, c8, c3, 1) +#define TLBIMVAL SYSREG_32(0, c8, c7, 5) +#define TLBIMVALIS SYSREG_32(0, c8, c3, 5) +#define TLBIMVAA SYSREG_32(0, c8, c7, 3) +#define TLBIMVAAIS SYSREG_32(0, c8, c3, 3) +#define TLBIMVAAL SYSREG_32(0, c8, c7, 7) +#define TLBIMVAALIS SYSREG_32(0, c8, c3, 7) +#define TLBIALLH SYSREG_32(4, c8, c7, 0) +#define TLBIALLHIS SYSREG_32(4, c8, c3, 0) +#define TLBIALLNSNH SYSREG_32(4, c8, c7, 4) +#define TLBIALLNSNHIS SYSREG_32(4, c8, c3, 4) +#define TLBIMVAH SYSREG_32(4, c8, c7, 1) +#define TLBIMVAHIS SYSREG_32(4, c8, c3, 1) +#define TLBIMVALH SYSREG_32(4, c8, c7, 5) +#define TLBIMVALHIS SYSREG_32(4, c8, c3, 5) +#define TLBIIPAS2 SYSREG_32(4, c8, c4, 1) +#define TLBIIPAS2IS SYSREG_32(4, c8, c0, 1) +#define TLBIIPAS2L SYSREG_32(4, c8, c5, 5) +#define TLBIIPAS2LIS SYSREG_32(4, c8, c0, 5) + +#define SYSREG_32(...) 32, __VA_ARGS__ +#define SYSREG_64(...) 64, __VA_ARGS__ + +#define _arm_write_sysreg(size, ...) arm_write_sysreg_ ## size(__VA_ARGS__) +#define arm_write_sysreg(...) _arm_write_sysreg(__VA_ARGS__) + +#define _arm_read_sysreg(size, ...) arm_read_sysreg_ ## size(__VA_ARGS__) +#define arm_read_sysreg(...) _arm_read_sysreg(__VA_ARGS__) + +#ifndef __ASSEMBLY__ +/* for gcc < 5 */ +asm(".arch_extension virt\n"); + +#define arm_write_sysreg_32(op1, crn, crm, op2, val) \ + asm volatile ("mcr p15, "#op1", %0, "#crn", "#crm", "#op2"\n" \ + : : "r" ((u32)(val))) +#define arm_write_sysreg_64(op1, crm, val) \ + asm volatile ("mcrr p15, "#op1", %Q0, %R0, "#crm"\n" \ + : : "r" ((u64)(val))) + +#define arm_read_sysreg_32(op1, crn, crm, op2, val) \ + asm volatile ("mrc p15, "#op1", %0, "#crn", "#crm", "#op2"\n" \ + : "=r" ((u32)(val))) +#define arm_read_sysreg_64(op1, crm, val) \ + asm volatile ("mrrc p15, "#op1", %Q0, %R0, "#crm"\n" \ + : "=r" ((u64)(val))) + +#define arm_read_banked_reg(reg, val) \ + asm volatile ("mrs %0, " #reg "\n" : "=r" (val)) + +#define arm_write_banked_reg(reg, val) \ + asm volatile ("msr " #reg ", %0\n" : : "r" (val)) + +#define arm_rw_banked_reg(reg, val, is_read) \ + do { \ + if (is_read) \ + arm_read_banked_reg(reg, val); \ + else \ + arm_write_banked_reg(reg, val); \ + } while (0) + +#else /* __ASSEMBLY__ */ + +#define arm_write_sysreg_32(op1, crn, crm, op2, reg) \ + mcr p15, op1, reg, crn, crm, op2 +#define arm_write_sysreg_64(op1, crm, reg1, reg2) \ + mcrr p15, op1, reg1, reg2, crm + +#define arm_read_sysreg_32(op1, crn, crm, op2, reg) \ + mrc p15, op1, reg, crn, crm, op2 +#define arm_read_sysreg_64(op1, crm, reg1, reg2) \ + mrrc p15, op1, reg1, reg2, crm + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/hypervisor/arch/arm/include/asm/traps.h b/hypervisor/arch/arm/include/asm/traps.h new file mode 100644 index 0000000000000000000000000000000000000000..99cb3ada2161403372d8bc53366dad45851935f6 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/traps.h @@ -0,0 +1,29 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_TRAPS_H +#define _JAILHOUSE_ASM_TRAPS_H + +#include + +struct trap_context { + unsigned long *regs; + u32 hsr; +}; + +void access_cell_reg(struct trap_context *ctx, u8 reg, unsigned long *val, + bool is_read); + +/* now include from arm-common */ +#include_next + +#endif /* !_JAILHOUSE_ASM_TRAPS_H */ diff --git a/hypervisor/arch/arm/include/asm/types.h b/hypervisor/arch/arm/include/asm/types.h new file mode 100644 index 0000000000000000000000000000000000000000..4c4769a5f0f274a87bc2d6cd46e3f2cdcba75ec5 --- /dev/null +++ b/hypervisor/arch/arm/include/asm/types.h @@ -0,0 +1,13 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define BITS_PER_LONG 32 diff --git a/hypervisor/arch/arm/iommu.c b/hypervisor/arch/arm/iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..2c02c8129db90805dc1cc40d67dce2be31e31604 --- /dev/null +++ b/hypervisor/arch/arm/iommu.c @@ -0,0 +1,34 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +unsigned int iommu_count_units(void) +{ + return 0; +} + +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return 0; +} + +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return 0; +} + +void iommu_config_commit(struct cell *cell) +{ +} diff --git a/hypervisor/arch/arm/lib.c b/hypervisor/arch/arm/lib.c new file mode 100644 index 0000000000000000000000000000000000000000..8ed191cda58beafd16dbbd4ab923216d779cc837 --- /dev/null +++ b/hypervisor/arch/arm/lib.c @@ -0,0 +1,32 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +unsigned long long __aeabi_llsl(unsigned long long val, unsigned int shift); +unsigned long long __aeabi_llsr(unsigned long long val, unsigned int shift); + +unsigned long long __aeabi_llsl(unsigned long long val, unsigned int shift) +{ + u32 lo = (u32)val << shift; + u32 hi = ((u32)(val >> 32) << shift) | ((u32)val >> (32 - shift)); + + return ((unsigned long long)hi << 32) | lo; +} + +unsigned long long __aeabi_llsr(unsigned long long val, unsigned int shift) +{ + u32 lo = ((u32)val >> shift) | ((u32)(val >> 32) << (32 - shift)); + u32 hi = (u32)val >> shift; + + return ((unsigned long long)hi << 32) | lo; +} diff --git a/hypervisor/arch/arm/mmio.c b/hypervisor/arch/arm/mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..0162bc7ca5bf49bf27ad25d30c9498da8b9ceb74 --- /dev/null +++ b/hypervisor/arch/arm/mmio.c @@ -0,0 +1,143 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Extend the value of 'size' bits to a signed long */ +static inline unsigned long sign_extend(unsigned long val, unsigned int size) +{ + unsigned long mask = 1UL << (size - 1); + + return (val ^ mask) - mask; +} + +/* Taken from the ARM ARM pseudocode for taking a data abort */ +static void arch_inject_dabt(struct trap_context *ctx, unsigned long addr) +{ + unsigned int lr_offset; + unsigned long vbar; + bool is_thumb; + u32 sctlr, ttbcr, cpsr, pc; + + arm_read_sysreg(SCTLR_EL1, sctlr); + arm_read_sysreg(TTBCR, ttbcr); + + arm_read_banked_reg(ELR_hyp, pc); + arm_read_banked_reg(SPSR, cpsr); + + /* Set cpsr */ + is_thumb = cpsr & PSR_T_BIT; + cpsr &= ~(PSR_MODE_MASK | PSR_IT_MASK(0xff) | PSR_T_BIT + | PSR_J_BIT | PSR_E_BIT); + cpsr |= (PSR_ABT_MODE | PSR_I_BIT | PSR_A_BIT); + if (sctlr & SCTLR_TE_BIT) + cpsr |= PSR_T_BIT; + if (sctlr & SCTLR_EE_BIT) + cpsr |= PSR_E_BIT; + + arm_write_banked_reg(SPSR_fsxc, cpsr); + + lr_offset = (is_thumb ? 4 : 0); + arm_write_banked_reg(LR_abt, pc + lr_offset); + + /* Branch to dabt vector */ + if (sctlr & SCTLR_V_BIT) + vbar = 0xffff0000; + else + arm_read_sysreg(VBAR, vbar); + arm_write_banked_reg(ELR_hyp, vbar + 0x10); + + /* Signal a debug fault. DFSR layout depends on the LPAE bit */ + if (ttbcr >> 31) + arm_write_sysreg(DFSR, (1 << 9) | 0x22); + else + arm_write_sysreg(DFSR, 0x2); + arm_write_sysreg(DFAR, addr); +} + +enum trap_return arch_handle_dabt(struct trap_context *ctx) +{ + enum mmio_result mmio_result; + struct mmio_access mmio; + unsigned long hpfar; + unsigned long hdfar; + /* Decode the syndrome fields */ + u32 iss = HSR_ISS(ctx->hsr); + u32 isv = iss >> 24; + u32 sas = iss >> 22 & 0x3; + u32 sse = iss >> 21 & 0x1; + u32 srt = iss >> 16 & 0xf; + u32 ea = iss >> 9 & 0x1; + u32 cm = iss >> 8 & 0x1; + u32 s1ptw = iss >> 7 & 0x1; + u32 is_write = iss >> 6 & 0x1; + u32 size = 1 << sas; + + arm_read_sysreg(HPFAR, hpfar); + arm_read_sysreg(HDFAR, hdfar); + mmio.address = hpfar << 8; + mmio.address |= hdfar & 0xfff; + + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++; + + /* + * Invalid instruction syndrome means multiple access or writeback, there + * is nothing we can do. + */ + if (!isv || size > sizeof(unsigned long)) + goto error_unhandled; + + /* Re-inject abort during page walk, cache maintenance or external */ + if (s1ptw || ea || cm) { + arch_inject_dabt(ctx, hdfar); + return TRAP_HANDLED; + } + + if (is_write) { + /* Load the value to write from the src register */ + access_cell_reg(ctx, srt, &mmio.value, true); + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + } else { + mmio.value = 0; + } + mmio.is_write = is_write; + mmio.size = size; + + mmio_result = mmio_handle_access(&mmio); + if (mmio_result == MMIO_ERROR) + return TRAP_FORBIDDEN; + if (mmio_result == MMIO_UNHANDLED) + goto error_unhandled; + + /* Put the read value into the dest register */ + if (!is_write) { + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + access_cell_reg(ctx, srt, &mmio.value, false); + } + + arch_skip_instruction(ctx); + return TRAP_HANDLED; + +error_unhandled: + panic_printk("Unhandled data %s at 0x%lx(%d)\n", + (is_write ? "write" : "read"), mmio.address, size); + + return TRAP_UNHANDLED; +} diff --git a/hypervisor/arch/arm/mmu_hyp.c b/hypervisor/arch/arm/mmu_hyp.c new file mode 100644 index 0000000000000000000000000000000000000000..676c7fda920cd23b9be096c2441be74cedcb8faf --- /dev/null +++ b/hypervisor/arch/arm/mmu_hyp.c @@ -0,0 +1,384 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +/* This is only used if we use the new hyp-stub ABI that was introduced in + * 4.12-rc1 */ +#define LINUX_HVC_SET_VECTOR 0 + +/* functions used for translating addresses during the MMU setup process */ +typedef void* (*phys2virt_t)(unsigned long); +typedef unsigned long (*virt2phys_t)(volatile const void *); + +/* + * Two identity mappings need to be created for enabling the MMU: one for the + * code and one for the stack. + * There should not currently be any conflict with the existing mappings, but we + * still make sure not to override anything by using the 'conflict' flag. + */ +static struct { + unsigned long addr; + unsigned long flags; + bool conflict; +} id_maps[2]; + +extern unsigned long trampoline_start, trampoline_end; + +static inline unsigned int hvc(unsigned int r0, unsigned int r1) +{ + register unsigned int __r0 asm("r0") = r0; + register unsigned int __r1 asm("r1") = r1; + + asm volatile("hvc #0" : "=r" (__r0) : "r" (__r0), "r" (__r1)); + return __r0; +} + +static int set_id_map(unsigned int i, unsigned long address, unsigned long size) +{ + if (i >= ARRAY_SIZE(id_maps)) + return -ENOMEM; + + /* The trampoline code should be contained in one page. */ + if ((address & PAGE_MASK) != ((address + size - 1) & PAGE_MASK)) { + printk("FATAL: Unable to IDmap more than one page at a time.\n"); + return -E2BIG; + } + + id_maps[i].addr = address; + id_maps[i].conflict = false; + id_maps[i].flags = PAGE_DEFAULT_FLAGS; + + return 0; +} + +static void create_id_maps(struct paging_structures *pg_structs) +{ + unsigned long i; + bool conflict; + + for (i = 0; i < ARRAY_SIZE(id_maps); i++) { + conflict = (paging_virt2phys(pg_structs, + id_maps[i].addr, PAGE_PRESENT_FLAGS) != + INVALID_PHYS_ADDR); + if (conflict) { + /* + * TODO: Get the flags, and update them if they are + * insufficient. Save the current flags in id_maps. + * This extraction should be implemented in the core. + */ + } else { + paging_create(pg_structs, id_maps[i].addr, PAGE_SIZE, + id_maps[i].addr, id_maps[i].flags, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + } + id_maps[i].conflict = conflict; + } +} + +static void destroy_id_maps(struct paging_structures *pg_structs) +{ + unsigned long i; + + for (i = 0; i < ARRAY_SIZE(id_maps); i++) { + if (id_maps[i].conflict) { + /* TODO: Switch back to the original flags */ + } else { + paging_destroy(pg_structs, id_maps[i].addr, + PAGE_SIZE, PAGING_NON_COHERENT); + } + } +} + +static void __attribute__((naked, noinline)) +cpu_switch_el2(virt2phys_t virt2phys) +{ + asm volatile( + /* + * Now that the bootstrap vectors are installed, call setup_el2 + * with the translated physical values of lr and sp as + * arguments. + */ + "mov r0, sp\n\t" + "push {lr}\n\t" + "blx %0\n\t" + "pop {lr}\n\t" + "push {r0}\n\t" + "mov r0, lr\n\t" + "blx %0\n\t" + "pop {r1}\n\t" + "hvc #0\n\t" + : + : "r" (virt2phys) + /* + * The call to virt2phys may clobber all temp registers. This + * list ensures that the compiler uses a decent register for + * hvirt2phys. + */ + : "cc", "memory", "r0", "r1", "r2", "r3"); +} + +/* + * This code is put in the id-mapped `.trampoline' section, allowing to enable + * and disable the MMU in a readable and portable fashion. + * This process makes the following function quite fragile: cpu_switch_phys2virt + * attempts to translate LR and SP using a call to the virtual address of + * phys2virt. + * Those two registers are thus supposed to be left intact by the whole MMU + * setup. The stack is all the same usable, since it is id-mapped as well. + */ +static void __attribute__((naked, section(".trampoline"))) +setup_mmu_el2(unsigned long phys_cpu_data, phys2virt_t phys2virt, u64 ttbr) +{ + u32 tcr = T0SZ + | (TCR_RGN_WB_WA << TCR_IRGN0_SHIFT) + | (TCR_RGN_WB_WA << TCR_ORGN0_SHIFT) + | (TCR_INNER_SHAREABLE << TCR_SH0_SHIFT) + | HTCR_RES1; + u32 sctlr_el1, sctlr_el2; + + /* Ensure that MMU is disabled. */ + arm_read_sysreg(SCTLR_EL2, sctlr_el2); + arm_write_sysreg(SCTLR_EL2, sctlr_el2 & ~SCTLR_M_BIT); + + /* + * This setup code is always preceded by a complete cache flush, so + * there is already a few memory barriers between the page table writes + * and here. + */ + isb(); + arm_write_sysreg(HMAIR0, DEFAULT_HMAIR0); + arm_write_sysreg(HMAIR1, DEFAULT_HMAIR1); + arm_write_sysreg(TTBR0_EL2, ttbr); + arm_write_sysreg(TCR_EL2, tcr); + + /* + * Flush HYP TLB. It should only be necessary if a previous hypervisor + * was running. + */ + arm_write_sysreg(TLBIALLH, 1); + dsb(nsh); + + /* + * We need coherency with the kernel in order to use the setup + * spinlocks: only enable the caches if they are enabled at EL1. + */ + arm_read_sysreg(SCTLR_EL1, sctlr_el1); + sctlr_el1 &= (SCTLR_I_BIT | SCTLR_C_BIT); + + /* Enable stage-1 translation */ + arm_read_sysreg(SCTLR_EL2, sctlr_el2); + sctlr_el2 |= SCTLR_M_BIT | sctlr_el1; + arm_write_sysreg(SCTLR_EL2, sctlr_el2); + isb(); + + /* + * Epilogue that returns to switch_exception_level. + * Must not touch anything else than the stack + */ + asm volatile( + /* Convert sp to per-cpu mapping */ + "add sp, %0\n\t" + /* Translate LR */ + "mov r0, lr\n\t" + "blx %1\n\t" + /* Jump back to virtual addresses */ + "bx r0\n\t" + : : "r" (LOCAL_CPU_BASE - phys_cpu_data), + "r" (phys2virt) + : "cc", "r0", "r1", "r2", "r3", "lr"); +} + +/* + * Shutdown the MMU and returns to EL1 with the kernel context stored in `regs' + */ +static void __attribute__((naked, section(".trampoline"))) +shutdown_el2(union registers *regs, unsigned long vectors) +{ + u32 sctlr_el2; + + /* Disable stage-1 translation, caches must be cleaned. */ + arm_read_sysreg(SCTLR_EL2, sctlr_el2); + sctlr_el2 &= ~(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT); + arm_write_sysreg(SCTLR_EL2, sctlr_el2); + isb(); + + /* Clean the MMU registers */ + arm_write_sysreg(HMAIR0, 0); + arm_write_sysreg(HMAIR1, 0); + arm_write_sysreg(TTBR0_EL2, 0); + arm_write_sysreg(TCR_EL2, 0); + isb(); + + /* Reset the vectors as late as possible */ + arm_write_sysreg(HVBAR, vectors); + + vmreturn(regs); +} + +static void check_mmu_map(unsigned long virt_addr, unsigned long phys_addr) +{ + unsigned long phys_base; + u64 par; + + arm_write_sysreg(ATS1HR, virt_addr); + isb(); + arm_read_sysreg(PAR_EL1, par); + phys_base = (unsigned long)(par & PAR_PA_MASK); + if ((par & PAR_F_BIT) || (phys_base != phys_addr)) { + printk("VA->PA check failed, expected %lx, got %lx\n", + phys_addr, phys_base); + while (1); + } +} + +/* + * Jumping to EL2 in the same C code represents an interesting challenge, since + * it will switch from virtual addresses to physical ones, and then back to + * virtual after setting up the EL2 MMU. + * To this end, the setup_mmu_el2 and cpu_switch_el2 functions are naked and + * must handle the stack themselves. + */ +int switch_exception_level(struct per_cpu *cpu_data) +{ + /* Save the virtual address of the phys2virt function for later */ + phys2virt_t phys2virt = paging_phys2hvirt; + virt2phys_t virt2phys = paging_hvirt2phys; + unsigned long phys_bootstrap = virt2phys(&bootstrap_vectors); + unsigned long phys_cpu_data = virt2phys(cpu_data); + unsigned long trampoline_phys = virt2phys((void *)&trampoline_start); + unsigned long trampoline_size = &trampoline_end - &trampoline_start; + unsigned long stack_phys = virt2phys(cpu_data->stack); + u64 ttbr_el2; + + /* Check the paging structures as well as the MMU initialisation */ + unsigned long jailhouse_base_phys = + paging_virt2phys(&hv_paging_structs, JAILHOUSE_BASE, + PAGE_DEFAULT_FLAGS); + + /* + * paging struct won't be easily accessible when initializing el2, only + * the CPU datas will be readable at their physical address + */ + ttbr_el2 = (u64)virt2phys(cpu_data->pg_structs.root_table) & TTBR_MASK; + + /* + * Mirror the mmu setup code, so that we are able to jump to the virtual + * address after enabling it. + * Those regions must fit on one page. + */ + + if (set_id_map(0, trampoline_phys, trampoline_size) != 0) + return -E2BIG; + if (set_id_map(1, stack_phys, PAGE_SIZE) != 0) + return -E2BIG; + create_id_maps(&cpu_data->pg_structs); + + /* + * Before doing anything hairy, we need to sync the caches with memory: + * they will be off at EL2. From this point forward and until the caches + * are re-enabled, we cannot write anything critical to memory. + */ + arm_dcaches_clean_by_sw(); + + /* Replace Linux hyp-stubs by our own bootstrap vector table. + * + * Hyp-stub ABI semantic changed since 4.12-rc1 on ARM. To share the + * hvc routine among both versions, we simply zero r1 which is + * meaningless for the old ABI. The new ABI expects an opcode in r0 and + * an argument in r1. See Linux + * Documentation/virtual/kvm/arm/hyp-abi.txt . + */ + if (hypervisor_header.arm_linux_hyp_abi == HYP_STUB_ABI_LEGACY) + hvc(phys_bootstrap, 0); + else + hvc(LINUX_HVC_SET_VECTOR, phys_bootstrap); + + cpu_switch_el2(virt2phys); + /* + * At this point, we are at EL2, and we work with physical addresses. + * The MMU needs to be initialised and execution must go back to virtual + * addresses before returning, or else we are pretty much doomed. + */ + + setup_mmu_el2(phys_cpu_data, phys2virt, ttbr_el2); + + /* Sanity check */ + check_mmu_map(JAILHOUSE_BASE, jailhouse_base_phys); + + /* Set the new vectors once we're back to a sane, virtual state */ + arm_write_sysreg(HVBAR, &hyp_vectors); + + /* Remove the identity mapping */ + destroy_id_maps(&cpu_data->pg_structs); + + return 0; +} + +void __attribute__((noreturn)) arch_shutdown_mmu(struct per_cpu *cpu_data) +{ + static spinlock_t map_lock; + + virt2phys_t virt2phys = paging_hvirt2phys; + unsigned long stack_phys = virt2phys(cpu_data->stack); + unsigned long trampoline_phys = virt2phys((void *)&trampoline_start); + union registers *regs_phys = + (union registers *)virt2phys(&cpu_data->guest_regs); + + /* Jump to the identity-mapped trampoline page before shutting down */ + void (*shutdown_fun_phys)(union registers*, unsigned long); + shutdown_fun_phys = (void*)virt2phys(shutdown_el2); + + /* + * No need to check for size or overlapping here, it has already be + * done, and the paging structures will soon be deleted. However, the + * cells' CPUs may execute this concurrently. + */ + spin_lock(&map_lock); + paging_create(&hv_paging_structs, stack_phys, PAGE_SIZE, stack_phys, + PAGE_DEFAULT_FLAGS, PAGING_NON_COHERENT | PAGING_NO_HUGE); + paging_create(&hv_paging_structs, trampoline_phys, PAGE_SIZE, + trampoline_phys, PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + spin_unlock(&map_lock); + + arm_dcaches_clean_by_sw(); + + /* + * Final shutdown: + * - disable the MMU whilst inside the trampoline page + * - reset the vectors + * - return to EL1 + */ + shutdown_fun_phys(regs_phys, hypervisor_header.arm_linux_hyp_vectors); + + __builtin_unreachable(); +} + +void arm_dcaches_flush(void *addr, unsigned long size, enum dcache_flush flush) +{ + while (size > 0) { + /* clean / invalidate by MVA to PoC */ + if (flush == DCACHE_CLEAN) + arm_write_sysreg(DCCMVAC, addr); + else if (flush == DCACHE_INVALIDATE) + arm_write_sysreg(DCIMVAC, addr); + else + arm_write_sysreg(DCCIMVAC, addr); + size -= MIN(cache_line_size, size); + addr += cache_line_size; + } +} diff --git a/hypervisor/arch/arm/setup.c b/hypervisor/arch/arm/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..adb56f580157cb9cdc06f1953a3523260e4218f5 --- /dev/null +++ b/hypervisor/arch/arm/setup.c @@ -0,0 +1,162 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned int cache_line_size; + +static int arch_check_features(void) +{ + u32 pfr1; + u32 ctr; + + arm_read_sysreg(ID_PFR1_EL1, pfr1); + + if (!PFR1_VIRT(pfr1)) + return -ENODEV; + + arm_read_sysreg(CTR_EL0, ctr); + /* Extract the minimal cache line size */ + cache_line_size = 4 << (ctr >> 16 & 0xf); + + return 0; +} + +int arch_init_early(void) +{ + int err; + + err = arch_check_features(); + if (err) + return err; + + return arm_init_early(); +} + +int arch_cpu_init(struct per_cpu *cpu_data) +{ + int err; + + /* + * Copy the registers to restore from the linux stack here, because we + * won't be able to access it later + */ + memcpy(&cpu_data->linux_reg, (void *)cpu_data->linux_sp, + NUM_ENTRY_REGS * sizeof(unsigned long)); + + err = switch_exception_level(cpu_data); + if (err) + return err; + + /* Setup guest traps */ + arm_write_sysreg(HCR, HCR_VM_BIT | HCR_IMO_BIT | HCR_FMO_BIT | + HCR_TSC_BIT | HCR_TAC_BIT | HCR_TSW_BIT); + + return arm_cpu_init(cpu_data); +} + +static inline void __attribute__((always_inline)) +cpu_prepare_return_el1(struct per_cpu *cpu_data, int return_code) +{ + cpu_data->linux_reg[0] = return_code; + + asm volatile ( + "msr sp_svc, %0\n\t" + "msr elr_hyp, %1\n\t" + "msr spsr_fsxc, %2\n\t" + : + : "r" (cpu_data->linux_sp + + (NUM_ENTRY_REGS * sizeof(unsigned long))), + "r" (cpu_data->linux_ret), + "r" (cpu_data->linux_flags)); +} + +void __attribute__((noreturn)) arch_cpu_activate_vmm(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + + /* Revoke full per_cpu access now that everything is set up. */ + paging_map_all_per_cpu(this_cpu_id(), false); + + /* Return to the kernel */ + cpu_prepare_return_el1(cpu_data, 0); + + asm volatile( + /* Reset the hypervisor stack */ + "mov sp, %0\n\t" + /* + * We don't care about clobbering the other registers from now + * on. Must be in sync with arch_entry. + */ + "ldm %1, {r0 - r12}\n\t" + /* + * After this, the kernel won't be able to access the hypervisor + * code. + */ + "eret\n\t" + : + : "r" (cpu_data->stack + sizeof(cpu_data->stack)), + "r" (cpu_data->linux_reg)); + + __builtin_unreachable(); +} + +void arch_shutdown_self(struct per_cpu *cpu_data) +{ + irqchip_cpu_shutdown(&cpu_data->public); + + /* Free the guest */ + arm_write_sysreg(HCR, 0); + arm_write_sysreg(VTCR_EL2, 0); + + /* Remove stage-2 mappings */ + arm_paging_vcpu_flush_tlbs(); + + /* TLB flush needs the cell's VMID */ + isb(); + arm_write_sysreg(VTTBR_EL2, 0); + + /* Return to EL1 */ + arch_shutdown_mmu(cpu_data); +} + +void arch_cpu_restore(unsigned int cpu_id, int return_code) +{ + struct per_cpu *cpu_data = per_cpu(cpu_id); + + /* + * If we haven't reached switch_exception_level yet, there is nothing to + * clean up. + */ + if (!is_el2()) + return; + + /* + * Otherwise, attempt do disable the MMU and return to EL1 using the + * arch_shutdown path. cpu_return will fill the banked registers and the + * guest regs structure (stored at the beginning of the stack) to + * prepare the ERET. + */ + cpu_prepare_return_el1(cpu_data, return_code); + + memcpy(&cpu_data->guest_regs.usr, &cpu_data->linux_reg, + NUM_ENTRY_REGS * sizeof(unsigned long)); + + arch_shutdown_self(cpu_data); +} diff --git a/hypervisor/arch/arm/traps.c b/hypervisor/arch/arm/traps.c new file mode 100644 index 0000000000000000000000000000000000000000..6b402f741e573d374929bee4ded80b27898f3306 --- /dev/null +++ b/hypervisor/arch/arm/traps.c @@ -0,0 +1,523 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Condition check code is copied from Linux's + * - arch/arm/kernel/opcodes.c + * - arch/arm/kvm/emulate.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * condition code lookup table + * index into the table is test code: EQ, NE, ... LT, GT, AL, NV + * + * bit position in short is condition code: NZCV + */ +static const unsigned short cc_map[16] = { + 0xF0F0, /* EQ == Z set */ + 0x0F0F, /* NE */ + 0xCCCC, /* CS == C set */ + 0x3333, /* CC */ + 0xFF00, /* MI == N set */ + 0x00FF, /* PL */ + 0xAAAA, /* VS == V set */ + 0x5555, /* VC */ + 0x0C0C, /* HI == C set && Z clear */ + 0xF3F3, /* LS == C clear || Z set */ + 0xAA55, /* GE == (N==V) */ + 0x55AA, /* LT == (N!=V) */ + 0x0A05, /* GT == (!Z && (N==V)) */ + 0xF5FA, /* LE == (Z || (N!=V)) */ + 0xFFFF, /* AL always */ + 0 /* NV */ +}; + +/* Check condition field either from HSR or from SPSR in thumb mode */ +static bool arch_failed_condition(struct trap_context *ctx) +{ + u32 class = HSR_EC(ctx->hsr); + u32 iss = HSR_ISS(ctx->hsr); + u32 cpsr, flags, cond; + + arm_read_banked_reg(SPSR, cpsr); + flags = cpsr >> 28; + + /* + * Trapped instruction is unconditional, already passed the condition + * check, or is invalid + */ + if (class & 0x30 || class == 0) + return false; + + /* Is condition field valid? */ + if (iss & HSR_ISS_CV_BIT) { + cond = HSR_ISS_COND(iss); + } else { + /* This can happen in Thumb mode: examine IT state. */ + unsigned long it = PSR_IT(cpsr); + + /* it == 0 => unconditional. */ + if (it == 0) + return false; + + /* The cond for this insn works out as the top 4 bits. */ + cond = (it >> 4); + } + + /* Compare the apsr flags with the condition code */ + if ((cc_map[cond] >> flags) & 1) + return false; + + return true; +} + +/* + * When exceptions occur while instructions are executed in Thumb IF-THEN + * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have + * to do this little bit of work manually. The fields map like this: + * + * IT[7:0] -> CPSR[26:25],CPSR[15:10] + */ +static void arch_advance_itstate(struct trap_context *ctx) +{ + unsigned long itbits, cond; + u32 cpsr; + + arm_read_banked_reg(SPSR, cpsr); + if (!(cpsr & PSR_IT_MASK(0xff))) + return; + + itbits = PSR_IT(cpsr); + cond = itbits >> 5; + + if ((itbits & 0x7) == 0) + /* One instruction left in the block, next itstate is 0 */ + itbits = cond = 0; + else + itbits = (itbits << 1) & 0x1f; + + itbits |= (cond << 5); + cpsr &= ~PSR_IT_MASK(0xff); + cpsr |= PSR_IT_MASK(itbits); + + arm_write_banked_reg(SPSR_fsxc, cpsr); +} + +void arch_skip_instruction(struct trap_context *ctx) +{ + u32 pc; + + arm_read_banked_reg(ELR_hyp, pc); + pc += HSR_IL(ctx->hsr) ? 4 : 2; + arm_write_banked_reg(ELR_hyp, pc); + arch_advance_itstate(ctx); +} + +static inline void access_usr_reg(struct trap_context *ctx, u8 reg, + unsigned long *val, bool is_read) +{ + if (is_read) + *val = ctx->regs[reg]; + else + ctx->regs[reg] = *val; +} + +#define access_banked_r13_r14(mode, reg, val, is_read) \ + do { \ + if (reg == 13) \ + arm_rw_banked_reg(SP_##mode, *val, is_read); \ + else \ + arm_rw_banked_reg(LR_##mode, *val, is_read); \ + } while (0) + +void access_cell_reg(struct trap_context *ctx, u8 reg, unsigned long *val, + bool is_read) +{ + u32 mode; + + arm_read_banked_reg(SPSR, mode); + mode &= PSR_MODE_MASK; + + switch (reg) { + case 0 ... 12: + if (reg >= 8 && mode == PSR_FIQ_MODE) + switch (reg) { + case 8: + arm_rw_banked_reg(r8_fiq, *val, is_read); + break; + case 9: + arm_rw_banked_reg(r9_fiq, *val, is_read); + break; + case 10: + arm_rw_banked_reg(r10_fiq, *val, is_read); + break; + case 11: + arm_rw_banked_reg(r11_fiq, *val, is_read); + break; + case 12: + arm_rw_banked_reg(r12_fiq, *val, is_read); + break; + } + else + access_usr_reg(ctx, reg, val, is_read); + break; + case 13 ... 14: + switch (mode) { + case PSR_USR_MODE: + case PSR_SYS_MODE: + /* + * lr is saved on the stack, as it is not banked in HYP + * mode. sp is banked, so lr is at offset 13 in the USR + * regs. + */ + if (reg == 13) + access_banked_r13_r14(usr, reg, val, is_read); + else + access_usr_reg(ctx, 13, val, is_read); + break; + case PSR_SVC_MODE: + access_banked_r13_r14(svc, reg, val, is_read); + break; + case PSR_UND_MODE: + access_banked_r13_r14(und, reg, val, is_read); + break; + case PSR_ABT_MODE: + access_banked_r13_r14(abt, reg, val, is_read); + break; + case PSR_IRQ_MODE: + access_banked_r13_r14(irq, reg, val, is_read); + break; + case PSR_FIQ_MODE: + access_banked_r13_r14(fiq, reg, val, is_read); + break; + } + break; + case 15: + /* + * A trapped instruction that accesses the PC? Probably a bug, + * but nothing seems to prevent it. + */ + printk("WARNING: trapped instruction attempted to explicitly " + "access the PC.\n"); + if (is_read) + arm_read_banked_reg(ELR_hyp, *val); + else + arm_write_banked_reg(ELR_hyp, *val); + break; + default: + /* Programming error */ + printk("ERROR: attempt to write register %d\n", reg); + break; + } +} + +static void dump_guest_regs(struct trap_context *ctx) +{ + u8 reg; + unsigned long reg_val; + u32 pc, cpsr; + + arm_read_banked_reg(ELR_hyp, pc); + arm_read_banked_reg(SPSR, cpsr); + panic_printk("pc=0x%08x cpsr=0x%08x hsr=0x%08x\n", pc, cpsr, ctx->hsr); + for (reg = 0; reg < 15; reg++) { + access_cell_reg(ctx, reg, ®_val, true); + panic_printk("r%d=0x%08lx ", reg, reg_val); + if ((reg + 1) % 4 == 0) + panic_printk("\n"); + } + panic_printk("\n"); +} + +static enum trap_return arch_handle_smc(struct trap_context *ctx) +{ + unsigned long *regs = ctx->regs; + + if (SMCCC_IS_CONV_64(regs[0])) + return TRAP_FORBIDDEN; + + if (IS_PSCI_UBOOT(regs[0])) { + regs[0] = psci_dispatch(ctx); + arch_skip_instruction(ctx); + return TRAP_HANDLED; + } + + return handle_smc(ctx); +} + +static enum trap_return arch_handle_hvc(struct trap_context *ctx) +{ + unsigned long *regs = ctx->regs; + unsigned long code = regs[0]; + + if (HSR_ISS(ctx->hsr) != JAILHOUSE_HVC_CODE) + return TRAP_FORBIDDEN; + + regs[0] = hypercall(code, regs[1], regs[2]); + + if (code == JAILHOUSE_HC_DISABLE && regs[0] == 0) + arch_shutdown_self(per_cpu(this_cpu_id())); + + return TRAP_HANDLED; +} + +static enum trap_return arch_handle_cp15_32(struct trap_context *ctx) +{ + u32 hsr = ctx->hsr; + u32 rt = (hsr >> 5) & 0xf; + u32 read = hsr & 1; + u32 hcr, old_sctlr; + unsigned long val; + +#define CP15_32_PERFORM_WRITE(crn, opc1, crm, opc2) ({ \ + bool match = false; \ + if (HSR_MATCH_MCR_MRC(hsr, crn, opc1, crm, opc2)) { \ + arm_write_sysreg_32(opc1, c##crn, c##crm, opc2, val); \ + match = true; \ + } \ + match; \ +}) + + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_CP15]++; + + if (!read) + access_cell_reg(ctx, rt, &val, true); + + /* trapped by HCR.TAC */ + if (HSR_MATCH_MCR_MRC(ctx->hsr, 1, 0, 0, 1)) { /* ACTLR */ + /* Do not let the guest disable coherency by writing ACTLR... */ + if (read) + arm_read_sysreg(ACTLR_EL1, val); + } + /* all other regs are write-only / only trapped on writes */ + else if (read) { + return TRAP_UNHANDLED; + } + /* trapped by HCR.TSW */ + else if (HSR_MATCH_MCR_MRC(hsr, 7, 0, 6, 2) || /* DCISW */ + HSR_MATCH_MCR_MRC(hsr, 7, 0, 10, 2) || /* DCCSW */ + HSR_MATCH_MCR_MRC(hsr, 7, 0, 14, 2)) { /* DCCISW */ + arm_read_sysreg(HCR, hcr); + if (!(hcr & HCR_TVM_BIT)) { + arm_cell_dcaches_flush(this_cell(), + DCACHE_CLEAN_AND_INVALIDATE); + arm_write_sysreg(HCR, hcr | HCR_TVM_BIT); + } + } + /* trapped if HCR.TVM is set */ + else if (HSR_MATCH_MCR_MRC(hsr, 1, 0, 0, 0)) { /* SCTLR */ + arm_read_sysreg(SCTLR_EL1, old_sctlr); + + arm_write_sysreg(SCTLR_EL1, val); + + /* Check if caches were turned on or off. */ + if (SCTLR_C_AND_M_SET(val) != SCTLR_C_AND_M_SET(old_sctlr)) { + /* Flush dcaches again if they were enabled before. */ + if (SCTLR_C_AND_M_SET(old_sctlr)) + arm_cell_dcaches_flush(this_cell(), + DCACHE_CLEAN_AND_INVALIDATE); + /* Stop tracking VM control regs. */ + arm_read_sysreg(HCR, hcr); + arm_write_sysreg(HCR, hcr & ~HCR_TVM_BIT); + } + } else if (!(CP15_32_PERFORM_WRITE(2, 0, 0, 0) || /* TTBR0 */ + CP15_32_PERFORM_WRITE(2, 0, 0, 1) || /* TTBR1 */ + CP15_32_PERFORM_WRITE(2, 0, 0, 2) || /* TTBCR */ + CP15_32_PERFORM_WRITE(3, 0, 0, 0) || /* DACR */ + CP15_32_PERFORM_WRITE(5, 0, 0, 0) || /* DFSR */ + CP15_32_PERFORM_WRITE(5, 0, 0, 1) || /* IFSR */ + CP15_32_PERFORM_WRITE(6, 0, 0, 0) || /* DFAR */ + CP15_32_PERFORM_WRITE(6, 0, 0, 2) || /* IFAR */ + CP15_32_PERFORM_WRITE(5, 0, 1, 0) || /* ADFSR */ + CP15_32_PERFORM_WRITE(5, 0, 1, 1) || /* AIDSR */ + CP15_32_PERFORM_WRITE(10, 0, 2, 0) || /* PRRR / MAIR0 */ + CP15_32_PERFORM_WRITE(10, 0, 2, 1) || /* NMRR / MAIR1 */ + CP15_32_PERFORM_WRITE(13, 0, 0, 1))) { /* CONTEXTIDR */ + return TRAP_UNHANDLED; + } + + if (read) + access_cell_reg(ctx, rt, &val, false); + + arch_skip_instruction(ctx); + + return TRAP_HANDLED; +} + +static enum trap_return arch_handle_cp15_64(struct trap_context *ctx) +{ + u32 hsr = ctx->hsr; + u32 rt2 = (hsr >> 10) & 0xf; + u32 rt = (hsr >> 5) & 0xf; + u32 read = hsr & 1; + unsigned long lo, hi; + +#define CP15_64_PERFORM_WRITE(opc1, crm) ({ \ + bool match = false; \ + if (HSR_MATCH_MCRR_MRRC(hsr, opc1, crm)) { \ + arm_write_sysreg_64(opc1, c##crm, ((u64)hi << 32) | lo); \ + match = true; \ + } \ + match; \ +}) + + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_CP15]++; + + /* all regs are write-only / only trapped on writes */ + if (read) + return TRAP_UNHANDLED; + + access_cell_reg(ctx, rt, &lo, true); + access_cell_reg(ctx, rt2, &hi, true); + + /* trapped by HCR.IMO/FMO */ + if (HSR_MATCH_MCRR_MRRC(ctx->hsr, 0, 12)) { /* ICC_SGI1R */ + if (!gicv3_handle_sgir_write(((u64)hi << 32) | lo)) + return TRAP_UNHANDLED; + } else { + /* trapped if HCR.TVM is set */ + if (!(CP15_64_PERFORM_WRITE(0, 2) || /* TTBR0 */ + CP15_64_PERFORM_WRITE(1, 2))) /* TTBR1 */ + return TRAP_UNHANDLED; + } + + arch_skip_instruction(ctx); + + return TRAP_HANDLED; +} + +static enum trap_return handle_iabt(struct trap_context *ctx) +{ + unsigned long hpfar, hdfar; + + arm_read_sysreg(HPFAR, hpfar); + arm_read_sysreg(HDFAR, hdfar); + + panic_printk("FATAL: instruction abort at 0x%lx\n", + (hpfar << 8) | (hdfar & 0xfff)); + return TRAP_FORBIDDEN; +} + +static const trap_handler trap_handlers[0x40] = +{ + [HSR_EC_CP15_32] = arch_handle_cp15_32, + [HSR_EC_CP15_64] = arch_handle_cp15_64, + [HSR_EC_HVC] = arch_handle_hvc, + [HSR_EC_SMC] = arch_handle_smc, + [HSR_EC_IABT] = handle_iabt, + [HSR_EC_DABT] = arch_handle_dabt, +}; + +static void arch_handle_trap(union registers *guest_regs) +{ + struct trap_context ctx; + u32 exception_class; + int ret = TRAP_UNHANDLED; + + arm_read_sysreg(HSR, ctx.hsr); + exception_class = HSR_EC(ctx.hsr); + ctx.regs = guest_regs->usr; + + /* + * On some implementations, instructions that fail their condition check + * can trap. + */ + if (arch_failed_condition(&ctx)) { + arch_skip_instruction(&ctx); + return; + } + + if (trap_handlers[exception_class]) + ret = trap_handlers[exception_class](&ctx); + + switch (ret) { + case TRAP_UNHANDLED: + case TRAP_FORBIDDEN: + panic_printk("FATAL: %s (exception class 0x%02x)\n", + (ret == TRAP_UNHANDLED ? "unhandled trap" : + "forbidden access"), + exception_class); + dump_guest_regs(&ctx); + panic_park(); + } +} + +static void arch_dump_exit(union registers *regs, const char *reason) +{ + unsigned long pc; + unsigned int n; + + arm_read_banked_reg(ELR_hyp, pc); + panic_printk("Unhandled HYP %s exit at 0x%lx\n", reason, pc); + for (n = 0; n < NUM_USR_REGS; n++) + panic_printk("r%d:%s 0x%08lx%s", n, n < 10 ? " " : "", + regs->usr[n], n % 4 == 3 ? "\n" : " "); + panic_printk("\n"); +} + +static void arch_dump_abt(bool is_data) +{ + u32 hxfar; + u32 hsr; + + arm_read_sysreg(HSR, hsr); + if (is_data) + arm_read_sysreg(HDFAR, hxfar); + else + arm_read_sysreg(HIFAR, hxfar); + + panic_printk("Physical address: 0x%08x HSR: 0x%08x\n", hxfar, hsr); +} + +union registers* arch_handle_exit(union registers *regs) +{ + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL]++; + + switch (regs->exit_reason) { + case EXIT_REASON_IRQ: + irqchip_handle_irq(); + break; + case EXIT_REASON_TRAP: + arch_handle_trap(regs); + break; + + case EXIT_REASON_UNDEF: + arch_dump_exit(regs, "undef"); + panic_stop(); + case EXIT_REASON_DABT: + arch_dump_exit(regs, "data abort"); + arch_dump_abt(true); + panic_stop(); + case EXIT_REASON_PABT: + arch_dump_exit(regs, "prefetch abort"); + arch_dump_abt(false); + panic_stop(); + case EXIT_REASON_HVC: + arch_dump_exit(regs, "hvc"); + panic_stop(); + case EXIT_REASON_FIQ: + arch_dump_exit(regs, "fiq"); + panic_stop(); + default: + arch_dump_exit(regs, "unknown"); + panic_stop(); + } + + return regs; +} diff --git a/hypervisor/arch/arm64/Kbuild b/hypervisor/arch/arm64/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..4d3280219d51336faac7a131856b4c9618a37f2b --- /dev/null +++ b/hypervisor/arch/arm64/Kbuild @@ -0,0 +1,25 @@ +# +# Jailhouse AArch64 support +# +# Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH +# Copyright (c) Siemens AG, 2016 +# +# Authors: +# Antonios Motakis +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(src)/../arm-common/Kbuild + +always-y := lib.a + +# units initialization order as defined by linking order: +# irqchip (common-objs-y), + +lib-y := $(common-objs-y) +lib-y += entry.o setup.o control.o mmio.o paging.o caches.o traps.o +lib-y += iommu.o smmu-v3.o ti-pvu.o +lib-y += smmu.o diff --git a/hypervisor/arch/arm64/Makefile b/hypervisor/arch/arm64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0718994dcf0f30bc8ac2a79497fb71f79038908b --- /dev/null +++ b/hypervisor/arch/arm64/Makefile @@ -0,0 +1,15 @@ +# +# Jailhouse AArch64 support +# +# Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH +# +# Authors: +# Antonios Motakis +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +LINUXINCLUDE += -I$(src)/arch/arm-common/include + +KBUILD_CFLAGS += -march=armv8-a+nofp diff --git a/hypervisor/arch/arm64/asm-defines.c b/hypervisor/arch/arm64/asm-defines.c new file mode 100644 index 0000000000000000000000000000000000000000..774dd1451affe1876ed9cf059961167cb57fb05c --- /dev/null +++ b/hypervisor/arch/arm64/asm-defines.c @@ -0,0 +1,50 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Antonios Motakis + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +void common(void); + +void common(void) +{ + OFFSET(HEADER_MAX_CPUS, jailhouse_header, max_cpus); + OFFSET(HEADER_CORE_SIZE, jailhouse_header, core_size); + OFFSET(HEADER_DEBUG_CONSOLE_VIRT, jailhouse_header, debug_console_base); + OFFSET(HEADER_HYP_STUB_VERSION, jailhouse_header, arm_linux_hyp_abi); + OFFSET(SYSCONFIG_DEBUG_CONSOLE_PHYS, jailhouse_system, + debug_console.address); + OFFSET(SYSCONFIG_HYPERVISOR_PHYS, jailhouse_system, + hypervisor_memory.phys_start); + OFFSET(PERCPU_ID_AA64MMFR0, per_cpu, id_aa64mmfr0); + OFFSET(PERCPU_SDEI_EVENT, per_cpu, sdei_event); + BLANK(); + + DEFINE(PERCPU_STACK_END, + __builtin_offsetof(struct per_cpu, stack) + \ + FIELD_SIZEOF(struct per_cpu, stack)); + DEFINE(PERCPU_SIZE_ASM, sizeof(struct per_cpu)); + DEFINE(CPU_STAT_VMEXITS_TOTAL, LOCAL_CPU_BASE + + __builtin_offsetof(struct per_cpu, + public.stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL])); + DEFINE(CPU_STAT_VMEXITS_SMCCC, LOCAL_CPU_BASE + + __builtin_offsetof(struct per_cpu, + public.stats[JAILHOUSE_CPU_STAT_VMEXITS_SMCCC])); + BLANK(); + + DEFINE(DCACHE_CLEAN_ASM, DCACHE_CLEAN); + DEFINE(DCACHE_INVALIDATE_ASM, DCACHE_INVALIDATE); + DEFINE(DCACHE_CLEAN_AND_INVALIDATE_ASM, DCACHE_CLEAN_AND_INVALIDATE); +} diff --git a/hypervisor/arch/arm64/caches.S b/hypervisor/arch/arm64/caches.S new file mode 100644 index 0000000000000000000000000000000000000000..39dad4af662d2f610c1007a5b1ec7406ef8b7d2d --- /dev/null +++ b/hypervisor/arch/arm64/caches.S @@ -0,0 +1,65 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2016 Huawei Technologies Duesseldorf GmbH + * Copyright (c) 2016 Siemens AG + * + * Authors: + * Antonios Motakis + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Implementation derived from Linux source files: + * - arch/arm64/mm/cache.S + * - arch/arm64/mm/proc-macros.S + */ + +#include + +/* + * dcache_line_size - get the minimum D-cache line size from the CTR register. + */ + .macro dcache_line_size, reg, tmp + mrs \tmp, ctr_el0 // read CTR + ubfm \tmp, \tmp, #16, #19 // cache line size encoding + mov \reg, #4 // bytes per word + lsl \reg, \reg, \tmp // actual cache line size + .endm + +/* + * arm_dcaches_flush(addr, size, flush) + * + * Ensure that the data held in the page addr is written back to the + * page in question. + * + * - addr - address + * - size - size in question + * - flush - type of flush (see enum dcache_flush) + */ + .global arm_dcaches_flush +arm_dcaches_flush: + dcache_line_size x3, x4 + add x1, x0, x1 + sub x4, x3, #1 + bic x0, x0, x4 + +1: cmp x2, #DCACHE_CLEAN_ASM + b.ne 2f + dc cvac, x0 + b 4f + +2: cmp x2, #DCACHE_INVALIDATE_ASM + b.ne 3f + dc ivac, x0 + b 4f + +3: dc civac, x0 // DCACHE_CLEAN_AND_INVALIDATE + +4: add x0, x0, x3 + cmp x0, x1 + b.lo 1b + + dsb sy + ret diff --git a/hypervisor/arch/arm64/control.c b/hypervisor/arch/arm64/control.c new file mode 100644 index 0000000000000000000000000000000000000000..0c2b713fb4d7a7cf82fcf7598c2a417a9c628881 --- /dev/null +++ b/hypervisor/arch/arm64/control.c @@ -0,0 +1,133 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +void arm_cpu_reset(unsigned long pc, bool aarch32) +{ + u64 hcr_el2; + u64 fpexc32_el2; + + /* put the cpu in a reset state */ + /* AARCH64_TODO: handle big endian support */ + arm_write_sysreg(SCTLR_EL1, SCTLR_EL1_RES1); + arm_write_sysreg(CNTKCTL_EL1, 0); + arm_write_sysreg(PMCR_EL0, 0); + + /* wipe any other state to avoid leaking information accross cells */ + memset(&this_cpu_data()->guest_regs, 0, sizeof(union registers)); + + /* AARCH64_TODO: wipe floating point registers */ + + /* wipe special registers */ + arm_write_sysreg(SP_EL0, 0); + arm_write_sysreg(SP_EL1, 0); + arm_write_sysreg(SPSR_EL1, 0); + + /* wipe the system registers */ + arm_write_sysreg(AFSR0_EL1, 0); + arm_write_sysreg(AFSR1_EL1, 0); + arm_write_sysreg(AMAIR_EL1, 0); + arm_write_sysreg(CONTEXTIDR_EL1, 0); + arm_write_sysreg(CPACR_EL1, CPACR_EL1_FPEN_ALL); + arm_write_sysreg(CSSELR_EL1, 0); + arm_write_sysreg(ESR_EL1, 0); + arm_write_sysreg(FAR_EL1, 0); + arm_write_sysreg(MAIR_EL1, 0); + arm_write_sysreg(PAR_EL1, 0); + arm_write_sysreg(TCR_EL1, 0); + arm_write_sysreg(TPIDRRO_EL0, 0); + arm_write_sysreg(TPIDR_EL0, 0); + arm_write_sysreg(TPIDR_EL1, 0); + arm_write_sysreg(TTBR0_EL1, 0); + arm_write_sysreg(TTBR1_EL1, 0); + arm_write_sysreg(VBAR_EL1, 0); + + arm_read_sysreg(FPEXC32_EL2, fpexc32_el2); + fpexc32_el2 |= FPEXC_EL2_EN_BIT; + arm_write_sysreg(FPEXC32_EL2, fpexc32_el2); + + /* wipe timer registers */ + arm_write_sysreg(CNTP_CTL_EL0, 0); + arm_write_sysreg(CNTP_CVAL_EL0, 0); + arm_write_sysreg(CNTP_TVAL_EL0, 0); + arm_write_sysreg(CNTV_CTL_EL0, 0); + arm_write_sysreg(CNTV_CVAL_EL0, 0); + arm_write_sysreg(CNTV_TVAL_EL0, 0); + + /* AARCH64_TODO: handle PMU registers */ + /* AARCH64_TODO: handle debug registers */ + /* AARCH64_TODO: handle system registers for AArch32 state */ + arm_read_sysreg(HCR_EL2, hcr_el2); + if (aarch32) { + arm_write_sysreg(SPSR_EL2, RESET_PSR_AARCH32); + hcr_el2 &= ~HCR_RW_BIT; + } else { + arm_write_sysreg(SPSR_EL2, RESET_PSR_AARCH64); + hcr_el2 |= HCR_RW_BIT; + } + arm_write_sysreg(HCR_EL2, hcr_el2); + + arm_write_sysreg(ELR_EL2, pc); + printk("======= 0x%lx", pc); + + if( this_cpu_data()->public.cell->config->use_virt_cpuid ){ + struct per_cpu *cpu_data = this_cpu_data(); + u32 logic_cpuid = 0; + u32 cpu; + for_each_cpu(cpu, cpu_data->public.cell->cpu_set){ + if( cpu == cpu_data->public.cpu_id){ + break; + } + logic_cpuid++; + } + printk("virtual cpuid: %u -> %u\n", this_cpu_id(), logic_cpuid); + arm_write_sysreg(VMPIDR_EL2, logic_cpuid); + } + else{ + unsigned long mpidr; + arm_read_sysreg(MPIDR_EL1, mpidr); + arm_write_sysreg(VMPIDR_EL2, mpidr); + } + + + /* transfer the context that may have been passed to PSCI_CPU_ON */ + this_cpu_data()->guest_regs.usr[1] = this_cpu_public()->cpu_on_context; + + arm_paging_vcpu_init(&this_cell()->arch.mm); + + irqchip_cpu_reset(this_cpu_data()); +} + +#ifdef CONFIG_CRASH_CELL_ON_PANIC +void arch_panic_park(void) +{ + arm_write_sysreg(ELR_EL2, 0); +} +#endif + +void arm_cpu_passthru_suspend(void) +{ + unsigned long hcr; + + arm_read_sysreg(HCR_EL2, hcr); + arm_write_sysreg(HCR_EL2, hcr | HCR_IMO_BIT | HCR_FMO_BIT); + isb(); + asm volatile("wfi" : : : "memory"); + arm_write_sysreg(HCR_EL2, hcr); +} diff --git a/hypervisor/arch/arm64/entry.S b/hypervisor/arch/arm64/entry.S new file mode 100644 index 0000000000000000000000000000000000000000..a9cabf7fd4da9b74d6005ea258fe030f70eb857a --- /dev/null +++ b/hypervisor/arch/arm64/entry.S @@ -0,0 +1,567 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015-2016 Huawei Technologies Duesseldorf GmbH + * Copyright (c) 2016 Siemens AG + * + * Authors: + * Antonios Motakis + * Dmitry Voytik + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#define LINUX_HVC_SET_VECTORS_LEGACY 1 +#define LINUX_HVC_SET_VECTORS 0 + + .data +vmexits_total: + .quad CPU_STAT_VMEXITS_TOTAL + +vmexits_smccc: + .quad CPU_STAT_VMEXITS_SMCCC + +/* x11 must contain the virt-to-phys offset */ +.macro virt2phys, register + add \register, \register, x11 +.endm + +/* x11 must contain the virt-to-phys offset */ +.macro phys2virt, register + sub \register, \register, x11 +.endm + +/* Entry point for Linux loader module on JAILHOUSE_ENABLE */ + .text + .globl arch_entry +arch_entry: + /* + * x0: cpuid + * + * We don't have access to our own address space yet, so we will + * abuse some caller saved registers to preserve across calls: + * x11: virtual-to-physical address offset + * x12: physical hypervisor address + * x13: virtual hypervisor address + * x14: physical UART address + * x15: virtual UART address + * x16: cpuid + * x17: caller lr + * x18: hyp-stub version + */ + mov x16, x0 + mov x17, x30 + + adr x0, hypervisor_header + + ldr x18, [x0, #HEADER_HYP_STUB_VERSION] + + ldr x15, =UART_BASE + + adrp x1, __page_pool + ldrh w2, [x0, #HEADER_MAX_CPUS] + mov x3, #PERCPU_SIZE_ASM + /* + * sysconfig = pool + max_cpus * percpu_size + */ + madd x1, x2, x3, x1 + ldr x14, [x1, #SYSCONFIG_DEBUG_CONSOLE_PHYS] + + ldr x13, =JAILHOUSE_BASE + + ldr x12, [x1, #SYSCONFIG_HYPERVISOR_PHYS] + + sub x11, x12, x13 + + /* + * Set jailhouse_header.debug_console_base to UART_BASE plus the offset + * into the UART's physical 2 MB page. + */ + and x1, x14, #0x1fffff + add x15, x15, x1 + str x15, [x0, #HEADER_DEBUG_CONSOLE_VIRT] + + /* + * When switching to EL2 using hvc #0, before the MMU is enabled, some + * data may still be kept in D-cache, such as the hypervisor core code. + * Flush it so that the CPU does not fetch wrong instructions. + */ + ldr x1, [x0, #HEADER_CORE_SIZE] + mov x2, DCACHE_CLEAN_AND_INVALIDATE_ASM + bl arm_dcaches_flush + + /* install bootstrap_vectors */ + ldr x1, =bootstrap_vectors + virt2phys x1 + + /* choose opcode */ + mov x0, #LINUX_HVC_SET_VECTORS + cmp x18, #HYP_STUB_ABI_LEGACY + b.ne 1f + mov x0, #LINUX_HVC_SET_VECTORS_LEGACY +1: + hvc #0 + + hvc #0 /* bootstrap vectors enter EL2 at el2_entry */ + b . /* we don't expect to return here */ + + /* the bootstrap vector returns us here in physical addressing */ +el2_entry: + mrs x1, esr_el2 + lsr x1, x1, #26 + cmp x1, #0x16 + b.ne . /* not hvc */ + + /* init bootstrap page tables */ + bl init_bootstrap_pt + + /* enable temporary mmu mapings for early initialization */ + adr x0, bootstrap_pt_l0 + adr x30, 1f /* set lr manually to ensure... */ + phys2virt x30 /* ...that we return to a virtual address */ + b enable_mmu_el2 +1: + /* install the final vectors */ + adr x1, hyp_vectors + msr vbar_el2, x1 + + mov x0, x16 /* preserved cpuid, will be passed to entry */ + adrp x1, __page_pool + mov x2, #PERCPU_SIZE_ASM + /* + * percpu data = pool + cpuid * percpu_size + */ + madd x1, x2, x0, x1 + + /* set up the stack and push the root cell's callee saved registers */ + add sp, x1, #PERCPU_STACK_END + stp x29, x17, [sp, #-16]! /* note: our caller lr is in x17 */ + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + /* + * We pad the stack, so we can consistently access the guest + * registers from either the initialization, or the exception + * handling code paths. 19 caller saved registers plus the + * exit_reason, which we don't use on entry. + */ + sub sp, sp, 20 * 8 + + mrs x29, id_aa64mmfr0_el1 + str x29, [x1, #PERCPU_ID_AA64MMFR0] + + mov x29, xzr /* reset fp,lr */ + mov x30, xzr + + /* Call entry(cpuid, struct per_cpu*). Should not return. */ + bl entry + b . + + +/* + * macros used by init_bootstrap_pt + */ + +/* clobbers x8,x9 */ +.macro set_pte table, xidx, xval, flags + add x8, \xval, #(\flags) + adr x9, \table + add x9, x9, \xidx, lsl #3 + str x8, [x9] +.endm + +/* clobbers x8,x9 */ +.macro set_block table, index, addr, lvl + and x8, \addr, \ + #(((1 << ((\lvl + 1) * 9)) - 1) << (12 + (3 - \lvl) * 9)) + set_pte \table, \index, x8, PAGE_DEFAULT_FLAGS +.endm + +/* clobbers x8,x9 */ +.macro set_block_dev table, index, addr, lvl + and x8, \addr, \ + #(((1 << ((\lvl + 1) * 9)) - 1) << (12 + (3 - \lvl) * 9)) + set_pte \table, \index, x8, (PAGE_DEFAULT_FLAGS|PAGE_FLAG_DEVICE) +.endm + +/* clobbers x8,x9 */ +.macro set_table parent, index, child + adr x8, \child + set_pte \parent, \index, x8, PTE_TABLE_FLAGS +.endm + +.macro get_index idx, addr, lvl + ubfx \idx, \addr, #(12 + (3 - \lvl) * 9), 9 +.endm + +init_bootstrap_pt: + /* + * Initialize early page tables to bootstrap the + * initialization process. These tables will be replaced + * during hypervisor initialization. + * + * x0: physical address of trampoline page + * x12: physical address of hypervisor binary + * x13: virtual address of hypervisor binary + * x14: physical address of uart to map + * x15: virtual address of uart to map + * + * These are referenced statically for now. + * + * Clobbers x0-x4,x8,x9 + */ + adrp x0, __trampoline_start + + /* map the l1 table that includes the firmware and the uart */ + get_index x2, x13, 0 + set_table bootstrap_pt_l0, x2, bootstrap_pt_l1_hyp_uart + + /* map the l1 table that includes the trampoline */ + get_index x3, x0, 0 + set_table bootstrap_pt_l0, x3, bootstrap_pt_l1_trampoline + + /* fill the l1 tables */ + get_index x2, x13, 1 + set_table bootstrap_pt_l1_hyp_uart, x2, bootstrap_pt_l2_hyp_uart + get_index x4, x0, 1 + set_block bootstrap_pt_l1_trampoline, x4, x0, 1 + + get_index x2, x13, 2 + set_block bootstrap_pt_l2_hyp_uart, x2, x12, 2 + get_index x3, x15, 2 + set_block_dev bootstrap_pt_l2_hyp_uart, x3, x14, 2 + + adrp x0, bootstrap_pt_l0 + mov x1, PAGE_SIZE * 4 + mov x2, DCACHE_INVALIDATE_ASM + b arm_dcaches_flush /* will return to our caller */ + + +.macro ventry label + .align 7 + b \label +.endm + + .align 11 +bootstrap_vectors: + ventry . + ventry . + ventry . + ventry . + + ventry . + ventry . + ventry . + ventry . + + ventry el2_entry + ventry . + ventry . + ventry . + + ventry . + ventry . + ventry . + ventry . + +.macro handle_vmexit_early + /* We need to save EL1 context, reserve some space on the stack */ + sub sp, sp, #(16 * 16) + /* And push [x1-x4] early, we need registers to work on */ + str x0, [sp, #(1 * 8)] + stp x1, x2, [sp, #(1 * 16)] + stp x3, x4, [sp, #(2 * 16)] + + /* [x0-x4] may now be clobbered. */ + + /* + * increase vmexits_total on each exit. Using x3 and x4 will preserve + * x0, which still holds the guest's value on exit. + */ + ldr x3, =vmexits_total + ldr x3, [x3] + ldr x4, [x3] + add x4, x4, #1 + str x4, [x3] +.endm + +.macro handle_vmexit_late handler + /* Fill the rest of the union registers. Should comply with NUM_USR_REGS */ + stp x5, x6, [sp, #(3 * 16)] + stp x7, x8, [sp, #(4 * 16)] + stp x9, x10, [sp, #(5 * 16)] + stp x11, x12, [sp, #(6 * 16)] + stp x13, x14, [sp, #(7 * 16)] + stp x15, x16, [sp, #(8 * 16)] + stp x17, x18, [sp, #(9 * 16)] + stp x19, x20, [sp, #(10 * 16)] + stp x21, x22, [sp, #(11 * 16)] + stp x23, x24, [sp, #(12 * 16)] + stp x25, x26, [sp, #(13 * 16)] + stp x27, x28, [sp, #(14 * 16)] + stp x29, x30, [sp, #(15 * 16)] + + mov x29, xzr /* reset fp,lr */ + mov x30, xzr + mov x0, sp + bl \handler + /* take the fast exit path, sp is already in place */ + b __vmreturn +.endm + +el1_trap: + handle_vmexit_late arch_handle_trap + +.macro handle_vmexit handler + .align 7 + handle_vmexit_early + handle_vmexit_late \handler +.endm + +.macro handle_vmexit_hardened handler + .align 7 + handle_vmexit_early + + /* Mitigate CVE 2017-5715 (aka Spectre v2) */ + mov w0, #SMCCC_ARCH_WORKAROUND_1 + smc #0 + + handle_vmexit_late \handler +.endm + +.macro handle_abort_fastpath + .align 7 + handle_vmexit_early + + /* Save old x0, which might contain guest SMC's function ID */ + mov x4, x0 + + mov w0, #SMCCC_ARCH_WORKAROUND_1 + smc #0 + + mrs x0, esr_el2 + lsr x0, x0, #ESR_EC_SHIFT + cmp x0, #ESR_EC_SMC64 + b.ne el1_trap /* normal trap if !SMC64 */ + + /* w4 holds the guest's function_id */ + eor w0, w4, #SMCCC_ARCH_WORKAROUND_1 + cbnz w0, el1_trap /* normal trap if !SMCCC_ARCH_WORKAROUND_1 */ + + /* Here we land if the guest called SMCCC_ARCH_WORKAROUND_1 */ + + /* + * Skip guest's instruction, it must have been 'smc #0' and must have + * had 4 bytes */ + mrs x0, elr_el2 + add x0, x0, #4 + msr elr_el2, x0 + + /* And don't forget to account the SMC exit */ + ldr x0, =vmexits_smccc + ldr x0, [x0] + ldr x1, [x0] + add x1, x1, #1 + str x1, [x0] + + /* beam me up, we only need to restore x4 and sp */ + ldr x4, [sp, #(2 * 16 + 1 * 8)] + add sp, sp, #(16 * 16) + eret + /* + * Mitigate Straight-line Speculation. + * Guard against Speculating past an ERET instruction and + * potentially perform speculative accesses to memory before + * processing the exception return + */ + dsb nsh + isb +.endm + +/* + * These are the default vectors. They are used on early startup and if no + * Spectre v2 mitigation is available. + */ + .align 11 +hyp_vectors: + ventry . + ventry . + ventry . + ventry . + + handle_vmexit arch_el2_abt + ventry . + ventry . + ventry . + + handle_vmexit arch_handle_trap + handle_vmexit irqchip_handle_irq + ventry . + ventry . + + handle_vmexit arch_handle_trap + handle_vmexit irqchip_handle_irq + ventry . + ventry . + + + .align 11 + .globl hyp_vectors_hardened +hyp_vectors_hardened: + ventry . + ventry . + ventry . + ventry . + + handle_vmexit arch_el2_abt /* no mitigation, we're doomed anyway... */ + ventry . + ventry . + ventry . + + handle_abort_fastpath + handle_vmexit_hardened irqchip_handle_irq + ventry . + ventry . + + handle_abort_fastpath + handle_vmexit irqchip_handle_irq + ventry . + ventry . + + + .pushsection .trampoline, "ax" + .globl enable_mmu_el2 +enable_mmu_el2: + /* + * x0: u64 ttbr0_el2 + */ + + /* setup the MMU for EL2 hypervisor mappings */ + ldr x1, =DEFAULT_MAIR_EL2 + msr mair_el2, x1 + + /* AARCH64_TODO: ARM architecture supports CPU clusters which could be + * in separate inner shareable domains. At the same time: "The Inner + * Shareable domain is expected to be the set of PEs controlled by + * a single hypervisor or operating system." (see p. 93 of ARM ARM) + * We should think what hw configuration we support by one instance of + * the hypervisor and choose Inner or Outer sharable domain. + */ + ldr x1, =(T0SZ(48) | (TCR_RGN_WB_WA << TCR_IRGN0_SHIFT) \ + | (TCR_RGN_WB_WA << TCR_ORGN0_SHIFT) \ + | (TCR_INNER_SHAREABLE << TCR_SH0_SHIFT) \ + | TCR_EL2_RES1) + + /* + * set TCR.(I)PS to the highest supported ID_AA64MMFR0_EL1.PARange value + */ + mrs x9, id_aa64mmfr0_el1 + /* Narrow PARange to fit the PS field in TCR_ELx */ + ubfx x9, x9, #ID_AA64MMFR0_PARANGE_SHIFT, #3 + bfi x1, x9, #TCR_PS_SHIFT, #3 + + msr tcr_el2, x1 + + msr ttbr0_el2, x0 + + isb + tlbi alle2 + dsb nsh + + /* Enable MMU, allow cacheability for instructions and data */ + ldr x1, =(SCTLR_I_BIT | SCTLR_C_BIT | SCTLR_M_BIT | SCTLR_EL2_RES1) + msr sctlr_el2, x1 + + isb + tlbi alle2 + dsb nsh + + ret + + + .globl shutdown_el2 +shutdown_el2: + /* x0: struct percpu* */ + + /* + * Disable the hypervisor MMU. + * + * Note: no data accesses must be done after turning MMU off unless the + * target region has been flushed out of D-cache. + */ + mrs x1, sctlr_el2 + ldr x2, =(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT) + bic x1, x1, x2 + msr sctlr_el2, x1 + isb + + msr mair_el2, xzr + msr ttbr0_el2, xzr + msr tcr_el2, xzr + isb + + /* Prepare continuation as vmreturn(guest_registers). */ + add x0, x0, #(PERCPU_STACK_END - 32 * 8) + + /* Fall through to vmreturn */ + + .globl vmreturn +vmreturn: + /* x0: union registers* */ + mov sp, x0 +__vmreturn: + ldp x29, x30, [sp, #(15 * 16)] + ldp x27, x28, [sp, #(14 * 16)] + ldp x25, x26, [sp, #(13 * 16)] + ldp x23, x24, [sp, #(12 * 16)] + ldp x21, x22, [sp, #(11 * 16)] + ldp x19, x20, [sp, #(10 * 16)] + ldp x17, x18, [sp, #(9 * 16)] + ldp x15, x16, [sp, #(8 * 16)] + ldp x13, x14, [sp, #(7 * 16)] + ldp x11, x12, [sp, #(6 * 16)] + ldp x9, x10, [sp, #(5 * 16)] + ldp x7, x8, [sp, #(4 * 16)] + ldp x5, x6, [sp, #(3 * 16)] + ldp x3, x4, [sp, #(2 * 16)] + ldp x1, x2, [sp, #(1 * 16)] + ldr x0, [sp, #(1 * 8)] + add sp, sp, #(16 * 16) + eret + /* + * Mitigate Straight-line Speculation. + * Guard against Speculating past an ERET instruction and + * potentially perform speculative accesses to memory before + * processing the exception return + */ + dsb nsh + isb + .popsection + + + .globl sdei_handler +sdei_handler: + mov w0, #1 + strh w0, [x1, #PERCPU_SDEI_EVENT] + + mrs x0, vtcr_el2 + orr x0, x0, #0xff + msr vtcr_el2, x0 + isb + tlbi vmalls12e1is + + ldr x0, =SDEI_EVENT_COMPLETE + mov x1, #SDEI_EV_HANDLED + smc #0 + + b . diff --git a/hypervisor/arch/arm64/include/asm/arch_gicv3.h b/hypervisor/arch/arm64/include/asm/arch_gicv3.h new file mode 100644 index 0000000000000000000000000000000000000000..93908232e16b31914d26827441b603b63df6d8d9 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/arch_gicv3.h @@ -0,0 +1,30 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * Author: + * Lokesh Vutla + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_ARM64_GIC_V3_H +#define _JAILHOUSE_ASM_ARM64_GIC_V3_H + +#include + +#define ICH_LR0_7_EL2(x) SYSREG_64(4, c12, c12, x) +#define ICH_LR8_15_EL2(x) SYSREG_64(4, c12, c13, x) + +#define ICC_SGI1R_EL1 SYSREG_64(0, c12, c11, 5) + +#define ARM_GIC_READ_LR0_7(n, val) arm_read_sysreg(ICH_LR0_7_EL2(n), val); +#define ARM_GIC_WRITE_LR0_7(n, val) arm_write_sysreg(ICH_LR0_7_EL2(n), val); + +#define ARM_GIC_READ_LR8_15(n, val) arm_read_sysreg(ICH_LR8_15_EL2(n), val); +#define ARM_GIC_WRITE_LR8_15(n, val) \ + arm_write_sysreg(ICH_LR8_15_EL2(n), val); + +#endif /* _JAILHOUSE_ASM_ARM64_GIC_V3_H */ diff --git a/hypervisor/arch/arm64/include/asm/bitops.h b/hypervisor/arch/arm64/include/asm/bitops.h new file mode 100644 index 0000000000000000000000000000000000000000..a4878e0ed614ba33f3021d44c2aa02a179623302 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/bitops.h @@ -0,0 +1,45 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Claudio Fontana + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* also include from arm-common */ +#include_next + +static inline int atomic_test_and_set_bit(int nr, volatile unsigned long *addr) +{ + u32 ret; + u64 test, tmp; + + /* word-align */ + addr = (unsigned long *)((u64)addr & ~0x7) + nr / BITS_PER_LONG; + nr %= BITS_PER_LONG; + + + /* AARCH64_TODO: using Inner Shareable DMB at the moment, + * revisit when we will deal with shareability domains */ + + do { + asm volatile ( + "ldxr %3, %2\n\t" + "ands %1, %3, %4\n\t" + "b.ne 1f\n\t" + "orr %3, %3, %4\n\t" + "1:\n\t" + "stxr %w0, %3, %2\n\t" + "dmb ish\n\t" + : "=&r" (ret), "=&r" (test), + "+Q" (*(volatile unsigned long *)addr), + "=&r" (tmp) + : "r" (1ul << nr)); + } while (ret); + return !!(test); +} diff --git a/hypervisor/arch/arm64/include/asm/entry.h b/hypervisor/arch/arm64/include/asm/entry.h new file mode 100644 index 0000000000000000000000000000000000000000..d663cbf6a8bff422ea79369352b38a4e7022492f --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/entry.h @@ -0,0 +1,24 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Antonios Motakis + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +extern unsigned long hyp_vectors_hardened; + +void enable_mmu_el2(u64 ttbr0_el2); +void __attribute__((noreturn)) shutdown_el2(struct per_cpu *cpu_data); + +void __attribute__((noreturn)) vmreturn(union registers *guest_regs); + +void sdei_handler(void *param); diff --git a/hypervisor/arch/arm64/include/asm/jailhouse_header.h b/hypervisor/arch/arm64/include/asm/jailhouse_header.h new file mode 100644 index 0000000000000000000000000000000000000000..d675ff9e9fec099b132d6e88e874a376eaa53899 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/jailhouse_header.h @@ -0,0 +1,13 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define JAILHOUSE_BASE __JH_CONST_UL(0xffffc0200000) diff --git a/hypervisor/arch/arm64/include/asm/paging.h b/hypervisor/arch/arm64/include/asm/paging.h new file mode 100644 index 0000000000000000000000000000000000000000..e600cf5821caf26a3c03f3fee7c8f1b89f443b37 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/paging.h @@ -0,0 +1,234 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015-2016 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PAGING_H +#define _JAILHOUSE_ASM_PAGING_H + +#include +#include +#include +#include +#include + +/* + * This file is based on hypervisor/arch/arm/include/asm/paging.h for AArch32. + * However, there are some differences. AArch64 supports different granule + * sizes for pages (4Kb, 16Kb, and 64Kb), while AArch32 supports only a 4Kb + * native page size. AArch64 also supports 4 levels of page tables, numbered + * L0-3, while AArch32 supports only 3 levels numbered L1-3. + * + * We currently only implement 4Kb granule size for the page tables. + * We support physical address ranges of up to 48 bits. + */ + +#define PAGE_SHIFT 12 + +#define MAX_PAGE_TABLE_LEVELS 4 + +#define L0_VADDR_MASK BIT_MASK(47, 39) +#define L1_VADDR_MASK BIT_MASK(38, 30) +#define L2_VADDR_MASK BIT_MASK(29, 21) + +#define L3_VADDR_MASK BIT_MASK(20, 12) + +/* + * Stage-1 and Stage-2 lower attributes. + * The contiguous bit is a hint that allows the PE to store blocks of 16 pages + * in the TLB. This may be a useful optimisation. + */ +#define PTE_ACCESS_FLAG (0x1 << 10) +/* + * When combining shareability attributes, the stage-1 ones prevail. So we can + * safely leave everything non-shareable at stage 2. + */ +#define PTE_NON_SHAREABLE (0x0 << 8) +#define PTE_OUTER_SHAREABLE (0x2 << 8) +#define PTE_INNER_SHAREABLE (0x3 << 8) + +#define PTE_MEMATTR(val) ((val) << 2) +#define PTE_FLAG_TERMINAL (0x1 << 1) +#define PTE_FLAG_VALID (0x1 << 0) + +/* These bits differ in stage 1 and 2 translations */ +#define S1_PTE_NG (0x1 << 11) +#define S1_PTE_ACCESS_RW (0x0 << 7) +#define S1_PTE_ACCESS_RO (0x1 << 7) +/* Res1 for EL2 stage-1 tables */ +#define S1_PTE_ACCESS_EL0 (0x1 << 6) + +#define S2_PTE_ACCESS_RO (0x1 << 6) +#define S2_PTE_ACCESS_WO (0x2 << 6) +#define S2_PTE_ACCESS_RW (0x3 << 6) + +/* + * Descriptor pointing to a page table + * (only for L1 and L2. L3 uses this encoding for terminal entries...) + */ +#define PTE_TABLE_FLAGS 0x3 + +#define PTE_L0_BLOCK_ADDR_MASK BIT_MASK(47, 39) +#define PTE_L1_BLOCK_ADDR_MASK BIT_MASK(47, 30) +#define PTE_L2_BLOCK_ADDR_MASK BIT_MASK(47, 21) +#define PTE_TABLE_ADDR_MASK BIT_MASK(47, 12) +#define PTE_PAGE_ADDR_MASK BIT_MASK(47, 12) + +#define BLOCK_512G_VADDR_MASK BIT_MASK(38, 0) +#define BLOCK_1G_VADDR_MASK BIT_MASK(29, 0) +#define BLOCK_2M_VADDR_MASK BIT_MASK(20, 0) + +/* + * AARCH64_TODO: the way TTBR_MASK is handled is almost certainly wrong. The + * low bits of the TTBR should be zero, however this is an alignment requirement + * as well for the actual location of the page table root. We get around the + * buggy behaviour in the AArch32 code we share, by setting the mask to the + * de facto alignment employed by the arch independent code: one page. + */ +#define TTBR_MASK BIT_MASK(47, 12) +#define VTTBR_VMID_SHIFT 48 + +#define TCR_EL2_RES1 ((1 << 31) | (1 << 23)) +#define VTCR_RES1 ((1 << 31)) +#define T0SZ(parange) (64 - parange) +#define SL0_L0 2 +#define SL0_L1 1 +#define SL0_L2 0 +#define PARANGE_48B 0x5 +#define TCR_RGN_NON_CACHEABLE 0x0 +#define TCR_RGN_WB_WA 0x1 +#define TCR_RGN_WT 0x2 +#define TCR_RGN_WB 0x3 +#define TCR_NON_SHAREABLE 0x0 +#define TCR_OUTER_SHAREABLE 0x2 +#define TCR_INNER_SHAREABLE 0x3 + +#define TCR_PS_SHIFT 16 +#define TCR_SH0_SHIFT 12 +#define TCR_ORGN0_SHIFT 10 +#define TCR_IRGN0_SHIFT 8 +#define TCR_SL0_SHIFT 6 +#define TCR_S_SHIFT 4 + +/* + * Hypervisor memory attribute indexes: + * 0: normal WB, RA, WA, non-transient + * 1: device + * 2: normal non-cacheable + * 3-7: unused + */ +#define DEFAULT_MAIR_EL2 0x00000000004404ff +#define MAIR_IDX_WBRAWA 0 +#define MAIR_IDX_DEV 1 +#define MAIR_IDX_NC 2 + +/* Stage 2 memory attributes (MemAttr[3:0]) */ +#define S2_MEMATTR_OWBIWB 0xf +#define S2_MEMATTR_DEV 0x1 + +#define S1_PTE_FLAG_NORMAL PTE_MEMATTR(MAIR_IDX_WBRAWA) +#define S1_PTE_FLAG_DEVICE PTE_MEMATTR(MAIR_IDX_DEV) +#define S1_PTE_FLAG_UNCACHED PTE_MEMATTR(MAIR_IDX_NC) + +#define S2_PTE_FLAG_NORMAL PTE_MEMATTR(S2_MEMATTR_OWBIWB) +#define S2_PTE_FLAG_DEVICE PTE_MEMATTR(S2_MEMATTR_DEV) + +#define S1_DEFAULT_FLAGS (PTE_FLAG_VALID | PTE_ACCESS_FLAG \ + | S1_PTE_FLAG_NORMAL | PTE_INNER_SHAREABLE\ + | S1_PTE_ACCESS_EL0) + +/* Memory Model Feature Register 0 */ +#define ID_AA64MMFR0_PARANGE_SHIFT 0 + +/* Macros used by the core, only for the EL2 stage-1 mappings */ +#define PAGE_FLAG_FRAMEBUFFER S1_PTE_FLAG_DEVICE +#define PAGE_FLAG_DEVICE S1_PTE_FLAG_DEVICE +#define PAGE_DEFAULT_FLAGS (S1_DEFAULT_FLAGS | S1_PTE_ACCESS_RW) +#define PAGE_READONLY_FLAGS (S1_DEFAULT_FLAGS | S1_PTE_ACCESS_RO) +#define PAGE_PRESENT_FLAGS PTE_FLAG_VALID +#define PAGE_NONPRESENT_FLAGS 0 + +#define INVALID_PHYS_ADDR (~0UL) + +#define UART_BASE 0xffffc0000000 + +/** + * Location of per-CPU temporary mapping region in hypervisor address space. + */ +#define TEMPORARY_MAPPING_BASE 0xff0000000000UL +#define NUM_TEMPORARY_PAGES 16 + +#define REMAP_BASE 0xff8000000000UL +#define NUM_REMAP_BITMAP_PAGES 4 + +#ifndef __ASSEMBLY__ + +struct cell; +struct paging_structures; + +typedef u64 *pt_entry_t; + +extern unsigned int cpu_parange, cpu_parange_encoded; + +unsigned int get_cpu_parange(void); + +/* The size of the cpu_parange, determines from which level we can + * start from the S2 translations, and the size of the first level + * page table */ +#define T0SZ_CELL T0SZ(cpu_parange) +#define SL0_CELL ((cpu_parange >= 44) ? SL0_L0 : SL0_L1) +#define CELL_ROOT_PT_PAGES \ + ({ unsigned int ret = 1; \ + if (cpu_parange > 39 && cpu_parange < 44) \ + ret = 1 << (cpu_parange - 39); \ + ret; }) + +/* Just match the host's PARange */ +#define VTCR_CELL (T0SZ_CELL | (SL0_CELL << TCR_SL0_SHIFT)\ + | (TCR_RGN_WB_WA << TCR_IRGN0_SHIFT) \ + | (TCR_RGN_WB_WA << TCR_ORGN0_SHIFT) \ + | (TCR_INNER_SHAREABLE << TCR_SH0_SHIFT)\ + | (cpu_parange_encoded << TCR_PS_SHIFT) \ + | VTCR_RES1) + +int arm_paging_cell_init(struct cell *cell); +void arm_paging_cell_destroy(struct cell *cell); + +void arm_paging_vcpu_init(struct paging_structures *pg_structs); + +static inline void arm_paging_vcpu_flush_tlbs(void) +{ + /* + * Invalidate all stage-1 and 2 TLB entries for the current VMID + * ERET will ensure completion of these ops + */ + asm volatile("tlbi vmalls12e1is"); +} + +/* Only executed on hypervisor paging struct changes */ +static inline void arch_paging_flush_page_tlbs(unsigned long page_addr) +{ + asm volatile( + "dsb ish\n\t" + "tlbi vae2, %0\n\t" + "dsb ish\n\t" + "isb\n\t" + : : "r" (page_addr >> PAGE_SHIFT)); +} + +/* Used to clean the PAGE_MAP_COHERENT page table changes */ +static inline void arch_paging_flush_cpu_caches(void *addr, long size) +{ + arm_dcaches_flush(addr, size, DCACHE_CLEAN); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PAGING_H */ diff --git a/hypervisor/arch/arm64/include/asm/percpu_fields.h b/hypervisor/arch/arm64/include/asm/percpu_fields.h new file mode 100644 index 0000000000000000000000000000000000000000..67573fd603e15e118ffb6ad8a0c880c1ade51f04 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/percpu_fields.h @@ -0,0 +1,16 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define ARCH_PERCPU_FIELDS \ + ARM_PERCPU_FIELDS \ + unsigned long id_aa64mmfr0; \ + bool sdei_event; diff --git a/hypervisor/arch/arm64/include/asm/processor.h b/hypervisor/arch/arm64/include/asm/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..312214b3e05f9fa750669e4c9f515f82cfdb4529 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/processor.h @@ -0,0 +1,43 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PROCESSOR_H +#define _JAILHOUSE_ASM_PROCESSOR_H + +#include + +/* also include from arm-common */ +#include_next + +#define NUM_USR_REGS 31 + +#define ARM_PARKING_CODE \ + 0xd503207f, /* 1: wfi */ \ + 0x17ffffff, /* b 1b */ + +#ifndef __ASSEMBLY__ + +union registers { + struct { + /* + * We have an odd number of registers, and the stack needs to + * be aligned after pushing all registers. Add 64 bit padding + * at the beginning. + */ + unsigned long __padding; + unsigned long usr[NUM_USR_REGS]; + }; +}; + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PROCESSOR_H */ diff --git a/hypervisor/arch/arm64/include/asm/sections.h b/hypervisor/arch/arm64/include/asm/sections.h new file mode 100644 index 0000000000000000000000000000000000000000..cc39b4082a4b33418d61ce59f7e34fe9ac75aad4 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/sections.h @@ -0,0 +1,36 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015-2016 Huawei Technologies Duesseldorf GmbH + * Copyright (c) 2016 Siemens AG + * + * Authors: + * Antonios Motakis + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* + * We have no memory management during early init; four pages is the minimum we + * can get away with to switch on the MMU with mappings for the hypervisor + * firmware and the UART as well as identity mapping for the trampoline code + * page. + */ +#define ARCH_SECTIONS \ + . = ALIGN(PAGE_SIZE); \ + .bootstrap_page_tables : { \ + bootstrap_pt_l0 = .; \ + . = . + PAGE_SIZE; \ + bootstrap_pt_l1_hyp_uart = .; \ + . = . + PAGE_SIZE; \ + bootstrap_pt_l1_trampoline = .; \ + . = . + PAGE_SIZE; \ + bootstrap_pt_l2_hyp_uart = .; \ + . = . + PAGE_SIZE; \ + } \ + .trampoline : { \ + __trampoline_start = .; \ + *(.trampoline) \ + } diff --git a/hypervisor/arch/arm64/include/asm/smc.h b/hypervisor/arch/arm64/include/asm/smc.h new file mode 100644 index 0000000000000000000000000000000000000000..ecd2cac69f13fef4176b3e997f216010b7275517 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/smc.h @@ -0,0 +1,67 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2018 OTH Regensburg + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +static inline long smc(unsigned long id) +{ + register unsigned long __id asm("r0") = id; + + asm volatile ("smc #0\n\t" + : "+r" (__id) + : : "memory", "x1", "x2", "x3"); + + return __id; +} + +static inline long smc_arg1(unsigned long id, unsigned long par1) +{ + register unsigned long __id asm("r0") = id; + register unsigned long __par1 asm("r1") = par1; + + asm volatile ("smc #0\n\t" + : "+r" (__id), "+r" (__par1) + : : "memory", "x2", "x3"); + + return __id; +} + +static inline long smc_arg2(unsigned long id, unsigned long par1, + unsigned long par2) +{ + register unsigned long __id asm("r0") = id; + register unsigned long __par1 asm("r1") = par1; + register unsigned long __par2 asm("r2") = par2; + + asm volatile ("smc #0\n\t" + : "+r" (__id), "+r" (__par1), "+r" (__par2) + : : "memory", "x3"); + + return __id; +} + +static inline long smc_arg5(unsigned long id, unsigned long par1, + unsigned long par2, unsigned long par3, + unsigned long par4, unsigned long par5) +{ + register unsigned long __id asm("r0") = id; + register unsigned long __par1 asm("r1") = par1; + register unsigned long __par2 asm("r2") = par2; + register unsigned long __par3 asm("r3") = par3; + register unsigned long __par4 asm("r4") = par4; + register unsigned long __par5 asm("r5") = par5; + + asm volatile ("smc #0\n\t" + : "+r" (__id), "+r" (__par1), "+r" (__par2), "+r" (__par3), + "+r"(__par4), "+r"(__par5) + : : "memory"); + + return __id; +} diff --git a/hypervisor/arch/arm64/include/asm/smmu.h b/hypervisor/arch/arm64/include/asm/smmu.h new file mode 100644 index 0000000000000000000000000000000000000000..def7cbdef05bad80cf3c8ec7b2a17557d9361960 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/smmu.h @@ -0,0 +1,12 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright Siemens AG, 2020 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +void arm_smmu_config_commit(struct cell *cell); diff --git a/hypervisor/arch/arm64/include/asm/spinlock.h b/hypervisor/arch/arm64/include/asm/spinlock.h new file mode 100644 index 0000000000000000000000000000000000000000..1d05174b24ce5b876d51a94d0335994ba1572c67 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/spinlock.h @@ -0,0 +1,82 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * Spinlock implementation copied from + * arch/arm64/include/asm/spinlock.h in Linux + * + * Copyright (C) 2012 ARM Ltd. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _JAILHOUSE_ASM_SPINLOCK_H +#define _JAILHOUSE_ASM_SPINLOCK_H + +#include + +#define TICKET_SHIFT 16 + +/* TODO: fix this if we add support for BE */ +typedef struct { + u16 owner; + u16 next; +} spinlock_t __attribute__((aligned(4))); + +/* + * According to ARMv8 DDI 0487D.a, B2-108: + * "The Load-Acquire, Load-AcquirePC, and Store-Release instructions + * can remove the requirement to use the explicit DMB instruction." + * + * So no need explicit memory_barrier bound with spin_lock/unlock + */ +static inline void spin_lock(spinlock_t *lock) +{ + unsigned int tmp; + spinlock_t lockval, newval; + + asm volatile( + /* Atomically increment the next ticket. */ +" prfm pstl1strm, %3\n" +"1: ldaxr %w0, %3\n" +" add %w1, %w0, %w5\n" +" stxr %w2, %w1, %3\n" +" cbnz %w2, 1b\n" + /* Did we get the lock? */ +" eor %w1, %w0, %w0, ror #16\n" +" cbz %w1, 3f\n" + /* + * No: spin on the owner. Send a local event to avoid missing an + * unlock before the exclusive load. + */ +" sevl\n" +"2: wfe\n" +" ldaxrh %w2, %4\n" +" eor %w1, %w2, %w0, lsr #16\n" +" cbnz %w1, 2b\n" + /* We got the lock. Critical section starts here. */ +"3:" + : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock) + : "Q" (lock->owner), "I" (1 << TICKET_SHIFT) + : "memory"); +} + +/* + * See spin_lock: This implementation implies a memory barrier. + */ +static inline void spin_unlock(spinlock_t *lock) +{ + asm volatile( +" stlrh %w1, %0\n" + : "=Q" (lock->owner) + : "r" (lock->owner + 1) + : "memory"); +} + +#endif /* !_JAILHOUSE_ASM_SPINLOCK_H */ diff --git a/hypervisor/arch/arm64/include/asm/sysregs.h b/hypervisor/arch/arm64/include/asm/sysregs.h new file mode 100644 index 0000000000000000000000000000000000000000..868ef887e156eb04234e78cb326b3020da679858 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/sysregs.h @@ -0,0 +1,186 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_SYSREGS_H +#define _JAILHOUSE_ASM_SYSREGS_H + +#define PSR_MODE_MASK 0xf +#define PSR_MODE_EL0t 0x0 +#define PSR_MODE_SVC 0x3 +#define PSR_MODE_EL1t 0x4 +#define PSR_MODE_EL1h 0x5 +#define PSR_MODE_EL2t 0x8 +#define PSR_MODE_EL2h 0x9 + +#define PSR_32_BIT (1 << 4) +#define PSR_F_BIT (1 << 6) +#define PSR_I_BIT (1 << 7) +#define PSR_A_BIT (1 << 8) +#define PSR_D_BIT (1 << 9) +#define PSR_IL_BIT (1 << 20) +#define PSR_SS_BIT (1 << 21) +#define RESET_PSR_AARCH64 (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT \ + | PSR_MODE_EL1h) +#define RESET_PSR_AARCH32 (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT \ + | PSR_32_BIT | PSR_MODE_SVC) + +#define MPIDR_CPUID_MASK 0xff00ffffffUL +#define MPIDR_CLUSTERID_MASK 0xff00ffff00UL +#define MPIDR_AFF0_MASK 0x00000000ffUL +#define MPIDR_U_BIT (1 << 30) +#define MPIDR_MP_BIT (1 << 31) + +#define MPIDR_LEVEL_BITS_SHIFT 3 +#define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT) +#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) + +#define MPIDR_LEVEL_SHIFT(level) \ + (((1 << (level)) >> 1) << MPIDR_LEVEL_BITS_SHIFT) + +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ + (((mpidr) >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK) + +#define SCTLR_M_BIT (1 << 0) +#define SCTLR_A_BIT (1 << 1) +#define SCTLR_C_BIT (1 << 2) +#define SCTLR_SA_BIT (1 << 3) +#define SCTLR_SA0_BIT (1 << 4) +#define SCTLR_CP15B_BIT (1 << 5) +#define SCTLR_ITD_BIT (1 << 7) +#define SCTLR_SED_BIT (1 << 8) +#define SCTLR_UMA_BIT (1 << 9) +#define SCTLR_I_BIT (1 << 12) +#define SCTLR_DZE_BIT (1 << 14) +#define SCTLR_UCT_BIT (1 << 15) +#define SCTLR_nTWI (1 << 16) +#define SCTLR_nTWE (1 << 18) +#define SCTLR_WXN_BIT (1 << 19) +#define SCTLR_E0E_BIT (1 << 24) +#define SCTLR_EE_BIT (1 << 25) +#define SCTLR_UCI_BIT (1 << 26) + +#define SCTLR_EL1_RES1 ((1 << 11) | (1 << 20) | (3 << 22) | (3 << 28)) +#define SCTLR_EL2_RES1 ((3 << 4) | (1 << 11) | (1 << 16) | (1 << 18) \ + | (3 << 22) | (3 << 28)) + +#define HCR_MIOCNCE_BIT (1u << 38) +#define HCR_ID_BIT (1u << 33) +#define HCR_CD_BIT (1u << 32) +#define HCR_RW_BIT (1u << 31) +#define HCR_TRVM_BIT (1u << 30) +#define HCR_HDC_BIT (1u << 29) +#define HCR_TDZ_BIT (1u << 28) +#define HCR_TGE_BIT (1u << 27) +#define HCR_TVM_BIT (1u << 26) +#define HCR_TTLB_BIT (1u << 25) +#define HCR_TPU_BIT (1u << 24) +#define HCR_TPC_BIT (1u << 23) +#define HCR_TSW_BIT (1u << 22) +#define HCR_TAC_BIT (1u << 21) +#define HCR_TIDCP_BIT (1u << 20) +#define HCR_TSC_BIT (1u << 19) +#define HCR_TID3_BIT (1u << 18) +#define HCR_TID2_BIT (1u << 17) +#define HCR_TID1_BIT (1u << 16) +#define HCR_TID0_BIT (1u << 15) +#define HCR_TWE_BIT (1u << 14) +#define HCR_TWI_BIT (1u << 13) +#define HCR_DC_BIT (1u << 12) +#define HCR_BSU_BITS (3u << 10) +#define HCR_BSU_INNER (1u << 10) +#define HCR_BSU_OUTER (2u << 10) +#define HCR_BSU_FULL HCR_BSU_BITS +#define HCR_FB_BIT (1u << 9) +#define HCR_VA_BIT (1u << 8) +#define HCR_VI_BIT (1u << 7) +#define HCR_VF_BIT (1u << 6) +#define HCR_AMO_BIT (1u << 5) +#define HCR_IMO_BIT (1u << 4) +#define HCR_FMO_BIT (1u << 3) +#define HCR_PTW_BIT (1u << 2) +#define HCR_SWIO_BIT (1u << 1) +#define HCR_VM_BIT (1u << 0) + +/* exception class */ +#define ESR_EC_SHIFT (26) +#define ESR_EC(esr) GET_FIELD((esr), 31, ESR_EC_SHIFT) +/* instruction length */ +#define ESR_IL(esr) GET_FIELD((esr), 25, 25) +/* Instruction specific syndrome */ +#define ESR_ISS(esr) GET_FIELD((esr), 24, 0) +/* Exception classes values */ +#define ESR_EC_UNKNOWN 0x00 +#define ESR_EC_WFx 0x01 +#define ESR_EC_CP15_32 0x03 +#define ESR_EC_CP15_64 0x04 +#define ESR_EC_CP14_MR 0x05 +#define ESR_EC_CP14_LS 0x06 +#define ESR_EC_FP_ASIMD 0x07 +#define ESR_EC_CP10_ID 0x08 +#define ESR_EC_CP14_64 0x0C +#define ESR_EC_ILL 0x0E +#define ESR_EC_SVC32 0x11 +#define ESR_EC_HVC32 0x12 +#define ESR_EC_SMC32 0x13 +#define ESR_EC_SVC64 0x15 +#define ESR_EC_HVC64 0x16 +#define ESR_EC_SMC64 0x17 +#define ESR_EC_SYS64 0x18 +#define ESR_EC_IMP_DEF 0x1f +#define ESR_EC_IABT_LOW 0x20 +#define ESR_EC_IABT_CUR 0x21 +#define ESR_EC_PC_ALIGN 0x22 +#define ESR_EC_DABT_LOW 0x24 +#define ESR_EC_DABT_CUR 0x25 +#define ESR_EC_SP_ALIGN 0x26 +#define ESR_EC_FP_EXC32 0x28 +#define ESR_EC_FP_EXC64 0x2C +#define ESR_EC_SERROR 0x2F +#define ESR_EC_BREAKPT_LOW 0x30 +#define ESR_EC_BREAKPT_CUR 0x31 +#define ESR_EC_SOFTSTP_LOW 0x32 +#define ESR_EC_SOFTSTP_CUR 0x33 +#define ESR_EC_WATCHPT_LOW 0x34 +#define ESR_EC_WATCHPT_CUR 0x35 +#define ESR_EC_BKPT32 0x38 +#define ESR_EC_VECTOR32 0x3A +#define ESR_EC_BRK64 0x3C + +#define ESR_MATCH_MSR_MRS(esr, op0, op1, crn, crm, op2) \ + (((esr) & (BIT_MASK(21, 10) | BIT_MASK(4, 1))) == \ + (((op0) << 20) | ((op2) << 17) | ((op1) << 14) | \ + ((crn) << 10) | ((crm) << 1))) + +/* exception level in SPSR_ELx */ +#define SPSR_EL(spsr) (((spsr) & 0xc) >> 2) + +#define CPACR_EL1_FPEN_ALL (3UL << 20) + +#define FPEXC_EL2_EN_BIT (1UL << 30) + +#ifndef __ASSEMBLY__ + +#include + +#define SYSREG_32(op1, crn, crm, op2) s3_##op1 ##_##crn ##_##crm ##_##op2 +#define SYSREG_64(op1, crn, crm, op2) SYSREG_32(op1, crn, crm, op2) + +#define arm_write_sysreg(sysreg, val) \ + asm volatile ("msr "__stringify(sysreg)", %0\n" \ + : : "r" ((u64)(val))) + +#define arm_read_sysreg(sysreg, val) \ + asm volatile ("mrs %0, "__stringify(sysreg)"\n" : "=r" ((val))) + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/hypervisor/arch/arm64/include/asm/ti-pvu.h b/hypervisor/arch/arm64/include/asm/ti-pvu.h new file mode 100644 index 0000000000000000000000000000000000000000..62aec7c0b4fd1cb75156c4eb240341e3e3e19874 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/ti-pvu.h @@ -0,0 +1,131 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * TI PVU IOMMU unit API headers + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _IOMMMU_PVU_H_ +#define _IOMMMU_PVU_H_ + +#include +#include + +#define PVU_NUM_TLBS 64 +#define PVU_NUM_ENTRIES 8 + +#define PVU_CONFIG_NTLB_MASK (0xff) +#define PVU_CONFIG_NENT_MASK (0xf << 16) + +#define PVU_MAX_VIRTID_MASK (0xfff) + +#define PVU_ENABLE_DIS (0x0) +#define PVU_ENABLE_EN (0x1) +#define PVU_ENABLE_MASK (0x1) + +struct pvu_hw_cfg { + u32 pid; + u32 config; + u8 resv_16[8]; + u32 enable; + u32 virtid_map1; + u32 virtid_map2; + u8 resv_48[20]; + u32 exception_logging_disable; + u8 resv_260[208]; + u32 destination_id; + u8 resv_288[24]; + u32 exception_logging_control; + u32 exception_logging_header0; + u32 exception_logging_header1; + u32 exception_logging_data0; + u32 exception_logging_data1; + u32 exception_logging_data2; + u32 exception_logging_data3; + u8 resv_320[4]; + u32 exception_pend_set; + u32 exception_pend_clear; + u32 exception_ENABLE_set; + u32 exception_ENABLE_clear; + u32 eoi_reg; +}; + +#define PVU_TLB_ENTRY_VALID (2) +#define PVU_TLB_ENTRY_INVALID (0) +#define PVU_TLB_ENTRY_MODE_MASK (0x3 << 30) +#define PVU_TLB_ENTRY_FLAG_MASK (0xff7f) +#define PVU_TLB_ENTRY_PGSIZE_MASK (0xf << 16) + +#define PVU_ENTRY_INVALID (0 << 30) +#define PVU_ENTRY_VALID (2 << 30) + +#define LPAE_PAGE_PERM_UR (1 << 15) +#define LPAE_PAGE_PERM_UW (1 << 14) +#define LPAE_PAGE_PERM_UX (1 << 13) +#define LPAE_PAGE_PERM_SR (1 << 12) +#define LPAE_PAGE_PERM_SW (1 << 11) +#define LPAE_PAGE_PERM_SX (1 << 10) + +#define LPAE_PAGE_MEM_WRITETHROUGH (2 << 8) +#define LPAE_PAGE_OUTER_SHARABLE (1 << 4) +#define LPAE_PAGE_IS_NOALLOC (0 << 2) +#define LPAE_PAGE_OS_NOALLOC (0 << 0) + +struct pvu_hw_tlb_entry { + u32 reg0; + u32 reg1; + u32 reg2; + u32 reg3; + u32 reg4; + u32 reg5; + u32 reg6; + u32 reg7; +}; + +#define PVU_TLB_EN_MASK (1 << 31) +#define PVU_TLB_LOG_DIS_MASK (1 << 30) +#define PVU_TLB_FAULT_MASK (1 << 29) +#define PVU_TLB_CHAIN_MASK (0xfff) + +struct pvu_hw_tlb { + u32 chain; + u8 resv_32[28]; + struct pvu_hw_tlb_entry entry[8]; + u8 resv_4096[3808]; +}; + +struct pvu_tlb_entry { + u64 virt_addr; + u64 phys_addr; + u64 size; + u64 flags; +}; + +struct pvu_dev { + u32 *cfg_base; + u32 *tlb_base; + + u32 num_tlbs; + u32 num_entries; + u16 max_virtid; + + u16 tlb_data[PVU_NUM_TLBS]; + u16 free_tlb_count; +}; + +int pvu_iommu_map_memory(struct cell *cell, + const struct jailhouse_memory *mem); + +int pvu_iommu_unmap_memory(struct cell *cell, + const struct jailhouse_memory *mem); + +void pvu_iommu_config_commit(struct cell *cell); + +#endif /* _IOMMMU_PVU_H_ */ diff --git a/hypervisor/arch/arm64/include/asm/traps.h b/hypervisor/arch/arm64/include/asm/traps.h new file mode 100644 index 0000000000000000000000000000000000000000..a7c07624c9abd667204de13f0a7a22d8122d1d9d --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/traps.h @@ -0,0 +1,32 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_TRAPS_H +#define _JAILHOUSE_ASM_TRAPS_H + +#include + +struct trap_context { + unsigned long *regs; + u64 elr; + u64 esr; + u64 spsr; + u64 sp; +}; + +void arch_handle_trap(union registers *guest_regs); +void arch_el2_abt(union registers *regs); + +/* now include from arm-common */ +#include_next + +#endif /* !_JAILHOUSE_ASM_TRAPS_H */ diff --git a/hypervisor/arch/arm64/include/asm/types.h b/hypervisor/arch/arm64/include/asm/types.h new file mode 100644 index 0000000000000000000000000000000000000000..fbec8931da453857b290b32f7c5df01c3c6d45d7 --- /dev/null +++ b/hypervisor/arch/arm64/include/asm/types.h @@ -0,0 +1,13 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Dmitry Voytik + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define BITS_PER_LONG 64 diff --git a/hypervisor/arch/arm64/iommu.c b/hypervisor/arch/arm64/iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..ca998789a7c45a7ea74509a57bbc059aebc8a337 --- /dev/null +++ b/hypervisor/arch/arm64/iommu.c @@ -0,0 +1,44 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +unsigned int iommu_count_units(void) +{ + unsigned int units = 0; + + while (units < JAILHOUSE_MAX_IOMMU_UNITS && + system_config->platform_info.iommu_units[units].base) + units++; + return units; +} + +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return pvu_iommu_map_memory(cell, mem); +} + +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return pvu_iommu_unmap_memory(cell, mem); +} + +void iommu_config_commit(struct cell *cell) +{ + arm_smmu_config_commit(cell); + pvu_iommu_config_commit(cell); +} diff --git a/hypervisor/arch/arm64/mmio.c b/hypervisor/arch/arm64/mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..7fbfef753f433a425d0027b74a06f195997db500 --- /dev/null +++ b/hypervisor/arch/arm64/mmio.c @@ -0,0 +1,112 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * Copyright (C) 2014 ARM Limited + * + * Authors: + * Antonios Motakis + * + * Part of the fuctionality is derived from the AArch32 implementation, under + * hypervisor/arch/arm/mmio.c by Jean-Philippe Brucker. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* AARCH64_TODO: consider merging this with the AArch32 version */ + +/* AARCH64_TODO: we can use SXTB, SXTH, SXTW */ +/* Extend the value of 'size' bits to a signed long */ +static inline unsigned long sign_extend(unsigned long val, unsigned int size) +{ + unsigned long mask = 1UL << (size - 1); + + return (val ^ mask) - mask; +} + +static void arch_inject_dabt(struct trap_context *ctx, unsigned long addr) +{ + int err __attribute__((unused)) = trace_error(-EINVAL); + while (1); +} + +enum trap_return arch_handle_dabt(struct trap_context *ctx) +{ + enum mmio_result mmio_result; + struct mmio_access mmio; + unsigned long hpfar; + unsigned long hdfar; + /* Decode the syndrome fields */ + u32 iss = ESR_ISS(ctx->esr); + u32 isv = iss >> 24; + u32 sas = iss >> 22 & 0x3; + u32 sse = iss >> 21 & 0x1; + u32 srt = iss >> 16 & 0x1f; + u32 ea = iss >> 9 & 0x1; + u32 cm = iss >> 8 & 0x1; + u32 s1ptw = iss >> 7 & 0x1; + u32 is_write = iss >> 6 & 0x1; + u32 size = 1 << sas; + + arm_read_sysreg(HPFAR_EL2, hpfar); + arm_read_sysreg(FAR_EL2, hdfar); + mmio.address = hpfar << 8; + mmio.address |= hdfar & 0xfff; + + this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++; + + /* + * Invalid instruction syndrome means multiple access or writeback, + * there is nothing we can do. + */ + if (!isv) + goto error_unhandled; + + /* Re-inject abort during page walk, cache maintenance or external */ + if (s1ptw || ea || cm) { + arch_inject_dabt(ctx, hdfar); + return TRAP_HANDLED; + } + + if (is_write) { + /* Load the value to write from the src register */ + mmio.value = (srt == 31) ? 0 : ctx->regs[srt]; + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + } else { + mmio.value = 0; + } + mmio.is_write = is_write; + mmio.size = size; + + mmio_result = mmio_handle_access(&mmio); + if (mmio_result == MMIO_ERROR) + return TRAP_FORBIDDEN; + if (mmio_result == MMIO_UNHANDLED) + goto error_unhandled; + + /* Put the read value into the dest register */ + if (!is_write && (srt != 31)) { + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + ctx->regs[srt] = mmio.value; + } + + arch_skip_instruction(ctx); + return TRAP_HANDLED; + +error_unhandled: + panic_printk("Unhandled data %s at 0x%lx(%d)\n", + (is_write ? "write" : "read"), mmio.address, size); + + return TRAP_UNHANDLED; +} diff --git a/hypervisor/arch/arm64/paging.c b/hypervisor/arch/arm64/paging.c new file mode 100644 index 0000000000000000000000000000000000000000..27adcf55572e3b30594eae54ee215876ef999ddd --- /dev/null +++ b/hypervisor/arch/arm64/paging.c @@ -0,0 +1,48 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright 2018 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +unsigned int cpu_parange_encoded; + +/** + * Return the physical address bits. + * + * In arch_paging_init this value will be kept in cpu_parange + * for later reference + * + * @return The physical address bits. + */ +unsigned int get_cpu_parange(void) +{ + static const unsigned int pa_bits[] = { 32, 36, 40, 42, 44, 48 }; + unsigned int cpu; + + /* Largest supported value (for 4K paging) */ + cpu_parange_encoded = PARANGE_48B; + + /* + * early_init calls paging_init, which will indirectly call + * get_cpu_parange, prior to cell_init, we cannot use + * for_each_cpu yet. So we need to iterate over the configuration + * of the root cell. + */ + for (cpu = 0; cpu < system_config->root_cell.cpu_set_size * 8; cpu++) + if (cpu_id_valid(cpu) && + (per_cpu(cpu)->id_aa64mmfr0 & 0xf) < cpu_parange_encoded) + cpu_parange_encoded = per_cpu(cpu)->id_aa64mmfr0 & 0xf; + + return cpu_parange_encoded < ARRAY_SIZE(pa_bits) ? + pa_bits[cpu_parange_encoded] : 0; +} diff --git a/hypervisor/arch/arm64/setup.c b/hypervisor/arch/arm64/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..376648e3f1d4f97791fa5296c22eee0a66145ad0 --- /dev/null +++ b/hypervisor/arch/arm64/setup.c @@ -0,0 +1,159 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern u8 __trampoline_start[]; + +int arch_init_early(void) +{ + unsigned long trampoline_page = paging_hvirt2phys(&__trampoline_start); + int err; + + /* + * ID-map the trampoline code page. + * + * We will need it for shutting down once the final page table is + * installed. So better do this early while we can still handle errors. + */ + err = paging_create(&hv_paging_structs, trampoline_page, PAGE_SIZE, + trampoline_page, PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + if (err) + return err; + + return arm_init_early(); +} + +int arch_cpu_init(struct per_cpu *cpu_data) +{ + unsigned long hcr = HCR_VM_BIT | HCR_IMO_BIT | HCR_FMO_BIT + | HCR_TSC_BIT | HCR_TAC_BIT | HCR_RW_BIT; + int err; + + /* link to ID-mapping of trampoline page */ + err = paging_create_hvpt_link(&cpu_data->pg_structs, + paging_hvirt2phys(&__trampoline_start)); + if (err) + return err; + + /* switch to the permanent page tables */ + enable_mmu_el2(paging_hvirt2phys(cpu_data->pg_structs.root_table)); + + err = arm_cpu_init(cpu_data); + if (err) + return err; + + if (sdei_available) { + if (smc_arg5(SDEI_EVENT_REGISTER, 0, + (unsigned long)sdei_handler, LOCAL_CPU_BASE, + 0, 0) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + + if (smc_arg1(SDEI_EVENT_ENABLE, 0) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + + if (smc(SDEI_PE_UNMASK) != ARM_SMCCC_SUCCESS) + return trace_error(-EIO); + + hcr &= ~(HCR_IMO_BIT | HCR_FMO_BIT); + } + + /* Setup guest traps */ + arm_write_sysreg(HCR_EL2, hcr); + + /* Conditionally switch to hardened vectors */ + if (this_cpu_data()->smccc_feat_workaround_1 >= ARM_SMCCC_SUCCESS) + arm_write_sysreg(vbar_el2, &hyp_vectors_hardened); + + return 0; +} + +void __attribute__((noreturn)) arch_cpu_activate_vmm(void) +{ + unsigned int cpu_id = this_cpu_id(); + + /* + * Switch the stack to the private mapping before deactivating the + * common one. + */ + asm volatile( + "add sp, sp, %0" + : : "g" (LOCAL_CPU_BASE - (unsigned long)per_cpu(cpu_id))); + + /* Revoke full per_cpu access now that everything is set up. */ + paging_map_all_per_cpu(cpu_id, false); + + /* return to the caller in Linux */ + arm_write_sysreg(ELR_EL2, this_cpu_data()->guest_regs.usr[30]); + + vmreturn(&this_cpu_data()->guest_regs); +} + +/* disable the hypervisor on the current CPU */ +void arch_shutdown_self(struct per_cpu *cpu_data) +{ + void (*shutdown_func)(struct per_cpu *) = + (void (*)(struct per_cpu *))paging_hvirt2phys(shutdown_el2); + + if (sdei_available) { + smc(SDEI_PE_MASK); + smc_arg1(SDEI_EVENT_UNREGISTER, 0); + } + + irqchip_cpu_shutdown(&cpu_data->public); + + /* Free the guest */ + arm_write_sysreg(HCR_EL2, HCR_RW_BIT); + arm_write_sysreg(VTCR_EL2, VTCR_RES1); + + /* Remove stage-2 mappings */ + arm_paging_vcpu_flush_tlbs(); + + /* TLB flush needs the cell's VMID */ + isb(); + arm_write_sysreg(VTTBR_EL2, 0); + + /* we will restore the root cell state with the MMU turned off, + * so we need to make sure it has been committed to memory */ + arch_paging_flush_cpu_caches(cpu_data, sizeof(*cpu_data)); + dsb(ish); + + /* hand over control of EL2 back to Linux */ + asm volatile("msr vbar_el2, %0" + :: "r" (hypervisor_header.arm_linux_hyp_vectors)); + + /* Return to EL1 */ + shutdown_func((struct per_cpu *)paging_hvirt2phys(cpu_data)); +} + +void arch_cpu_restore(unsigned int cpu_id, int return_code) +{ + struct per_cpu *cpu_data = per_cpu(cpu_id); + + /* Jailhouse initialization failed; return to the caller in EL1 */ + arm_write_sysreg(ELR_EL2, cpu_data->guest_regs.usr[30]); + + cpu_data->guest_regs.usr[0] = return_code; + + arch_shutdown_self(cpu_data); +} diff --git a/hypervisor/arch/arm64/smmu-v3.c b/hypervisor/arch/arm64/smmu-v3.c new file mode 100644 index 0000000000000000000000000000000000000000..5a76a68daab5747112d7ff86cbb225ca91c3f944 --- /dev/null +++ b/hypervisor/arch/arm64/smmu-v3.c @@ -0,0 +1,1137 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + * + * Authors: + * Lokesh Vutla + * Pratyush Yadav + * + * The guest cells are assigned stream IDs in their configs and only those + * assigned stream IDs can be used by the cells. There is no checking in place + * to make sure two cells do not use the same stream IDs. This must be taken + * care of when creating the cell configs. + * + * This driver is implemented based on the following assumptions: + * - Running on a Little endian 64 bit core compatible with ARM v8 architecture. + * - SMMU supporting only AARCH64 mode. + * - SMMU AARCH 64 stage 2 translation configurations are compatible with ARMv8 + * VMSA. So re using the translation tables of CPU for SMMU. + * + * This driver is loosely based on the Linux kernel SMMU v3 driver. + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offset of addr from start of the page. */ +#define PAGE_OFFSET(addr) ((addr) & PAGE_OFFS_MASK) + +#define LOWER_32_BITS(n) ((u32)(n)) +#define UPPER_32_BITS(n) ((n) >> 32) + +/* MMIO registers */ +#define ARM_SMMU_IDR0 0x0 +#define IDR0_ST_LVL BIT_MASK(28, 27) +#define IDR0_TTENDIAN BIT_MASK(22, 21) +#define IDR0_VATOS (1 << 20) +#define IDR0_VMID16 (1 << 18) +#define IDR0_PRI (1 << 16) +#define IDR0_ATOS (1 << 15) +#define IDR0_MSI (1 << 13) +#define IDR0_ASID16 (1 << 12) +#define IDR0_NS1ATS (1 << 11) +#define IDR0_ATS (1 << 10) +#define IDR0_S2P (1 << 0) +#define IDR0_S1P (1 << 1) +#define IDR0_HTTU BIT_MASK(7, 6) +#define IDR0_COHACC (1 << 4) +#define IDR0_TTF BIT_MASK(3, 2) + +#define IDR0_TTF_AARCH64 2 +#define IDR0_TTENDIAN_LE 2 +#define IDR0_ST_LVL_2LVL 1 + +#define ARM_SMMU_VMID8_MAX_VMID 255 + +#define ARM_SMMU_IDR1 0x4 +#define IDR1_TABLES_PRESET (1 << 30) +#define IDR1_QUEUES_PRESET (1 << 29) +#define IDR1_REL (1 << 28) +#define IDR1_CMDQS BIT_MASK(25, 21) +#define IDR1_EVTQS BIT_MASK(20, 16) +#define IDR1_SSIDSIZE BIT_MASK(10, 6) +#define IDR1_SIDSIZE BIT_MASK(5, 0) + +#define ARM_SMMU_IDR2 0x8 +#define ARM_SMMU_IDR3 0xC +#define ARM_SMMU_IDR4 0x10 +#define ARM_SMMU_IDR5 0x14 + +#define ARM_SMMU_CR0 0x20 +#define CR0_CMDQEN (1 << 3) +#define CR0_EVTQEN (1 << 2) +#define CR0_SMMUEN (1 << 0) + +#define ARM_SMMU_CR0ACK 0x24 + +#define ARM_SMMU_CR1 0x28 +#define CR1_TABLE_SH BIT_MASK(11, 10) +#define CR1_TABLE_OC BIT_MASK(9, 8) +#define CR1_TABLE_IC BIT_MASK(7, 6) +#define CR1_QUEUE_SH BIT_MASK(5, 4) +#define CR1_QUEUE_OC BIT_MASK(3, 2) +#define CR1_QUEUE_IC BIT_MASK(1, 0) +/* CR1 cacheability fields don't quite follow the usual TCR-style encoding */ +#define CR1_CACHE_NC 0 +#define CR1_CACHE_WB 1 +#define CR1_CACHE_WT 2 + +#define ARM_SMMU_CR2 0x2c +#define CR2_PTM (1 << 2) +#define CR2_RECINVSID (1 << 1) +#define CR2_E2H (1 << 0) + +#define ARM_SMMU_STRTAB_BASE 0x80 +#define STRTAB_BASE_RA (1UL << 62) +#define STRTAB_BASE_ADDR_MASK BIT_MASK(51, 6) + +#define ARM_SMMU_STRTAB_BASE_CFG 0x88 +#define STRTAB_BASE_CFG_FMT BIT_MASK(17, 16) +#define STRTAB_BASE_CFG_FMT_LINEAR 0 +#define STRTAB_BASE_CFG_FMT_2LVL 1 +#define STRTAB_BASE_CFG_SPLIT BIT_MASK(10, 6) +#define STRTAB_BASE_CFG_LOG2SIZE BIT_MASK(5, 0) + +#define ARM_SMMU_CMDQ_BASE 0x90 +#define ARM_SMMU_CMDQ_PROD 0x98 +#define ARM_SMMU_CMDQ_CONS 0x9c + +#define ARM_SMMU_EVTQ_BASE 0xa0 +#define ARM_SMMU_EVTQ_PROD 0x100a8 +#define ARM_SMMU_EVTQ_CONS 0x100ac +#define ARM_SMMU_EVTQ_IRQ_CFG0 0xb0 +#define ARM_SMMU_EVTQ_IRQ_CFG1 0xb8 +#define ARM_SMMU_EVTQ_IRQ_CFG2 0xbc + +#define ARM_SMMU_GERROR 0x60 +#define GERROR_CMDQ_ERR (1 << 0) +#define GERROR_EVTQ_ABT_ERR (1 << 2) + +#define ARM_SMMU_GERRORN 0x64 +#define ARM_SMMU_IRQ_CTRL 0x50 +#define ARM_SMMU_IRQ_CTRLACK 0x54 +#define ARM_SMMU_GERROR_IRQ_CFG0 0x68 +#define ARM_SMMU_EVTQ_IRQ_CFG0 0xb0 + +/* Common memory attribute values */ +#define ARM_SMMU_SH_NSH 0 +#define ARM_SMMU_SH_OSH 2 +#define ARM_SMMU_SH_ISH 3 +#define ARM_SMMU_MEMATTR_DEVICE_nGnRE 0x1 +#define ARM_SMMU_MEMATTR_OIWB 0xf + +#define Q_IDX(reg, shift) ((reg) & ((1 << (shift)) - 1)) +#define Q_WRP(reg, shift) ((reg) & (1 << (shift))) +#define Q_OVERFLOW_FLAG (1 << 31) +#define Q_OVF(reg) ((reg) & Q_OVERFLOW_FLAG) +#define Q_EMPTY(prod, cons, shift) \ + (Q_IDX((prod), (shift)) == Q_IDX((cons), (shift)) && \ + Q_WRP((prod), (shift)) == Q_WRP((cons), (shift))) +#define Q_FULL(prod, cons, shift) \ + (Q_IDX((prod), (shift)) == Q_IDX((cons), (shift)) && \ + Q_WRP((prod), (shift)) != Q_WRP((cons), (shift))) + +#define Q_BASE_RWA (1UL << 62) +#define Q_BASE_ADDR_MASK BIT_MASK(51, 5) +#define Q_BASE_LOG2SIZE BIT_MASK(4, 0) + +/* + * Stream table. + * + * Linear: Enough to cover 1 << IDR1.SIDSIZE entries + * 2lvl: 128k L1 entries, + * 256 lazy entries per table (each table covers a PCI bus) + */ +#define STRTAB_L1_SZ_SHIFT 20 +#define STRTAB_SPLIT 8 + +#define STRTAB_L1_DESC_DWORDS 1 +#define STRTAB_L1_DESC_SIZE (STRTAB_L1_DESC_DWORDS << 3) +#define STRTAB_L1_DESC_SPAN BIT_MASK(4, 0) +#define STRTAB_L1_DESC_L2PTR_MASK BIT_MASK(51, 6) + +#define STRTAB_STE_DWORDS_BITS 3 +#define STRTAB_STE_DWORDS (1 << STRTAB_STE_DWORDS_BITS) +#define STRTAB_STE_SIZE (STRTAB_STE_DWORDS << 3) +#define STRTAB_STE_0_V (1UL << 0) +#define STRTAB_STE_0_CFG BIT_MASK(3, 1) +#define STRTAB_STE_0_CFG_ABORT 0 +#define STRTAB_STE_0_CFG_BYPASS 4 +#define STRTAB_STE_0_CFG_S1_TRANS 5 +#define STRTAB_STE_0_CFG_S2_TRANS 6 +#define STRTAB_STE_0_S1CTXPTR BIT_MASK(51, 6) +#define STRTAB_STE_0_S1CDMAX BIT_MASK(63, 59) +#define STRTAB_STE_1_S1DSS BIT_MASK(1, 0) +#define STRTAB_STE_1_S1CIR BIT_MASK(3, 2) +#define STRTAB_STE_1_S1COR BIT_MASK(5, 4) +#define STRTAB_STE_1_S1CSH BIT_MASK(7, 6) +#define STRTAB_STE_1_S1STALLD (1UL << 27) +#define STRTAB_CTXDESC_DWORDS 8 +#define STRTAB_CTXDESC_S1CTXPTR_SHIFT 6 + +#define STRTAB_STE_1_SHCFG BIT_MASK(45, 44) +#define STRTAB_STE_1_SHCFG_INCOMING 1UL + +#define STRTAB_STE_2_S2VMID BIT_MASK(15, 0) +#define STRTAB_STE_2_VTCR BIT_MASK(50, 32) +#define STRTAB_STE_2_S2AA64 (1UL << 51) +#define STRTAB_STE_2_S2ENDI (1UL << 52) +#define STRTAB_STE_2_S2PTW (1UL << 54) +#define STRTAB_STE_2_S2R (1UL << 58) + +#define STRTAB_STE_3_S2TTB_MASK BIT_MASK(51, 4) + +#define CTXDESC_1_TTB0 BIT_MASK(51, 4) +#define CTXDESC_2_TTB1 BIT_MASK(51, 4) +#define CTXDESC_TTB0_SHIFT 4 +#define CTXDESC_TTB1_SHIFT 4 + +/* Command queue */ +#define CMDQ_ENT_DWORDS 2 +#define CMDQ_ENT_SIZE (CMDQ_ENT_DWORDS << 3) +#define CMDQ_MAX_SZ_SHIFT 8 + +#define CMDQ_CONS_ERR BIT_MASK(30, 24) +#define CMDQ_ERR_CERROR_NONE_IDX 0 +#define CMDQ_ERR_CERROR_ILL_IDX 1 +#define CMDQ_ERR_CERROR_ABT_IDX 2 + +#define CMDQ_0_OP BIT_MASK(7, 0) +#define CMDQ_0_SSV (1UL << 11) + +#define CMDQ_PREFETCH_0_SSID BIT_MASK(31, 12) +#define CMDQ_PREFETCH_0_SID BIT_MASK(63, 32) +#define CMDQ_PREFETCH_1_SIZE BIT_MASK(4, 0) +#define CMDQ_PREFETCH_1_ADDR_MASK BIT_MASK(63, 12) + +#define CMDQ_CFGI_0_SID BIT_MASK(63, 32) +#define CMDQ_CFGI_1_LEAF (1UL << 0) +#define CMDQ_CFGI_1_RANGE BIT_MASK(4, 0) + +#define CMDQ_TLBI_0_VMID BIT_MASK(47, 32) +#define CMDQ_TLBI_0_ASID BIT_MASK(63, 48) +#define CMDQ_TLBI_1_LEAF (1UL << 0) +#define CMDQ_TLBI_1_VA_MASK BIT_MASK(63, 12) +#define CMDQ_TLBI_1_IPA_MASK BIT_MASK(51, 12) + +#define CMDQ_PRI_0_SSID BIT_MASK(31, 12) +#define CMDQ_PRI_0_SID BIT_MASK(63, 32) +#define CMDQ_PRI_1_GRPID BIT_MASK(8, 0) +#define CMDQ_PRI_1_RESP BIT_MASK(13, 12) + +#define CMDQ_SYNC_0_CS BIT_MASK(13, 12) +#define CMDQ_SYNC_0_CS_NONE 0 +#define CMDQ_SYNC_0_CS_IRQ 1 +#define CMDQ_SYNC_0_CS_SEV 2 +#define CMDQ_SYNC_0_MSH BIT_MASK(23, 22) +#define CMDQ_SYNC_0_MSIATTR BIT_MASK(27, 24) +#define CMDQ_SYNC_0_MSIDATA BIT_MASK(63, 32) +#define CMDQ_SYNC_1_MSIADDR_MASK BIT_MASK(51, 2) + +/* Event queue */ +#define EVTQ_ENT_DWORDS 4 +#define EVTQ_MAX_SZ_SHIFT 7 + +#define EVTQ_0_ID BIT_MASK(7, 0) + +#define ARM_SMMU_SYNC_TIMEOUT 1000000 + +#define FIELD_PREP(mask, val) \ + (((u64)(val) << (__builtin_ffsl((mask)) - 1)) & (mask)) +#define FIELD_GET(mask, reg) \ + (((reg) & (mask)) >> (__builtin_ffsl((mask)) - 1)) +#define FIELD_CLEAR(mask, reg) \ + ((reg) & (~(mask))) + +#define CMDQ_OP_PREFETCH_CFG 0x1 +#define CMDQ_OP_PREFETCH_ADDR 0x2 +#define CMDQ_OP_CFGI_STE 0x3 +#define CMDQ_OP_CFGI_ALL 0x4 +#define CMDQ_OP_TLBI_NH_ASID 0x11 +#define CMDQ_OP_TLBI_NH_VA 0x12 +#define CMDQ_OP_TLBI_EL2_ALL 0x20 +#define CMDQ_OP_TLBI_S12_VMALL 0x28 +#define CMDQ_OP_TLBI_S2_IPA 0x2a +#define CMDQ_OP_TLBI_NSNH_ALL 0x30 +#define CMDQ_OP_CMD_SYNC 0x46 +#define ARM_SMMU_FEAT_2_LVL_STRTAB (1 << 0) + +/* High-level queue structures */ +struct arm_smmu_cmdq_ent { + /* Common fields */ + u8 opcode; + bool substream_valid; + + /* Command-specific fields */ + union { + struct { + u32 sid; + u8 size; + u64 addr; + } prefetch; + + struct { + u32 sid; + union { + bool leaf; + u8 span; + }; + } cfgi; + + struct { + u16 asid; + u16 vmid; + bool leaf; + u64 addr; + } tlbi; + + struct { + u32 msidata; + u64 msiaddr; + } sync; + }; +}; + +struct arm_smmu_queue { + u64 *base; + u64 base_dma; + u64 q_base; + u64 ent_dwords; + u32 max_n_shift; + u32 prod; + u32 cons; + u32 *prod_reg; + u32 *cons_reg; + u32 gerr_mask; +}; + +struct arm_smmu_cmdq { + struct arm_smmu_queue q; + spinlock_t lock; +}; + +struct arm_smmu_evtq { + struct arm_smmu_queue q; +}; + +/* High-level stream table structures */ +struct arm_smmu_strtab_l1_desc { + u8 span; + u64 *l2ptr; + u64 l2ptr_dma; + u32 active_stes; +}; + +struct arm_smmu_strtab_cfg { + u64 *strtab; + u64 strtab_dma; + struct arm_smmu_strtab_l1_desc *l1_desc; + unsigned int num_l1_ents; + u64 strtab_base; + u32 strtab_base_cfg; +}; + +/* An SMMUv3 instance */ +struct arm_smmu_device { + void *base; + u32 features; + struct arm_smmu_cmdq cmdq; + struct arm_smmu_evtq evtq; + unsigned int sid_bits; + struct arm_smmu_strtab_cfg strtab_cfg; +}; + +static struct arm_smmu_device smmu_devices[JAILHOUSE_MAX_IOMMU_UNITS]; + +/* Low-level queue manipulation functions */ +static bool queue_full(struct arm_smmu_queue *q) +{ + u32 shift = q->max_n_shift; + + return Q_FULL(q->prod, q->cons, shift); +} + +static bool queue_empty(struct arm_smmu_queue *q) +{ + u32 shift = q->max_n_shift; + + return Q_EMPTY(q->prod, q->cons, shift); +} + +static void queue_sync_cons(struct arm_smmu_queue *q) +{ + q->cons = mmio_read32(q->cons_reg); +} + +static bool queue_error(struct arm_smmu_device *smmu, struct arm_smmu_queue *q) +{ + u32 gerror, gerrorn; + + gerror = mmio_read32(smmu->base + ARM_SMMU_GERROR); + gerrorn = mmio_read32(smmu->base + ARM_SMMU_GERRORN); + + return (gerror ^ gerrorn) & q->gerr_mask; +} + +static void queue_inc_prod(struct arm_smmu_queue *q) +{ + u32 shift = q->max_n_shift; + u32 prod = (Q_WRP(q->prod, shift) | Q_IDX(q->prod, shift)) + 1; + + q->prod = Q_OVF(q->prod) | Q_WRP(prod, shift) | Q_IDX(prod, shift); + mmio_write32(q->prod_reg, q->prod); +} + +static void queue_write(u64 *dst, u64 *src, u32 n_dwords) +{ + u32 n; + + for (n = 0; n < n_dwords; ++n) + *dst++ = *src++; + dsb(ishst); +} + +static u64 *queue_entry(struct arm_smmu_queue *q, u32 reg) +{ + return q->base + (Q_IDX(reg, q->max_n_shift) * q->ent_dwords); +} + +/* High-level queue accessors */ +static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) +{ + memset(cmd, 0, CMDQ_ENT_SIZE); + cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode); + + switch (ent->opcode) { + case CMDQ_OP_TLBI_EL2_ALL: + case CMDQ_OP_TLBI_NSNH_ALL: + break; + case CMDQ_OP_PREFETCH_ADDR: + cmd[1] |= FIELD_PREP(CMDQ_PREFETCH_1_SIZE, ent->prefetch.size); + cmd[1] |= ent->prefetch.addr & CMDQ_PREFETCH_1_ADDR_MASK; + /* Fallthrough */ + case CMDQ_OP_PREFETCH_CFG: + cmd[0] |= FIELD_PREP(CMDQ_PREFETCH_0_SID, ent->prefetch.sid); + break; + case CMDQ_OP_CFGI_STE: + cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid); + cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_LEAF, ent->cfgi.leaf); + break; + case CMDQ_OP_CFGI_ALL: + /* Cover the entire SID range */ + cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31); + break; + case CMDQ_OP_TLBI_NH_VA: + cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid); + cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid); + cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf); + cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK; + break; + case CMDQ_OP_TLBI_S2_IPA: + cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid); + cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf); + cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK; + break; + case CMDQ_OP_TLBI_NH_ASID: + cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid); + /* Fallthrough */ + case CMDQ_OP_TLBI_S12_VMALL: + cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid); + break; + case CMDQ_OP_CMD_SYNC: + if (ent->sync.msiaddr) + cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ); + else + cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV); + cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH) | + FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB) | + FIELD_PREP(CMDQ_SYNC_0_MSIDATA, ent->sync.msidata); + cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK; + break; + default: + return trace_error(-ENOENT); + } + + return 0; +} + +static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu) +{ + struct arm_smmu_queue *q; + u64 cmd[CMDQ_ENT_DWORDS]; + u32 gerrorn; + struct arm_smmu_cmdq_ent cmd_sync = { + .opcode = CMDQ_OP_CMD_SYNC, + }; + + q = &smmu->cmdq.q; + + /* + * Convert the faulty command to sync and clear the error so + * command consumption can continue. + */ + arm_smmu_cmdq_build_cmd(cmd, &cmd_sync); + queue_write(queue_entry(q, q->cons), cmd, q->ent_dwords); + + gerrorn = mmio_read32(smmu->base + ARM_SMMU_GERRORN); + + gerrorn ^= GERROR_CMDQ_ERR; + mmio_write32(smmu->base + ARM_SMMU_GERRORN, gerrorn); +} + +static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd) +{ + struct arm_smmu_queue *q = &smmu->cmdq.q; + + while (queue_full(q)) + queue_sync_cons(q); + + queue_write(queue_entry(q, q->prod), cmd, q->ent_dwords); + queue_inc_prod(q); + while (!queue_empty(q)) { + queue_sync_cons(q); + if (queue_error(smmu, q)) + arm_smmu_cmdq_skip_err(smmu); + } +} + +static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, + struct arm_smmu_cmdq_ent *ent) +{ + u64 cmd[CMDQ_ENT_DWORDS]; + + if (arm_smmu_cmdq_build_cmd(cmd, ent)) + /* Ignore any unknown command */ + return; + + spin_lock(&smmu->cmdq.lock); + arm_smmu_cmdq_insert_cmd(smmu, cmd); + spin_unlock(&smmu->cmdq.lock); +} + +static void arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu) +{ + struct arm_smmu_cmdq_ent ent = { .opcode = CMDQ_OP_CMD_SYNC }; + u64 cmd[CMDQ_ENT_DWORDS]; + + arm_smmu_cmdq_build_cmd(cmd, &ent); + + spin_lock(&smmu->cmdq.lock); + arm_smmu_cmdq_insert_cmd(smmu, cmd); + spin_unlock(&smmu->cmdq.lock); +} + +/* Stream table manipulation functions */ +static void +arm_smmu_write_strtab_l1_desc(u64 *dst, struct arm_smmu_strtab_l1_desc *desc) +{ + u64 val = 0; + + val |= FIELD_PREP(STRTAB_L1_DESC_SPAN, desc->span); + val |= desc->l2ptr_dma & STRTAB_L1_DESC_L2PTR_MASK; + + /* Assuming running on Little endian cpu */ + *dst = val; + dsb(ishst); +} + +static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid) +{ + struct arm_smmu_cmdq_ent cmd = { + .opcode = CMDQ_OP_CFGI_STE, + .cfgi = { + .sid = sid, + .leaf = true, + }, + }; + + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + arm_smmu_cmdq_issue_sync(smmu); +} + +static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, + u64 *guest_ste, u64 *dst, bool bypass, + u32 vmid) +{ + struct paging_structures *pg_structs = &this_cell()->arch.mm; + u64 val, vttbr; + + val = 0; + + /* Bypass */ + if (bypass) { + val = STRTAB_STE_0_V; + val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS); + dst[1] = FIELD_PREP(STRTAB_STE_1_SHCFG, + STRTAB_STE_1_SHCFG_INCOMING); + dst[2] = FIELD_PREP(STRTAB_STE_2_S2VMID, vmid); + dst[0] = val; + dsb(ishst); + if (smmu) + arm_smmu_sync_ste_for_sid(smmu, sid); + return; + } + + dst[2] = FIELD_PREP(STRTAB_STE_2_S2VMID, vmid) | + FIELD_PREP(STRTAB_STE_2_VTCR, VTCR_CELL) | + STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 | + STRTAB_STE_2_S2R; + + vttbr = paging_hvirt2phys(pg_structs->root_table); + dst[3] = vttbr & STRTAB_STE_3_S2TTB_MASK; + + val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S2_TRANS); + val |= STRTAB_STE_0_V; + + arm_smmu_sync_ste_for_sid(smmu, sid); + dst[0] = val; + dsb(ishst); + arm_smmu_sync_ste_for_sid(smmu, sid); +} + +static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent) +{ + unsigned int n; + + for (n = 0; n < nent; ++n) { + arm_smmu_write_strtab_ent(NULL, -1, NULL, strtab, true, + (u32)this_cell()->config->id); + strtab += STRTAB_STE_DWORDS; + } +} + +static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu) +{ + void *strtab; + u64 reg; + u32 size; + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + + size = (1 << smmu->sid_bits) * STRTAB_STE_SIZE; + strtab = page_alloc_aligned(&mem_pool, PAGES(size)); + if (!strtab) + return -ENOMEM; + + cfg->strtab_dma = paging_hvirt2phys(strtab); + cfg->strtab = strtab; + cfg->num_l1_ents = 1 << smmu->sid_bits; + + /* Configure strtab_base_cfg for a linear table covering all SIDs */ + reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_LINEAR); + reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits); + cfg->strtab_base_cfg = reg; + + arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents); + return 0; +} + +static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu) +{ + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + u32 size = sizeof(*cfg->l1_desc) * cfg->num_l1_ents; + void *strtab = smmu->strtab_cfg.strtab; + unsigned int n; + + cfg->l1_desc = page_alloc(&mem_pool, PAGES(size)); + if (!cfg->l1_desc) + return -ENOMEM; + + for (n = 0; n < cfg->num_l1_ents; ++n) { + memset(&cfg->l1_desc[n], 0, sizeof(*cfg->l1_desc)); + arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[n]); + strtab += STRTAB_L1_DESC_SIZE; + } + + return 0; +} + +static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu) +{ + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + u32 size, l1size; + void *strtab; + u64 reg; + int ret; + + /* Calculate the L1 size, capped to the SIDSIZE. */ + size = STRTAB_L1_SZ_SHIFT - 3; + size = MIN(size, smmu->sid_bits - STRTAB_SPLIT); + cfg->num_l1_ents = 1 << size; + size += STRTAB_SPLIT; + + /* + * This driver only supports "size" bits out of "smmu->sid_bits" + * that is specified by hardware. + */ + if (size < smmu->sid_bits) { + printk("WARN: SMMU 2-level strtab only covers %u/%u bits of SID\n", + size, smmu->sid_bits); + smmu->sid_bits = size; + } + + l1size = cfg->num_l1_ents * STRTAB_L1_DESC_SIZE; + strtab = page_alloc_aligned(&mem_pool, PAGES(l1size)); + if (!strtab) + return -ENOMEM; + + cfg->strtab_dma = paging_hvirt2phys(strtab); + cfg->strtab = strtab; + + /* Configure strtab_base_cfg for 2 levels */ + reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_2LVL); + reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, size); + reg |= FIELD_PREP(STRTAB_BASE_CFG_SPLIT, STRTAB_SPLIT); + cfg->strtab_base_cfg = reg; + + ret = arm_smmu_init_l1_strtab(smmu); + if (ret) + page_free(&mem_pool, strtab, PAGES(l1size)); + + return ret; +} + +static int arm_smmu_init_strtab(struct arm_smmu_device *smmu) +{ + u64 reg; + int ret; + + if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) + ret = arm_smmu_init_strtab_2lvl(smmu); + else + ret = arm_smmu_init_strtab_linear(smmu); + + if (ret) + return ret; + + /* Set the strtab base address */ + reg = smmu->strtab_cfg.strtab_dma & STRTAB_BASE_ADDR_MASK; + reg |= STRTAB_BASE_RA; + smmu->strtab_cfg.strtab_base = reg; + + return 0; +} + +static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, + struct arm_smmu_queue *q, + unsigned long prod_off, + unsigned long cons_off, + unsigned long dwords, + unsigned int gerr_mask) +{ + /* Queue size is capped to 4K. So allocate 1 page */ + q->base = page_alloc(&mem_pool, 1); + if (!q->base) + return -ENOMEM; + + q->base_dma = paging_hvirt2phys(q->base); + + q->prod_reg = smmu->base + prod_off; + q->cons_reg = smmu->base + cons_off; + q->ent_dwords = dwords; + + q->q_base = Q_BASE_RWA; + q->q_base |= q->base_dma & Q_BASE_ADDR_MASK; + q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->max_n_shift); + + q->gerr_mask = gerr_mask; + q->prod = q->cons = 0; + + return 0; +} + +static int arm_smmu_init_queues(struct arm_smmu_device *smmu) +{ + int ret; + + /* cmdq */ + ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD, + ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS, + GERROR_CMDQ_ERR); + if (ret) + return ret; + + /* evtq */ + ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD, + ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS, + GERROR_EVTQ_ABT_ERR); + if (ret) + return ret; + + return ret; +} + +static int arm_smmu_init_structures(struct arm_smmu_device *smmu) +{ + int ret; + + ret = arm_smmu_init_queues(smmu); + if (ret) + return ret; + + return arm_smmu_init_strtab(smmu); +} + +static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val, + unsigned int reg_off, unsigned int ack_off) +{ + u32 n, timeout = ARM_SMMU_SYNC_TIMEOUT; + + mmio_write32(smmu->base + reg_off, val); + for (n = 0; n < timeout; n++) { + if (mmio_read32(smmu->base + ack_off) == val) + return 0; + } + + return trace_error(-EINVAL); +} + +static int arm_smmu_device_reset(struct arm_smmu_device *smmu) +{ + int ret; + u32 reg, enables; + struct arm_smmu_cmdq_ent cmd; + + /* Clear CR0 and sync (disables SMMU and queue processing) */ + ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_CR0, ARM_SMMU_CR0ACK); + if (ret) + return ret; + + /* CR1 (table and queue memory attributes) */ + reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_ISH) | + FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_WB) | + FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_WB) | + FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_ISH) | + FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_WB) | + FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_WB); + mmio_write32(smmu->base + ARM_SMMU_CR1, reg); + + /* Stream table */ + mmio_write64(smmu->base + ARM_SMMU_STRTAB_BASE, + smmu->strtab_cfg.strtab_base); + mmio_write32(smmu->base + ARM_SMMU_STRTAB_BASE_CFG, + smmu->strtab_cfg.strtab_base_cfg); + + /* Command queue */ + mmio_write64(smmu->base + ARM_SMMU_CMDQ_BASE, smmu->cmdq.q.q_base); + mmio_write32(smmu->base + ARM_SMMU_CMDQ_PROD, smmu->cmdq.q.prod); + mmio_write32(smmu->base + ARM_SMMU_CMDQ_CONS, smmu->cmdq.q.cons); + + enables = CR0_CMDQEN; + ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, + ARM_SMMU_CR0ACK); + if (ret) + return ret; + + /* Invalidate any cached configuration */ + cmd.opcode = CMDQ_OP_CFGI_ALL; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + arm_smmu_cmdq_issue_sync(smmu); + + cmd.opcode = CMDQ_OP_TLBI_NSNH_ALL; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + + /* Invalidate any stale TLB entries */ + cmd.opcode = CMDQ_OP_TLBI_EL2_ALL; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + arm_smmu_cmdq_issue_sync(smmu); + + /* Event queue */ + mmio_write64(smmu->base + ARM_SMMU_EVTQ_BASE, smmu->evtq.q.q_base); + mmio_write32(smmu->base + ARM_SMMU_EVTQ_PROD, smmu->evtq.q.prod); + mmio_write32(smmu->base + ARM_SMMU_EVTQ_CONS, smmu->evtq.q.cons); + + enables |= CR0_EVTQEN; + ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, + ARM_SMMU_CR0ACK); + if (ret) + return ret; + + /* ToDo: Add support for PRI queue and IRQs */ + + enables |= CR0_SMMUEN; + ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, + ARM_SMMU_CR0ACK); + + return ret; +} + +static int arm_smmu_device_init_features(struct arm_smmu_device *smmu) +{ + u32 reg; + + /* IDR0 */ + reg = mmio_read32(smmu->base + ARM_SMMU_IDR0); + + smmu->features = 0; + /* 2-level structures */ + if (FIELD_GET(IDR0_ST_LVL, reg) == IDR0_ST_LVL_2LVL) + smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB; + + if (!(reg & IDR0_S2P)) + return trace_error(-ENODEV); + + if (FIELD_GET(IDR0_S1P, reg)) + smmu->features |= IDR0_S1P; + + if (FIELD_GET(IDR0_VMID16, reg)) + smmu->features |= IDR0_VMID16; + + /* IDR1 */ + reg = mmio_read32(smmu->base + ARM_SMMU_IDR1); + if (reg & (IDR1_TABLES_PRESET | IDR1_QUEUES_PRESET | IDR1_REL)) + return trace_error(-ENODEV); + + /* Queue sizes, capped at 4k */ + smmu->cmdq.q.max_n_shift = MIN(CMDQ_MAX_SZ_SHIFT, + FIELD_GET(IDR1_CMDQS, reg)); + if (!smmu->cmdq.q.max_n_shift) + return trace_error(-ENODEV); + + smmu->evtq.q.max_n_shift = MIN(EVTQ_MAX_SZ_SHIFT, + FIELD_GET(IDR1_EVTQS, reg)); + + /* SID sizes */ + smmu->sid_bits = FIELD_GET(IDR1_SIDSIZE, reg); + + /* + * If the SMMU supports fewer bits than would fill a single L2 stream + * table, use a linear table instead. + */ + if (smmu->sid_bits <= STRTAB_SPLIT) + smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB; + + return 0; +} + +static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid) +{ + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + struct arm_smmu_strtab_l1_desc *desc; + struct arm_smmu_cmdq_ent cmd; + void *strtab; + u32 size; + + desc = &cfg->l1_desc[sid >> STRTAB_SPLIT]; + if (desc->l2ptr) { + desc->active_stes++; + return 0; + } + + size = 1 << (STRTAB_SPLIT + STRTAB_STE_DWORDS_BITS + 3); + strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS]; + + desc->span = STRTAB_SPLIT + 1; + desc->l2ptr = page_alloc_aligned(&mem_pool, PAGES(size)); + if (!desc->l2ptr) + return trace_error(-ENOMEM); + + desc->l2ptr_dma = paging_hvirt2phys(desc->l2ptr); + desc->active_stes = 1; + arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT); + arm_smmu_write_strtab_l1_desc(strtab, desc); + + /* Invalidate cached L1 descriptors. */ + cmd.opcode = CMDQ_OP_CFGI_STE; + cmd.cfgi.sid = sid; + cmd.cfgi.leaf = false; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + + return 0; +} + +static void arm_smmu_uninit_l2_strtab(struct arm_smmu_device *smmu, u32 sid) +{ + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + struct arm_smmu_strtab_l1_desc *desc; + struct arm_smmu_cmdq_ent cmd; + void *strtab; + u32 size; + + desc = &cfg->l1_desc[sid >> STRTAB_SPLIT]; + + desc->active_stes--; + if (desc->active_stes) + return; + + desc->l2ptr = NULL; + desc->l2ptr_dma = 0; + desc->span = 0; + strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS]; + arm_smmu_write_strtab_l1_desc(strtab, desc); + + /* Invalidate cached L1 descriptors. */ + cmd.opcode = CMDQ_OP_CFGI_STE; + cmd.cfgi.sid = sid; + cmd.cfgi.leaf = false; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + + size = 1 << (STRTAB_SPLIT + STRTAB_STE_DWORDS_BITS + 3); + page_free(&mem_pool, desc->l2ptr, PAGES(size)); +} + +static u64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) +{ + u64 *step; + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + + if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { + struct arm_smmu_strtab_l1_desc *l1_desc; + int idx; + + /* Two-level walk */ + idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS; + l1_desc = &cfg->l1_desc[idx]; + idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS; + step = &l1_desc->l2ptr[idx]; + } else { + /* Simple linear lookup */ + step = &cfg->strtab[sid * STRTAB_STE_DWORDS]; + } + + return step; +} + +static int arm_smmu_init_ste(struct arm_smmu_device *smmu, u32 sid, u32 vmid) +{ + int ret = 0; + u64 *step; + + if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { + ret = arm_smmu_init_l2_strtab(smmu, sid); + if (ret) + return ret; + } + + step = arm_smmu_get_step_for_sid(smmu, sid); + arm_smmu_write_strtab_ent(smmu, sid, NULL, step, false, vmid); + + return 0; +} + +static void arm_smmu_uninit_ste(struct arm_smmu_device *smmu, u32 sid, u32 vmid) +{ + u64 *step; + + step = arm_smmu_get_step_for_sid(smmu, sid); + arm_smmu_write_strtab_ent(smmu, sid, NULL, step, true, vmid); + + if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) + arm_smmu_uninit_l2_strtab(smmu, sid); +} + +static int arm_smmuv3_cell_init(struct cell *cell) +{ + struct arm_smmu_device *smmu = &smmu_devices[0]; + struct jailhouse_iommu *iommu; + struct arm_smmu_cmdq_ent cmd; + union jailhouse_stream_id sid; + unsigned int n, s; + int ret; + + if (!iommu_count_units()) + return 0; + + iommu = &system_config->platform_info.iommu_units[0]; + for (n = 0; n < iommu_count_units(); iommu++, smmu++, n++) { + if (iommu->type != JAILHOUSE_IOMMU_SMMUV3) + continue; + + for_each_stream_id(sid, cell->config, s) { + ret = arm_smmu_init_ste(smmu, sid.id, cell->config->id); + if (ret) + return ret; + } + + cmd.opcode = CMDQ_OP_TLBI_S12_VMALL; + cmd.tlbi.vmid = cell->config->id; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + arm_smmu_cmdq_issue_sync(smmu); + } + + return 0; +} + +static void arm_smmuv3_cell_exit(struct cell *cell) +{ + struct arm_smmu_device *smmu = &smmu_devices[0]; + struct jailhouse_iommu *iommu; + struct arm_smmu_cmdq_ent cmd; + union jailhouse_stream_id sid; + unsigned int n, s; + + if (!iommu_count_units()) + return; + + iommu = &system_config->platform_info.iommu_units[0]; + for (n = 0; n < JAILHOUSE_MAX_IOMMU_UNITS; iommu++, smmu++, n++) { + if (iommu->type != JAILHOUSE_IOMMU_SMMUV3) + continue; + + for_each_stream_id(sid, cell->config, s) { + arm_smmu_uninit_ste(smmu, sid.id, cell->config->id); + } + + cmd.opcode = CMDQ_OP_TLBI_S12_VMALL; + cmd.tlbi.vmid = cell->config->id; + arm_smmu_cmdq_issue_cmd(smmu, &cmd); + arm_smmu_cmdq_issue_sync(smmu); + } +} + +static int arm_smmuv3_init(void) +{ + struct arm_smmu_device *smmu = &smmu_devices[0]; + struct jailhouse_iommu *iommu; + int ret; + unsigned int n; + + iommu = &system_config->platform_info.iommu_units[0]; + for (n = 0; n < iommu_count_units(); iommu++, smmu++, n++) { + if (iommu->type != JAILHOUSE_IOMMU_SMMUV3) + continue; + + smmu->base = paging_map_device(iommu->base, iommu->size); + + /* ToDo: irq allocation*/ + + ret = arm_smmu_device_init_features(smmu); + if (ret) + return ret; + + ret = arm_smmu_init_structures(smmu); + if (ret) + return ret; + + /* Reset the device */ + ret = arm_smmu_device_reset(smmu); + if (ret) + return ret; + } + + return arm_smmuv3_cell_init(&root_cell); +} + +DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(arm_smmuv3); +DEFINE_UNIT_SHUTDOWN_STUB(arm_smmuv3); +DEFINE_UNIT(arm_smmuv3, "ARM SMMU v3"); diff --git a/hypervisor/arch/arm64/smmu.c b/hypervisor/arch/arm64/smmu.c new file mode 100644 index 0000000000000000000000000000000000000000..7869b66b8ae633d960998cf79eaba8fa98e385b0 --- /dev/null +++ b/hypervisor/arch/arm64/smmu.c @@ -0,0 +1,603 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright 2018-2020 NXP + * Copyright Siemens AG, 2020 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Modified from Linux smmu.c + */ + +#include +#include +#include +#include +#include + +#include + +#define TLB_LOOP_TIMEOUT 1000000 + +/* SMMU global address space */ +#define ARM_SMMU_GR0(smmu) ((smmu)->base) +#define ARM_SMMU_GR1(smmu) ((smmu)->base + (1 << (smmu)->pgshift)) + +/* Translation context bank */ +#define ARM_SMMU_CB(smmu, n) ((smmu)->cb_base + ((n) << (smmu)->pgshift)) + +/* Configuration Register 0 */ +#define ARM_SMMU_GR0_sCR0 0x0 +#define sCR0_CLIENTPD (1 << 0) +#define sCR0_GFRE (1 << 1) +#define sCR0_GFIE (1 << 2) +#define sCR0_GCFGFRE (1 << 4) +#define sCR0_GCFGFIE (1 << 5) +#define sCR0_USFCFG (1 << 10) +#define sCR0_VMIDPNE (1 << 11) +#define sCR0_PTM (1 << 12) +#define sCR0_FB (1 << 13) + +/* Auxiliary Configuration Register */ +#define ARM_SMMU_GR0_sACR 0x10 +#define ARM_MMU500_ACTLR_CPRE (1 << 1) +#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8) +#define ARM_MMU500_ACR_S2CRB_TLBEN (1 << 10) +#define ARM_MMU500_ACR_CACHE_LOCK (1 << 26) + +/* Identification registers */ +#define ARM_SMMU_GR0_ID0 0x20 +#define ID0_S2TS (1 << 29) +#define ID0_SMS (1 << 27) +#define ID0_CTTW (1 << 14) +#define ID0_NUMSIDB(id) GET_FIELD(id, 12, 9) +#define ID0_NUMSMRG(id) GET_FIELD(id, 7, 0) + +#define ARM_SMMU_GR0_ID1 0x24 +#define ID1_PAGESIZE (1 << 31) +#define ID1_NUMPAGENDXB(id) GET_FIELD(id, 30, 28) +#define ID1_NUMS2CB(id) GET_FIELD(id, 23, 16) +#define ID1_NUMCB(id) GET_FIELD(id, 7, 0) + +#define ARM_SMMU_GR0_ID2 0x28 +#define ID2_PTFS_4K (1 << 12) +#define ID2_OAS(id) GET_FIELD(id, 7, 4) +#define ID2_IAS(id) GET_FIELD(id, 3, 0) + +#define ARM_SMMU_GR0_ID7 0x3c +#define ID7_MAJOR(id) GET_FIELD(id, 7, 4) + +/* Global Fault Status Register */ +#define ARM_SMMU_GR0_sGFSR 0x48 + +/* TLB */ +#define ARM_SMMU_GR0_TLBIVMID 0X64 +#define ARM_SMMU_GR0_TLBIALLNSNH 0x68 +#define ARM_SMMU_GR0_TLBIALLH 0x6c +#define ARM_SMMU_GR0_sTLBGSYNC 0x70 +#define ARM_SMMU_GR0_sTLBGSTATUS 0x74 +#define sTLBGSTATUS_GSACTIVE (1 << 0) + +/* Stream Match Register */ +#define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) +#define SMR_VALID (1 << 31) +#define SMR_MASK_SHIFT 16 +#define SMR_ID_SHIFT 0 +/* Ignore upper bit in ID and MASK */ +#define SMR_GET_ID(smr) ((smr) & BIT_MASK(14, 0)) +/* Mask is already specified from bit 0 in the configuration */ +#define SMR_GET_MASK(smr) ((smr) & BIT_MASK(14, 0)) + +/* Stream-to-Context Register */ +#define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) +#define S2CR_EXIDVALID (1 << 10) + +/* Context Bank Attribute Registers */ +#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) +#define CBAR_VMID_SHIFT 0 +#define CBAR_TYPE_SHIFT 16 +#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT) + +#define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2)) +#define CBA2R_RW64_64BIT (1 << 0) + +/* Stage 1 translation context bank address space */ +#define ARM_SMMU_CB_SCTLR 0x0 +#define ARM_SMMU_CB_ACTLR 0x4 +#define ARM_SMMU_CB_TTBR0 0x20 +#define ARM_SMMU_CB_TCR 0x30 +#define ARM_SMMU_CB_FSR 0x58 + +#define SCTLR_CFIE (1 << 6) +#define SCTLR_CFRE (1 << 5) +#define SCTLR_AFE (1 << 2) +#define SCTLR_TRE (1 << 1) +#define SCTLR_M (1 << 0) + +#define TCR_RES0 (BIT_MASK(31, 23) | BIT_MASK(20, 19)) + +#define FSR_MULTI (1 << 31) +#define FSR_SS (1 << 30) +#define FSR_UUT (1 << 8) +#define FSR_ASF (1 << 7) +#define FSR_TLBLKF (1 << 6) +#define FSR_TLBMCF (1 << 5) +#define FSR_EF (1 << 4) +#define FSR_PF (1 << 3) +#define FSR_AFF (1 << 2) +#define FSR_TF (1 << 1) +#define FSR_IGN (FSR_AFF | FSR_ASF | \ + FSR_TLBMCF | FSR_TLBLKF) +#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \ + FSR_EF | FSR_PF | FSR_TF | FSR_IGN) + +/* Context Bank Index */ +#define S2CR_CBNDX(s2cr) SET_FIELD((s2cr), 7, 0) +/* Register type */ +#define S2CR_TYPE(s2cr) SET_FIELD((s2cr), 17, 16) +/* Privileged Attribute Configuration */ +#define S2CR_PRIVCFG(s2cr) SET_FIELD((s2cr), 25, 24) + +#define S2CR_TYPE_TRANS 0 +#define S2CR_TYPE_FAULT 2 + +#define S2CR_PRIVCFG_DEFAULT 0 + +struct arm_smmu_smr { + u16 mask; + u16 id; + bool valid; +}; + +struct arm_smmu_device { + void *base; + void *cb_base; + unsigned long pgshift; + u32 num_context_banks; + u32 num_mapping_groups; + struct arm_smmu_smr *smrs; +}; + +static struct arm_smmu_device smmu_device[JAILHOUSE_MAX_IOMMU_UNITS]; +static unsigned int num_smmu_devices; + +#define for_each_smmu(smmu, counter) \ + for ((smmu) = &smmu_device[0], (counter) = 0; \ + (counter) < num_smmu_devices; \ + (smmu)++, (counter)++) + +static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) +{ + struct arm_smmu_smr *smr = smmu->smrs + idx; + u32 reg = (smr->id << SMR_ID_SHIFT) | (smr->mask << SMR_MASK_SHIFT) | + (smr->valid ? SMR_VALID : 0); + + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx), reg); +} + +static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx, + unsigned int type, unsigned int cbndx) +{ + u32 reg = S2CR_TYPE(type) | S2CR_CBNDX(cbndx) | + S2CR_PRIVCFG(S2CR_PRIVCFG_DEFAULT); + + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx), reg); +} + +/* Wait for any pending TLB invalidations to complete */ +static int arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) +{ + void *base = ARM_SMMU_GR0(smmu); + unsigned int loop, n; + + mmio_write32(base + ARM_SMMU_GR0_sTLBGSYNC, 0); + for (loop = 0; loop < TLB_LOOP_TIMEOUT; loop++) { + if (!(mmio_read32(base + ARM_SMMU_GR0_sTLBGSTATUS) & + sTLBGSTATUS_GSACTIVE)) + return 0; + for (n = 0; n < 1000; n++) + cpu_relax(); + } + printk("TLB sync timed out -- SMMU may be deadlocked\n"); + + return trace_error(-EINVAL); +} + +static void arm_smmu_setup_context_bank(struct arm_smmu_device *smmu, + struct cell *cell, unsigned int vmid) +{ + /* + * We use the cell ID here, one cell use one context. + */ + void *cb_base = ARM_SMMU_CB(smmu, vmid); + void *gr1_base = ARM_SMMU_GR1(smmu); + + /* CBA2R */ + mmio_write32(gr1_base + ARM_SMMU_GR1_CBA2R(vmid), CBA2R_RW64_64BIT); + + /* CBAR */ + mmio_write32(gr1_base + ARM_SMMU_GR1_CBAR(vmid), + CBAR_TYPE_S2_TRANS | (vmid << CBAR_VMID_SHIFT)); + + /* TCR */ + mmio_write32(cb_base + ARM_SMMU_CB_TCR, VTCR_CELL & ~TCR_RES0); + + /* TTBR0 */ + mmio_write64(cb_base + ARM_SMMU_CB_TTBR0, + paging_hvirt2phys(cell->arch.mm.root_table) & TTBR_MASK); + + /* SCTLR */ + mmio_write32(cb_base + ARM_SMMU_CB_SCTLR, + SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE | SCTLR_M); +} + +static void arm_smmu_disable_context_bank(struct arm_smmu_device *smmu, int idx) +{ + mmio_write32(ARM_SMMU_CB(smmu, idx) + ARM_SMMU_CB_SCTLR, 0); +} + +static int arm_smmu_device_reset(struct arm_smmu_device *smmu) +{ + void *gr0_base = ARM_SMMU_GR0(smmu); + unsigned int idx; + u32 reg; + + /* Clear global FSR */ + reg = mmio_read32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sGFSR); + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sGFSR, reg); + + /* + * Reset stream mapping groups: Initial values mark all SMRn as + * invalid and all S2CRn as fault until overridden. + */ + for (idx = 0; idx < smmu->num_mapping_groups; ++idx) { + if (smmu->smrs) + arm_smmu_write_smr(smmu, idx); + + arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_FAULT, 0); + } + + /* + * Before clearing ARM_MMU500_ACTLR_CPRE, need to + * clear CACHE_LOCK bit of ACR first. + */ + reg = mmio_read32(gr0_base + ARM_SMMU_GR0_sACR); + reg &= ~ARM_MMU500_ACR_CACHE_LOCK; + + /* + * Allow unmatched Stream IDs to allocate bypass + * TLB entries for reduced latency. + */ + reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN; + mmio_write32(gr0_base + ARM_SMMU_GR0_sACR, reg); + + /* Make sure all context banks are disabled and clear CB_FSR */ + for (idx = 0; idx < smmu->num_context_banks; ++idx) { + void *cb_base = ARM_SMMU_CB(smmu, idx); + + arm_smmu_disable_context_bank(smmu, idx); + mmio_write32(cb_base + ARM_SMMU_CB_FSR, FSR_FAULT); + /* + * Disable MMU-500's not-particularly-beneficial next-page + * prefetcher for the sake of errata #841119 and #826419. + */ + reg = mmio_read32(cb_base + ARM_SMMU_CB_ACTLR); + reg &= ~ARM_MMU500_ACTLR_CPRE; + mmio_write32(cb_base + ARM_SMMU_CB_ACTLR, reg); + } + + /* Invalidate the TLB, just in case */ + mmio_write32(gr0_base + ARM_SMMU_GR0_TLBIALLH, 0); + mmio_write32(gr0_base + ARM_SMMU_GR0_TLBIALLNSNH, 0); + return arm_smmu_tlb_sync_global(smmu); +} + +static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) +{ + void *gr0_base = ARM_SMMU_GR0(smmu); + u32 id, num_s2_context_banks; + unsigned long size; + + /* We only support version 2 */ + if (ID7_MAJOR(mmio_read32(gr0_base + ARM_SMMU_GR0_ID7)) != 2) + return trace_error(-EIO); + + /* Make sure the SMMU is not in use */ + if (!(mmio_read32(gr0_base + ARM_SMMU_GR0_sCR0) & sCR0_CLIENTPD)) + return trace_error(-EBUSY); + + /* ID0 */ + id = mmio_read32(gr0_base + ARM_SMMU_GR0_ID0); + + if (!(id & ID0_S2TS)) + return trace_error(-EIO); + + size = 1 << ID0_NUMSIDB(id); + + if (id & ID0_SMS) { + size = ID0_NUMSMRG(id); + if (size == 0) + return trace_error(-ENODEV); + + /* Zero-initialised to mark as invalid */ + smmu->smrs = page_alloc(&mem_pool, PAGES(size * sizeof(*smmu->smrs))); + if (!smmu->smrs) + return -ENOMEM; + memset(smmu->smrs, 0, PAGES(size * sizeof(*smmu->smrs))); + + printk(" stream matching with %lu SMR groups\n", size); + } + + smmu->num_mapping_groups = size; + + /* ID1 */ + id = mmio_read32(gr0_base + ARM_SMMU_GR0_ID1); + smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12; + + /* Check for size mismatch of SMMU address space from mapped region */ + size = 1 << (ID1_NUMPAGENDXB(id) + 1); + size <<= smmu->pgshift; + if (smmu->cb_base != gr0_base + size) + printk("Warning: SMMU address space size (0x%lx) " + "differs from mapped region size (0x%tx)!\n", + size * 2, (smmu->cb_base - gr0_base) * 2); + + num_s2_context_banks = ID1_NUMS2CB(id); + smmu->num_context_banks = ID1_NUMCB(id); + if (num_s2_context_banks > smmu->num_context_banks) + return trace_error(-ENODEV); + + printk(" %u context banks (%u stage-2 only)\n", + smmu->num_context_banks, num_s2_context_banks); + + /* ID2 */ + id = mmio_read32(gr0_base + ARM_SMMU_GR0_ID2); + if (ID2_IAS(id) < cpu_parange_encoded) + return trace_error(-EIO); + if (ID2_OAS(id) < cpu_parange_encoded) + return trace_error(-EIO); + if (!(id & ID2_PTFS_4K)) + return trace_error(-EIO); + + return 0; +} + +static int arm_smmu_find_sme(u16 id, u16 mask, struct arm_smmu_device *smmu) +{ + struct arm_smmu_smr *smrs = smmu->smrs; + int free_idx = -EINVAL; + unsigned int n; + + /* Stream indexing is blissfully easy */ + if (!smrs) + return id; + + /* Validating SMRs is... less so */ + for (n = 0; n < smmu->num_mapping_groups; ++n) { + if (!smrs[n].valid) { + /* + * Note the first free entry we come across, which + * we'll claim in the end if nothing else matches. + */ + if (free_idx < 0) + free_idx = n; + continue; + } + /* + * If the new entry is _entirely_ matched by an existing entry, + * then reuse that, with the guarantee that there also cannot + * be any subsequent conflicting entries. In normal use we'd + * expect simply identical entries for this case, but there's + * no harm in accommodating the generalisation. + */ + if ((mask & smrs[n].mask) == mask && + !((id ^ smrs[n].id) & ~smrs[n].mask)) { + return n; + } + /* + * If the new entry has any other overlap with an existing one, + * though, then there always exists at least one stream ID + * which would cause a conflict, and we can't allow that risk. + */ + if (!((id ^ smrs[n].id) & ~(smrs[n].mask | mask))) + return -EINVAL; + } + + return free_idx; +} + +static int arm_smmu_cell_init(struct cell *cell) +{ + unsigned int vmid = cell->config->id; + struct arm_smmu_device *smmu; + struct arm_smmu_smr *smr; + union jailhouse_stream_id fsid; + unsigned int dev, n; + u16 sid, smask; + int ret, idx; + + /* If no sids, ignore */ + if (!cell->config->num_stream_ids) + return 0; + + for_each_smmu(smmu, dev) { + arm_smmu_setup_context_bank(smmu, cell, vmid); + + smr = smmu->smrs; + + for_each_stream_id(fsid, cell->config, n) { + sid = SMR_GET_ID(fsid.mmu500.id); + smask = SMR_GET_MASK(fsid.mmu500.mask_out); + + ret = arm_smmu_find_sme(sid, smask, smmu); + if (ret < 0) + return trace_error(ret); + idx = ret; + + printk("Assigning SID 0x%x, Mask 0x%x to cell \"%s\"\n", + sid, smask, cell->config->name); + + arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_TRANS, vmid); + + smr[idx].id = sid; + smr[idx].mask = smask; + smr[idx].valid = true; + + arm_smmu_write_smr(smmu, idx); + } + + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID, vmid); + ret = arm_smmu_tlb_sync_global(smmu); + if (ret < 0) + return ret; + } + + return 0; +} + +static bool arm_smmu_return_sid_to_root_cell(struct arm_smmu_device *smmu, + union jailhouse_stream_id fsid, + int idx) +{ + unsigned int n; + union jailhouse_stream_id rsid; + + for_each_stream_id(rsid, root_cell.config, n) { + if (fsid.id == rsid.id) { + printk("Assigning SID 0x%llx Mask: 0x%llx to cell \"%s\"\n", + SMR_GET_ID(fsid.mmu500.id), + SMR_GET_MASK(fsid.mmu500.mask_out), + root_cell.config->name); + + /* We just need to update S2CR, SMR can stay as is. */ + arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_TRANS, + root_cell.config->id); + return true; + } + } + return false; +} + +static void arm_smmu_cell_exit(struct cell *cell) +{ + int id = cell->config->id; + struct arm_smmu_device *smmu; + union jailhouse_stream_id fsid; + unsigned int dev, n; + u16 sid, smask; + int idx; + + /* If no sids, ignore */ + if (!cell->config->num_stream_ids) + return; + + for_each_smmu(smmu, dev) { + for_each_stream_id(fsid, cell->config, n) { + sid = SMR_GET_ID(fsid.mmu500.id); + smask = SMR_GET_MASK(fsid.mmu500.mask_out); + + idx = arm_smmu_find_sme(sid, smask, smmu); + if (idx < 0) + continue; + + /* return full stream ids */ + if (arm_smmu_return_sid_to_root_cell(smmu, fsid, idx)) + continue; + + if (smmu->smrs) { + smmu->smrs[idx].id = 0; + smmu->smrs[idx].mask = 0; + smmu->smrs[idx].valid = false; + + arm_smmu_write_smr(smmu, idx); + } + arm_smmu_write_s2cr(smmu, idx, S2CR_TYPE_FAULT, 0); + } + + arm_smmu_disable_context_bank(smmu, id); + + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID, id); + arm_smmu_tlb_sync_global(smmu); + } +} + +void arm_smmu_config_commit(struct cell *cell) +{ + struct arm_smmu_device *smmu; + unsigned int dev; + + if (cell != &root_cell) + return; + + for_each_smmu(smmu, dev) { + /* + * Enable fault reporting, + * private VMIDS, disable TLB broadcasting, + * fault unmatched streams + */ + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0, + sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE | + sCR0_VMIDPNE | sCR0_PTM | sCR0_USFCFG); + } +} + +static void arm_smmu_shutdown(void) +{ + struct arm_smmu_device *smmu; + unsigned int dev; + + for_each_smmu(smmu, dev) { + mmio_write32(ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0, + sCR0_CLIENTPD); + } +} + +static int arm_smmu_init(void) +{ + struct jailhouse_iommu *iommu; + struct arm_smmu_device *smmu; + unsigned int n; + int err; + + for (n = 0; n < iommu_count_units(); n++) { + iommu = &system_config->platform_info.iommu_units[n]; + if (iommu->type != JAILHOUSE_IOMMU_ARM_MMU500) + continue; + + smmu = &smmu_device[num_smmu_devices]; + smmu->base = paging_map_device(iommu->base, iommu->size); + if (!smmu->base) { + err = -ENOMEM; + goto error; + } + + printk("ARM MMU500 at 0x%llx with:\n", iommu->base); + + smmu->cb_base = smmu->base + iommu->size / 2; + + err = arm_smmu_device_cfg_probe(smmu); + if (err) + goto error; + + err = arm_smmu_device_reset(smmu); + if (err) + goto error; + + num_smmu_devices++; + } + + if (num_smmu_devices == 0) + return 0; + + err = arm_smmu_cell_init(&root_cell); + if (!err) + return 0; + +error: + arm_smmu_shutdown(); + return err; +} + +DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(arm_smmu); +DEFINE_UNIT(arm_smmu, "ARM SMMU"); diff --git a/hypervisor/arch/arm64/ti-pvu.c b/hypervisor/arch/arm64/ti-pvu.c new file mode 100644 index 0000000000000000000000000000000000000000..5da85b5c9ad30784cc9ebcf7d8b55cb86f91c422 --- /dev/null +++ b/hypervisor/arch/arm64/ti-pvu.c @@ -0,0 +1,584 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * TI PVU IOMMU unit + * + * Peripheral Virtualization Unit(PVU) is an IOMMU (memory management + * unit for DMA) which is designed for 2nd stage address translation in a + * real time manner. + * + * Unlike ARM-SMMU, all the memory mapping information is stored in the + * local registers instead of the in-memory page tables. + * + * There are limitations on the number of available contexts, page sizes, + * number of pages that can be mapped, etc. + * + * PVU is designed to be programmed with all the memory mapping at once. + * Therefore, it defers the actual register programming till config_commit. + * Also, it does not support unmapping of the pages at runtime. + * + * Authors: + * Nikhil Devshatwar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#define MAX_PVU_ENTRIES (PAGE_SIZE / sizeof (struct pvu_tlb_entry)) +#define MAX_VIRTID 7 + +static struct pvu_dev pvu_units[JAILHOUSE_MAX_IOMMU_UNITS]; +static unsigned int pvu_count; + +static const u64 pvu_page_size_bytes[] = { + 4 * 1024, + 16 * 1024, + 64 * 1024, + 2 * 1024 * 1024, + 32 * 1024 * 1024, + 512 * 1024 * 1024, + 1 * 1024 * 1024 * 1024, + 16ULL * 1024 * 1024 * 1024, +}; + +static inline u32 is_aligned(u64 addr, u64 size) +{ + return (addr % size) == 0; +} + +static void pvu_tlb_enable(struct pvu_dev *dev, u16 tlbnum) +{ + struct pvu_hw_tlb *tlb; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + mmio_write32_field(&tlb->chain, PVU_TLB_LOG_DIS_MASK, 0); + mmio_write32_field(&tlb->chain, PVU_TLB_EN_MASK, 1); +} + +static void pvu_tlb_disable(struct pvu_dev *dev, u16 tlbnum) +{ + struct pvu_hw_tlb *tlb; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + mmio_write32_field(&tlb->chain, PVU_TLB_EN_MASK, 0); + mmio_write32_field(&tlb->chain, PVU_TLB_LOG_DIS_MASK, 1); +} + +static u32 pvu_tlb_is_enabled(struct pvu_dev *dev, u16 tlbnum) +{ + struct pvu_hw_tlb *tlb; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + if (mmio_read32_field(&tlb->chain, PVU_TLB_EN_MASK)) + return 1; + else + return 0; +} + +static int pvu_tlb_chain(struct pvu_dev *dev, u16 tlbnum, u16 tlb_next) +{ + struct pvu_hw_tlb *tlb; + + if (tlb_next <= tlbnum || tlb_next <= dev->max_virtid) + return -EINVAL; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + mmio_write32_field(&tlb->chain, PVU_TLB_CHAIN_MASK, tlb_next); + return 0; +} + +static u32 pvu_tlb_next(struct pvu_dev *dev, u16 tlbnum) +{ + struct pvu_hw_tlb *tlb; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + return mmio_read32_field(&tlb->chain, PVU_TLB_CHAIN_MASK); +} + +static u32 pvu_tlb_alloc(struct pvu_dev *dev, u16 virtid) +{ + unsigned int i; + + for (i = dev->max_virtid + 1; i < dev->num_tlbs; i++) { + if (dev->tlb_data[i] == 0) { + dev->tlb_data[i] = virtid << dev->num_entries; + dev->free_tlb_count--; + return i; + } + } + + /* + * We should never reach here, tlb_allocation should not fail. + * pvu_iommu_map_memory ensures that there are enough free TLBs + */ + + BUG(); + return 0; +} + +static void pvu_tlb_flush(struct pvu_dev *dev, u16 tlbnum) +{ + struct pvu_hw_tlb_entry *entry; + struct pvu_hw_tlb *tlb; + u32 i; + + pvu_tlb_disable(dev, tlbnum); + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + + for (i = 0; i < dev->num_entries; i++) { + + entry = &tlb->entry[i]; + mmio_write32(&entry->reg0, 0x0); + mmio_write32(&entry->reg1, 0x0); + mmio_write32(&entry->reg2, 0x0); + mmio_write32(&entry->reg4, 0x0); + mmio_write32(&entry->reg5, 0x0); + mmio_write32(&entry->reg6, 0x0); + } + + mmio_write32(&tlb->chain, 0x0); + + if (i < dev->max_virtid) { + dev->tlb_data[tlbnum] = 0x0 | i << dev->num_entries; + } else { + /* This was a chained TLB */ + dev->tlb_data[tlbnum] = 0x0; + dev->free_tlb_count++; + } + +} + +static void pvu_entry_enable(struct pvu_dev *dev, u16 tlbnum, u8 index) +{ + struct pvu_hw_tlb_entry *entry; + struct pvu_hw_tlb *tlb; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + entry = &tlb->entry[index]; + + mmio_write32_field(&entry->reg2, PVU_TLB_ENTRY_MODE_MASK, + PVU_TLB_ENTRY_VALID); + + dev->tlb_data[tlbnum] |= (1 << index); +} + +static void pvu_entry_write(struct pvu_dev *dev, u16 tlbnum, u8 index, + struct pvu_tlb_entry *ent) +{ + struct pvu_hw_tlb_entry *entry; + struct pvu_hw_tlb *tlb; + u8 pgsz; + + tlb = (struct pvu_hw_tlb *)dev->tlb_base + tlbnum; + entry = &tlb->entry[index]; + + for (pgsz = 0; pgsz < ARRAY_SIZE(pvu_page_size_bytes); pgsz++) { + if (ent->size == pvu_page_size_bytes[pgsz]) + break; + } + + mmio_write32(&entry->reg0, ent->virt_addr & 0xffffffff); + mmio_write32_field(&entry->reg1, 0xffff, (ent->virt_addr >> 32)); + mmio_write32(&entry->reg2, 0x0); + + mmio_write32(&entry->reg4, ent->phys_addr & 0xffffffff); + mmio_write32_field(&entry->reg5, 0xffff, (ent->phys_addr >> 32)); + mmio_write32(&entry->reg6, 0x0); + + mmio_write32_field(&entry->reg2, PVU_TLB_ENTRY_PGSIZE_MASK, pgsz); + mmio_write32_field(&entry->reg2, PVU_TLB_ENTRY_FLAG_MASK, ent->flags); + + /* Do we need "DSB NSH" here to make sure all writes are finished? */ + pvu_entry_enable(dev, tlbnum, index); +} + +static u32 pvu_init_device(struct pvu_dev *dev, u16 max_virtid) +{ + struct pvu_hw_cfg *cfg; + unsigned int i; + + cfg = (struct pvu_hw_cfg *)dev->cfg_base; + + dev->num_tlbs = mmio_read32_field(&cfg->config, PVU_CONFIG_NTLB_MASK); + dev->num_entries = + mmio_read32_field(&cfg->config, PVU_CONFIG_NENT_MASK); + + if (max_virtid >= dev->num_tlbs) { + printk("ERROR: PVU: Max virtid(%d) should be less than num_tlbs(%d)\n", + max_virtid, dev->num_tlbs); + return -EINVAL; + } + + dev->max_virtid = max_virtid; + dev->free_tlb_count = dev->num_tlbs - (max_virtid + 1); + + mmio_write32(&cfg->virtid_map1, 0); + mmio_write32_field(&cfg->virtid_map2, PVU_MAX_VIRTID_MASK, max_virtid); + + for (i = 0; i < dev->num_tlbs; i++) { + + pvu_tlb_disable(dev, i); + if (i < dev->max_virtid) + dev->tlb_data[i] = 0x0 | i << dev->num_entries; + else + dev->tlb_data[i] = 0x0; + } + + /* Enable all types of exceptions */ + mmio_write32(&cfg->exception_logging_disable, 0x0); + mmio_write32(&cfg->exception_logging_control, 0x0); + mmio_write32_field(&cfg->enable, PVU_ENABLE_MASK, PVU_ENABLE_EN); + return 0; +} + +static void pvu_shutdown_device(struct pvu_dev *dev) +{ + struct pvu_hw_cfg *cfg; + unsigned int i; + + cfg = (struct pvu_hw_cfg *)dev->cfg_base; + + for (i = 0; i < dev->num_tlbs; i++) { + pvu_tlb_flush(dev, i); + } + + mmio_write32_field(&cfg->enable, PVU_ENABLE_MASK, PVU_ENABLE_DIS); +} + +/* + * Split a memory region into multiple pages, where page size is one of the PVU + * supported size and the start address is aligned to page size + */ +static int pvu_entrylist_create(u64 ipa, u64 pa, u64 map_size, u64 flags, + struct pvu_tlb_entry *entlist, u32 num_entries) +{ + u64 page_size, vaddr, paddr; + unsigned int count; + s64 size; + int idx; + + vaddr = ipa; + paddr = pa; + size = map_size; + count = 0; + + while (size > 0) { + + if (count == num_entries) { + printk("ERROR: PVU: Need more TLB entries for mapping %llx => %llx with size %llx\n", + ipa, pa, map_size); + return -EINVAL; + } + + /* Try size from largest to smallest */ + for (idx = ARRAY_SIZE(pvu_page_size_bytes) - 1; idx >= 0; idx--) { + + page_size = pvu_page_size_bytes[idx]; + + if (is_aligned(vaddr, page_size) && + is_aligned(paddr, page_size) && + (u64)size >= page_size) { + + entlist[count].virt_addr = vaddr; + entlist[count].phys_addr = paddr; + entlist[count].size = page_size; + entlist[count].flags = flags; + + count++; + vaddr += page_size; + paddr += page_size; + size -= page_size; + break; + } + } + + if (idx < 0) { + printk("ERROR: PVU: Addresses %llx %llx" \ + "aren't aligned to any of the allowed page sizes\n", + vaddr, paddr); + return -EINVAL; + } + } + return count; +} + +static void pvu_entrylist_sort(struct pvu_tlb_entry *entlist, u32 num_entries) +{ + struct pvu_tlb_entry temp; + unsigned int i, j; + + for (i = 0; i < num_entries; i++) { + for (j = i; j < num_entries; j++) { + + if (entlist[i].size < entlist[j].size) { + temp = entlist[i]; + entlist[i] = entlist[j]; + entlist[j] = temp; + } + } + } +} + +static void pvu_iommu_program_entries(struct cell *cell, u8 virtid) +{ + unsigned int inst, i, tlbnum, idx, ent_count; + struct pvu_tlb_entry *ent, *cell_entries; + struct pvu_dev *dev; + int tlb_next; + + cell_entries = cell->arch.iommu_pvu.entries; + ent_count = cell->arch.iommu_pvu.ent_count; + if (ent_count == 0 || cell_entries == NULL) + return; + + /* Program same memory mapping for all of the instances */ + for (inst = 0; inst < pvu_count; inst++) { + + dev = &pvu_units[inst]; + if (pvu_tlb_is_enabled(dev, virtid)) + continue; + + tlbnum = virtid; + for (i = 0; i < ent_count; i++) { + + ent = &cell_entries[i]; + idx = i % dev->num_entries; + + if (idx == 0 && i >= dev->num_entries) { + /* Find next available TLB and chain to it */ + tlb_next = pvu_tlb_alloc(dev, virtid); + pvu_tlb_chain(dev, tlbnum, tlb_next); + pvu_tlb_enable(dev, tlbnum); + tlbnum = tlb_next; + } + + pvu_entry_write(dev, tlbnum, idx, ent); + } + pvu_tlb_enable(dev, tlbnum); + } +} + +/* + * Actual TLB entry programming is deferred till config_commit + * Only populate the pvu_entries array for now + */ +int pvu_iommu_map_memory(struct cell *cell, + const struct jailhouse_memory *mem) +{ + struct pvu_tlb_entry *ent; + struct pvu_dev *dev; + unsigned int size; + u32 tlb_count, flags = 0; + int ret; + + if (pvu_count == 0 || (mem->flags & JAILHOUSE_MEM_DMA) == 0) + return 0; + + if (cell->arch.iommu_pvu.ent_count == MAX_PVU_ENTRIES) + return -ENOMEM; + + if (mem->flags & JAILHOUSE_MEM_READ) + flags |= (LPAE_PAGE_PERM_UR | LPAE_PAGE_PERM_SR); + if (mem->flags & JAILHOUSE_MEM_WRITE) + flags |= (LPAE_PAGE_PERM_UW | LPAE_PAGE_PERM_SW); + if (mem->flags & JAILHOUSE_MEM_EXECUTE) + flags |= (LPAE_PAGE_PERM_UX | LPAE_PAGE_PERM_SX); + + flags |= (LPAE_PAGE_MEM_WRITETHROUGH | LPAE_PAGE_OUTER_SHARABLE | + LPAE_PAGE_IS_NOALLOC | LPAE_PAGE_OS_NOALLOC); + + ent = &cell->arch.iommu_pvu.entries[cell->arch.iommu_pvu.ent_count]; + size = MAX_PVU_ENTRIES - cell->arch.iommu_pvu.ent_count; + + ret = pvu_entrylist_create(mem->virt_start, mem->phys_start, mem->size, + flags, ent, size); + if (ret < 0) + return ret; + + /* + * Check if there are enough TLBs left for *chaining* to ensure that + * pvu_tlb_alloc called from config_commit never fails + */ + dev = &pvu_units[0]; + tlb_count = (cell->arch.iommu_pvu.ent_count + ret - 1) / + dev->num_entries; + + if (tlb_count > dev->free_tlb_count) { + printk("ERROR: PVU: Mapping this memory needs more TLBs than that are available\n"); + return -EINVAL; + } + + cell->arch.iommu_pvu.ent_count += ret; + return 0; +} + +int pvu_iommu_unmap_memory(struct cell *cell, + const struct jailhouse_memory *mem) +{ + u32 cell_state; + + if (pvu_count == 0 || (mem->flags & JAILHOUSE_MEM_DMA) == 0) + return 0; + + /* + * PVU does not support dynamic unmapping of memory + */ + + cell_state = cell->comm_page.comm_region.cell_state; + + if (cell_state == JAILHOUSE_CELL_RUNNING || + cell_state == JAILHOUSE_CELL_RUNNING_LOCKED) + printk("WARNING: PVU cannot unmap memory at runtime for cell %s\n", + cell->config->name); + + return 0; +} + +void pvu_iommu_config_commit(struct cell *cell) +{ + union jailhouse_stream_id virtid; + unsigned int i; + + if (pvu_count == 0 || !cell) + return; + + /* + * Chaining the TLB entries adds extra latency to translate those + * addresses. + * Sort the entries in descending order of page sizes to reduce effects + * of chaining and thus reducing average translation latency + */ + pvu_entrylist_sort(cell->arch.iommu_pvu.entries, + cell->arch.iommu_pvu.ent_count); + + for_each_stream_id(virtid, cell->config, i) { + if (virtid.id > MAX_VIRTID) + continue; + + pvu_iommu_program_entries(cell, virtid.id); + } + + cell->arch.iommu_pvu.ent_count = 0; +} + +static int pvu_iommu_cell_init(struct cell *cell) +{ + union jailhouse_stream_id virtid; + unsigned int i; + struct pvu_dev *dev; + + if (pvu_count == 0) + return 0; + + cell->arch.iommu_pvu.ent_count = 0; + cell->arch.iommu_pvu.entries = page_alloc(&mem_pool, 1); + if (!cell->arch.iommu_pvu.entries) + return -ENOMEM; + + dev = &pvu_units[0]; + for_each_stream_id(virtid, cell->config, i) { + + if (virtid.id > MAX_VIRTID) + continue; + + if (pvu_tlb_is_enabled(dev, virtid.id)) + return -EINVAL; + } + return 0; +} + +static int pvu_iommu_flush_context(u16 virtid) +{ + unsigned int i, tlbnum, next; + struct pvu_dev *dev; + + for (i = 0; i < pvu_count; i++) { + + dev = &pvu_units[i]; + tlbnum = virtid; + + while (tlbnum) { + + next = pvu_tlb_next(dev, tlbnum); + pvu_tlb_flush(dev, tlbnum); + tlbnum = next; + } + } + return 0; +} + +static void pvu_iommu_cell_exit(struct cell *cell) +{ + union jailhouse_stream_id virtid; + unsigned int i; + + if (pvu_count == 0) + return; + + for_each_stream_id(virtid, cell->config, i) { + + if (virtid.id > MAX_VIRTID) + continue; + + pvu_iommu_flush_context(virtid.id); + } + + cell->arch.iommu_pvu.ent_count = 0; + page_free(&mem_pool, cell->arch.iommu_pvu.entries, 1); + cell->arch.iommu_pvu.entries = NULL; +} + +static int pvu_iommu_init(void) +{ + struct jailhouse_iommu *iommu; + struct pvu_dev *dev; + unsigned int i; + int ret; + + iommu = &system_config->platform_info.iommu_units[0]; + for (i = 0; i < iommu_count_units(); iommu++, i++) { + + if (iommu->type != JAILHOUSE_IOMMU_PVU) + continue; + + dev = &pvu_units[pvu_count]; + dev->cfg_base = paging_map_device(iommu->base, + iommu->size); + dev->tlb_base = paging_map_device(iommu->tipvu.tlb_base, + iommu->tipvu.tlb_size); + + ret = pvu_init_device(dev, MAX_VIRTID); + if (ret) + return ret; + + pvu_count++; + } + + return pvu_iommu_cell_init(&root_cell); +} + +static void pvu_iommu_shutdown(void) +{ + struct pvu_dev *dev; + unsigned int i; + + pvu_iommu_cell_exit(&root_cell); + + for (i = 0; i < pvu_count; i++) { + + dev = &pvu_units[i]; + pvu_shutdown_device(dev); + } + +} + +DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(pvu_iommu); +DEFINE_UNIT(pvu_iommu, "PVU IOMMU"); diff --git a/hypervisor/arch/arm64/traps.c b/hypervisor/arch/arm64/traps.c new file mode 100644 index 0000000000000000000000000000000000000000..488dd7f852b63569aaec61171f77bf55cae39b13 --- /dev/null +++ b/hypervisor/arch/arm64/traps.c @@ -0,0 +1,206 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * Dmitry Voytik + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void arch_skip_instruction(struct trap_context *ctx) +{ + u64 pc; + + arm_read_sysreg(ELR_EL2, pc); + pc += ESR_IL(ctx->esr) ? 4 : 2; + arm_write_sysreg(ELR_EL2, pc); +} + +static enum trap_return handle_hvc(struct trap_context *ctx) +{ + unsigned long *regs = ctx->regs; + unsigned long code = regs[0]; + + if (ESR_ISS(ctx->esr) != JAILHOUSE_HVC_CODE) + return TRAP_FORBIDDEN; + + regs[0] = hypercall(code, regs[1], regs[2]); + + if (code == JAILHOUSE_HC_DISABLE && regs[0] == 0) { + paging_map_all_per_cpu(this_cpu_id(), true); + arch_shutdown_self(per_cpu(this_cpu_id())); + } + + return TRAP_HANDLED; +} + +static enum trap_return handle_sysreg(struct trap_context *ctx) +{ + u32 esr = ctx->esr; + u32 rt = (esr >> 5) & 0x1f; + + /* All handled registers are write-only. */ + if (esr & 1) + return TRAP_UNHANDLED; + + if (ESR_MATCH_MSR_MRS(esr, 3, 0, 12, 11, 5) && /* ICC_SGI1R */ + gicv3_handle_sgir_write(rt == 31 ? 0 : ctx->regs[rt])) { + arch_skip_instruction(ctx); + return TRAP_HANDLED; + } + + return TRAP_UNHANDLED; +} + +static enum trap_return handle_iabt(struct trap_context *ctx) +{ + unsigned long hpfar, hdfar; + + if (this_cpu_data()->sdei_event) { + this_cpu_data()->sdei_event = false; + arm_write_sysreg(VTCR_EL2, VTCR_CELL); + isb(); + + arch_handle_sgi(SGI_EVENT, 1); + + return TRAP_HANDLED; + } + + arm_read_sysreg(HPFAR_EL2, hpfar); + arm_read_sysreg(FAR_EL2, hdfar); + + panic_printk("FATAL: instruction abort at 0x%lx\n", + (hpfar << 8) | (hdfar & 0xfff)); + return TRAP_FORBIDDEN; +} + +static void dump_regs(struct trap_context *ctx) +{ + unsigned char i; + u64 pc; + + arm_read_sysreg(ELR_EL2, pc); + panic_printk(" pc: %016llx lr: %016lx spsr: %08llx EL%lld\n" + " sp: %016llx elr: %016llx esr: %02llx %01llx %07llx\n", + pc, ctx->regs[30], ctx->spsr, SPSR_EL(ctx->spsr), + ctx->sp, ctx->elr, ESR_EC(ctx->esr), ESR_IL(ctx->esr), + ESR_ISS(ctx->esr)); + for (i = 0; i < NUM_USR_REGS - 1; i++) + panic_printk("%sx%d: %016lx%s", i < 10 ? " " : "", i, + ctx->regs[i], i % 3 == 2 ? "\n" : " "); + panic_printk("\n"); +} + +/* TODO: move this function to an arch-independent code if other architectures + * will need it. + */ +static void dump_mem(unsigned long start, unsigned long stop) +{ + unsigned long caddr = start & ~0x1f; + + if (stop <= start) + return; + printk("(0x%016lx - 0x%016lx):", start, stop); + for (;;) { + printk("\n%04lx: ", caddr & 0xffe0); + do { + if (caddr >= start) + printk("%08x ", *(unsigned int *)caddr); + else + printk(" "); + caddr += 4; + } while ((caddr & 0x1f) && caddr < stop); + if (caddr >= stop) + break; + } + printk("\n"); +} + +static void dump_hyp_stack(const struct trap_context *ctx) +{ + panic_printk("Hypervisor stack before exception "); + dump_mem(ctx->sp, (unsigned long)this_cpu_data()->stack + + sizeof(this_cpu_data()->stack)); +} + +static void fill_trap_context(struct trap_context *ctx, union registers *regs) +{ + arm_read_sysreg(SPSR_EL2, ctx->spsr); + switch (SPSR_EL(ctx->spsr)) { /* exception level */ + case 0: + arm_read_sysreg(SP_EL0, ctx->sp); break; + case 1: + arm_read_sysreg(SP_EL1, ctx->sp); break; + case 2: + /* SP_EL2 is not accessible in EL2. To obtain SP value before + * the excepton we can use the regs parameter. regs is located + * on the stack (see handle_vmexit in exception.S) */ + ctx->sp = (u64)(regs) + 16 * 16; break; + default: + ctx->sp = 0; break; /* should never happen */ + } + arm_read_sysreg(ESR_EL2, ctx->esr); + arm_read_sysreg(ELR_EL2, ctx->elr); + ctx->regs = regs->usr; +} + +static const trap_handler trap_handlers[0x40] = +{ + [ESR_EC_HVC64] = handle_hvc, + [ESR_EC_SMC64] = handle_smc, + [ESR_EC_SYS64] = handle_sysreg, + [ESR_EC_IABT_LOW] = handle_iabt, + [ESR_EC_DABT_LOW] = arch_handle_dabt, +}; + +void arch_handle_trap(union registers *guest_regs) +{ + struct trap_context ctx; + trap_handler handler; + int ret = TRAP_UNHANDLED; + + fill_trap_context(&ctx, guest_regs); + + handler = trap_handlers[ESR_EC(ctx.esr)]; + if (handler) + ret = handler(&ctx); + + if (ret == TRAP_UNHANDLED || ret == TRAP_FORBIDDEN) { + panic_printk("\nFATAL: %s (exception class 0x%02llx)\n", + (ret == TRAP_UNHANDLED ? "unhandled trap" : + "forbidden access"), + ESR_EC(ctx.esr)); + panic_printk("Cell state before exception:\n"); + dump_regs(&ctx); + panic_park(); + } +} + +void arch_el2_abt(union registers *regs) +{ + struct trap_context ctx; + + fill_trap_context(&ctx, regs); + panic_printk("\nFATAL: Unhandled HYP exception: " + "synchronous abort from EL2\n"); + dump_regs(&ctx); + dump_hyp_stack(&ctx); + panic_stop(); +} diff --git a/hypervisor/arch/x86/Kbuild b/hypervisor/arch/x86/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..7a42adb470ea1484413937fd857123a0ccacd34b --- /dev/null +++ b/hypervisor/arch/x86/Kbuild @@ -0,0 +1,49 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2017 +# Copyright (c) Valentine Sinitsyn, 2014 +# +# Authors: +# Jan Kiszka +# Valentine Sinitsyn +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +ccflags-$(CONFIG_JAILHOUSE_GCOV) += -fprofile-arcs -ftest-coverage + +always-y := lib-amd.a lib-intel.a + +common-objs-y := apic.o dbg-write.o entry.o setup.o control.o mmio.o iommu.o \ + paging.o pci.o i8042.o vcpu.o efifb.o ivshmem.o + +CFLAGS_efifb.o := -I$(src) + +$(obj)/efifb.o: $(src)/altc-8x16 + +# units initialization order as defined by linking order: +# iommu, ioapic, [test-device], [cat], + +common-objs-y += ioapic.o + +common-objs-$(CONFIG_TEST_DEVICE) += test-device.o + +amd-objs := svm.o amd_iommu.o svm-vmexit.o $(common-objs-y) +intel-objs := vmx.o vtd.o vmx-vmexit.o $(common-objs-y) cat.o + +targets += $(amd-objs) $(intel-objs) + +quiet_cmd_link_archive = AR $@ +cmd_link_archive = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(filter-out FORCE,$^) + +$(obj)/lib-amd.a: $(addprefix $(obj)/,$(amd-objs)) FORCE + $(call if_changed,link_archive) + +$(obj)/lib-intel.a: $(addprefix $(obj)/,$(intel-objs)) FORCE + $(call if_changed,link_archive) diff --git a/hypervisor/arch/x86/Makefile b/hypervisor/arch/x86/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6fce43c83b3f4bf11bc01843db0c69b34a1454c6 --- /dev/null +++ b/hypervisor/arch/x86/Makefile @@ -0,0 +1,21 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2016 +# Copyright (c) Valentine Sinitsyn, 2014 +# +# Authors: +# Jan Kiszka +# Valentine Sinitsyn +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +KBUILD_CFLAGS += -mcmodel=kernel -mno-sse -mno-mmx -mno-sse2 -mno-3dnow +KBUILD_CFLAGS += -mno-red-zone +KBUILD_CFLAGS += $(call cc-option,-mno-avx,) + +KBUILD_CPPFLAGS += -m64 + +BUILD_VARIANTS := amd intel diff --git a/hypervisor/arch/x86/altc-8x16 b/hypervisor/arch/x86/altc-8x16 new file mode 100644 index 0000000000000000000000000000000000000000..734b76eb1b16038cd1a61455dee150361162d865 Binary files /dev/null and b/hypervisor/arch/x86/altc-8x16 differ diff --git a/hypervisor/arch/x86/amd_iommu.c b/hypervisor/arch/x86/amd_iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..40ec4e20c77bc877b57e8201b1becb16d5faa93e --- /dev/null +++ b/hypervisor/arch/x86/amd_iommu.c @@ -0,0 +1,834 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014, 2015 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Valentine Sinitsyn + * Jan Kiszka + * + * Commands posting and event log parsing code, as well as many defines + * were adapted from Linux's amd_iommu driver written by Joerg Roedel + * and Leo Duran. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CAPS_IOMMU_HEADER_REG 0x00 +#define CAPS_IOMMU_EFR_SUP (1 << 27) +#define CAPS_IOMMU_BASE_LOW_REG 0x04 +#define CAPS_IOMMU_ENABLE (1 << 0) +#define CAPS_IOMMU_BASE_HI_REG 0x08 + +#define ACPI_REPORTING_HE_SUP (1 << 7) + +#define AMD_DEV_TABLE_BASE_REG 0x0000 +#define AMD_CMD_BUF_BASE_REG 0x0008 +#define AMD_EVT_LOG_BASE_REG 0x0010 +#define AMD_CONTROL_REG 0x0018 +#define AMD_CONTROL_IOMMU_EN (1UL << 0) +#define AMD_CONTROL_EVT_LOG_EN (1UL << 2) +#define AMD_CONTROL_EVT_INT_EN (1UL << 3) +#define AMD_CONTROL_COMM_WAIT_INT_EN (1UL << 4) +#define AMD_CONTROL_CMD_BUF_EN (1UL << 12) +#define AMD_CONTROL_SMIF_EN (1UL << 22) +#define AMD_CONTROL_SMIFLOG_EN (1UL << 24) +#define AMD_CONTROL_SEG_EN_MASK BIT_MASK(36, 34) +#define AMD_CONTROL_SEG_EN_SHIFT 34 +#define AMD_EXT_FEATURES_REG 0x0030 +#define AMD_EXT_FEAT_HE_SUP (1UL << 7) +#define AMD_EXT_FEAT_SMI_FSUP (1UL << 16) +#define AMD_EXT_FEAT_SMI_FSUP_MASK BIT_MASK(17, 16) +#define AMD_EXT_FEAT_SMI_FRC_MASK BIT_MASK(20, 18) +#define AMD_EXT_FEAT_SMI_FRC_SHIFT 18 +#define AMD_EXT_FEAT_SEG_SUP_MASK BIT_MASK(39, 38) +#define AMD_EXT_FEAT_SEG_SUP_SHIFT 38 +#define AMD_HEV_UPPER_REG 0x0040 +#define AMD_HEV_LOWER_REG 0x0048 +#define AMD_HEV_STATUS_REG 0x0050 +#define AMD_HEV_VALID (1UL << 1) +#define AMD_HEV_OVERFLOW (1UL << 2) +#define AMD_SMI_FILTER0_REG 0x0060 +#define AMD_SMI_FILTER_VALID (1UL << 16) +#define AMD_SMI_FILTER_LOCKED (1UL << 17) +#define AMD_DEV_TABLE_SEG1_REG 0x0100 +#define AMD_CMD_BUF_HEAD_REG 0x2000 +#define AMD_CMD_BUF_TAIL_REG 0x2008 +#define AMD_EVT_LOG_HEAD_REG 0x2010 +#define AMD_EVT_LOG_TAIL_REG 0x2018 +#define AMD_STATUS_REG 0x2020 +# define AMD_STATUS_EVT_OVERFLOW (1UL << 0) +# define AMD_STATUS_EVT_LOG_INT (1UL << 1) +# define AMD_STATUS_EVT_LOG_RUN (1UL << 3) + +struct dev_table_entry { + u64 raw64[4]; +} __attribute__((packed)); + +#define DTE_VALID (1UL << 0) +#define DTE_TRANSLATION_VALID (1UL << 1) +#define DTE_PAGING_MODE_4_LEVEL (4UL << 9) +#define DTE_IR (1UL << 61) +#define DTE_IW (1UL << 62) + +#define DEV_TABLE_SEG_MAX 8 +#define DEV_TABLE_SIZE 0x200000 + +union buf_entry { + u32 raw32[4]; + u64 raw64[2]; + struct { + u32 pad0; + u32 pad1:28; + u32 type:4; + }; +} __attribute__((packed)); + +#define CMD_COMPL_WAIT 0x01 +# define CMD_COMPL_WAIT_STORE (1 << 0) +# define CMD_COMPL_WAIT_INT (1 << 1) + +#define CMD_INV_DEVTAB_ENTRY 0x02 + +#define CMD_INV_IOMMU_PAGES 0x03 +# define CMD_INV_IOMMU_PAGES_SIZE (1 << 0) +# define CMD_INV_IOMMU_PAGES_PDE (1 << 1) + +#define EVENT_TYPE_ILL_DEV_TAB_ENTRY 0x01 +#define EVENT_TYPE_PAGE_TAB_HW_ERR 0x04 +#define EVENT_TYPE_ILL_CMD_ERR 0x05 +#define EVENT_TYPE_CMD_HW_ERR 0x06 +#define EVENT_TYPE_IOTLB_INV_TIMEOUT 0x07 +#define EVENT_TYPE_INV_PPR_REQ 0x09 + +#define BUF_LEN_EXPONENT_SHIFT 56 + +/* Allocate minimum space possible (4K or 256 entries) */ +#define BUF_SIZE(name, entry) ((1UL << name##_LEN_EXPONENT) * \ + sizeof(entry)) + +#define CMD_BUF_LEN_EXPONENT 8 +#define EVT_LOG_LEN_EXPONENT 8 + +#define CMD_BUF_SIZE BUF_SIZE(CMD_BUF, union buf_entry) +#define EVT_LOG_SIZE BUF_SIZE(EVT_LOG, union buf_entry) + +#define BITS_PER_SHORT 16 + +#define AMD_IOMMU_MAX_PAGE_TABLE_LEVELS 4 + +static struct amd_iommu { + int idx; + void *mmio_base; + /* Command Buffer, Event Log */ + unsigned char *cmd_buf_base; + unsigned char *evt_log_base; + /* Device table */ + void *devtable_segments[DEV_TABLE_SEG_MAX]; + u8 dev_tbl_seg_sup; + u32 cmd_tail_ptr; + bool he_supported; +} iommu_units[JAILHOUSE_MAX_IOMMU_UNITS]; + +#define for_each_iommu(iommu) for (iommu = iommu_units; \ + iommu < iommu_units + iommu_units_count; \ + iommu++) + +static unsigned int iommu_units_count; + +bool iommu_cell_emulates_ir(struct cell *cell) +{ + return false; +} + +static int amd_iommu_cell_init(struct cell *cell) +{ + // HACK for QEMU + if (iommu_units_count == 0) + return 0; + + if (cell->config->id > 0xffff) + return trace_error(-ERANGE); + + return 0; +} + +static void amd_iommu_completion_wait(struct amd_iommu *iommu); + +static void amd_iommu_submit_command(struct amd_iommu *iommu, + union buf_entry *cmd, bool draining) +{ + u32 head, next_tail, bytes_free; + unsigned char *cur_ptr; + + head = mmio_read64(iommu->mmio_base + AMD_CMD_BUF_HEAD_REG); + next_tail = (iommu->cmd_tail_ptr + sizeof(*cmd)) % CMD_BUF_SIZE; + bytes_free = (head - next_tail) % CMD_BUF_SIZE; + + /* Leave space for COMPLETION_WAIT that drains the buffer. */ + if (bytes_free < (2 * sizeof(*cmd)) && !draining) + /* Drain the buffer */ + amd_iommu_completion_wait(iommu); + + cur_ptr = &iommu->cmd_buf_base[iommu->cmd_tail_ptr]; + memcpy(cur_ptr, cmd, sizeof(*cmd)); + + /* Just to be sure. */ + arch_paging_flush_cpu_caches(cur_ptr, sizeof(*cmd)); + + iommu->cmd_tail_ptr = + (iommu->cmd_tail_ptr + sizeof(*cmd)) % CMD_BUF_SIZE; +} + +u64 amd_iommu_get_memory_region_flags(const struct jailhouse_memory *mem) +{ + unsigned long flags = AMD_IOMMU_PTE_P; + + if (!(mem->flags & JAILHOUSE_MEM_DMA)) + return 0; + + if (mem->flags & JAILHOUSE_MEM_READ) + flags |= AMD_IOMMU_PTE_IR; + if (mem->flags & JAILHOUSE_MEM_WRITE) + flags |= AMD_IOMMU_PTE_IW; + + return flags; +} + +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + /* + * Check that the address is not outside the scope of the page tables. + * With 4 levels, we only support 48 address bits. + */ + if (mem->virt_start & BIT_MASK(63, 48)) + return trace_error(-E2BIG); + + /* vcpu_map_memory_region already did the actual work. */ + return 0; +} + +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + /* vcpu_map_memory_region already did the actual work. */ + return 0; +} + +static void amd_iommu_inv_dte(struct amd_iommu *iommu, u16 device_id) +{ + union buf_entry invalidate_dte = {{ 0 }}; + + invalidate_dte.raw32[0] = device_id; + invalidate_dte.type = CMD_INV_DEVTAB_ENTRY; + + amd_iommu_submit_command(iommu, &invalidate_dte, false); +} + +static struct dev_table_entry *get_dev_table_entry(struct amd_iommu *iommu, + u16 bdf, bool allocate) +{ + struct dev_table_entry *devtable_seg; + u8 seg_idx, seg_shift; + u64 reg_base, reg_val; + unsigned int n; + u16 seg_mask; + u32 seg_size; + + if (!iommu->dev_tbl_seg_sup) { + seg_mask = 0; + seg_idx = 0; + seg_size = DEV_TABLE_SIZE; + } else { + seg_shift = BITS_PER_SHORT - iommu->dev_tbl_seg_sup; + seg_mask = ~((1 << seg_shift) - 1); + seg_idx = (seg_mask & bdf) >> seg_shift; + seg_size = DEV_TABLE_SIZE / (1 << iommu->dev_tbl_seg_sup); + } + + /* + * Device table segmentation is tricky in Jailhouse. As cells can + * "share" the IOMMU, we don't know maximum bdf in each segment + * because cells are initialized independently. Thus, we can't simply + * adjust segment sizes for our maximum bdfs. + * + * The next best things is to lazily allocate segments as we add + * device using maximum possible size for segments. In the worst case + * scenario, we waste around 2M chunk per IOMMU. + */ + devtable_seg = iommu->devtable_segments[seg_idx]; + if (!devtable_seg) { + /* If we are not permitted to allocate, just fail */ + if (!allocate) + return NULL; + + devtable_seg = page_alloc(&mem_pool, PAGES(seg_size)); + if (!devtable_seg) + return NULL; + iommu->devtable_segments[seg_idx] = devtable_seg; + + /* + * Initialize all entries to paging mode 0, IR & IW cleared so + * that DMA requests are blocked. + */ + for (n = 0; n < seg_size / sizeof(struct dev_table_entry); n++) + devtable_seg[n].raw64[0] = + DTE_VALID | DTE_TRANSLATION_VALID; + + if (!seg_idx) + reg_base = AMD_DEV_TABLE_BASE_REG; + else + reg_base = AMD_DEV_TABLE_SEG1_REG + (seg_idx - 1) * 8; + + /* Size in Kbytes = (m + 1) * 4, see Sect 3.3.6 */ + reg_val = paging_hvirt2phys(devtable_seg) | + (seg_size / PAGE_SIZE - 1); + mmio_write64(iommu->mmio_base + reg_base, reg_val); + } + + return &devtable_seg[bdf & ~seg_mask]; +} + +int iommu_add_pci_device(struct cell *cell, struct pci_device *device) +{ + struct dev_table_entry *dte = NULL; + struct amd_iommu *iommu; + u16 bdf; + + // HACK for QEMU + if (iommu_units_count == 0) + return 0; + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return 0; + + if (device->info->iommu >= JAILHOUSE_MAX_IOMMU_UNITS) + return trace_error(-ERANGE); + + iommu = &iommu_units[device->info->iommu]; + bdf = device->info->bdf; + + dte = get_dev_table_entry(iommu, bdf, true); + if (!dte) + return -ENOMEM; + + memset(dte, 0, sizeof(*dte)); + + /* DomainID */ + dte->raw64[1] = cell->config->id & 0xffff; + + /* Translation information */ + dte->raw64[0] = DTE_IR | DTE_IW | + paging_hvirt2phys(cell->arch.svm.npt_iommu_structs.root_table) | + DTE_PAGING_MODE_4_LEVEL | DTE_TRANSLATION_VALID | DTE_VALID; + + /* TODO: Interrupt remapping. For now, just forward them unmapped. */ + + /* Flush caches, just to be sure. */ + arch_paging_flush_cpu_caches(dte, sizeof(*dte)); + + amd_iommu_inv_dte(iommu, bdf); + + return 0; +} + +void iommu_remove_pci_device(struct pci_device *device) +{ + struct dev_table_entry *dte = NULL; + struct amd_iommu *iommu; + u16 bdf; + + // HACK for QEMU + if (iommu_units_count == 0) + return; + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return; + + iommu = &iommu_units[device->info->iommu]; + bdf = device->info->bdf; + + dte = get_dev_table_entry(iommu, bdf, false); + if (!dte) + return; + + /* + * Set Mode to 0 (translation disabled) and clear IR and IW to block + * DMA requests until the entry is reprogrammed for its new owner. + */ + dte->raw64[0] = DTE_VALID | DTE_TRANSLATION_VALID; + + /* Flush caches, just to be sure. */ + arch_paging_flush_cpu_caches(dte, sizeof(*dte)); + + amd_iommu_inv_dte(iommu, bdf); +} + +static void amd_iommu_cell_exit(struct cell *cell) +{ +} + +static void wait_for_zero(volatile u64 *sem, unsigned long mask) +{ + while (*sem & mask) + cpu_relax(); +} + +static void amd_iommu_invalidate_pages(struct amd_iommu *iommu, + u16 domain_id) +{ + union buf_entry invalidate_pages = {{ 0 }}; + + /* + * Flush everything, including PDEs, in whole address range, i.e. + * 0x7ffffffffffff000 with S bit (see Sect. 2.2.3). + */ + invalidate_pages.raw32[1] = domain_id; + invalidate_pages.raw32[2] = 0xfffff000 | CMD_INV_IOMMU_PAGES_SIZE | + CMD_INV_IOMMU_PAGES_PDE; + invalidate_pages.raw32[3] = 0x7fffffff; + invalidate_pages.type = CMD_INV_IOMMU_PAGES; + + amd_iommu_submit_command(iommu, &invalidate_pages, false); +} + +static void amd_iommu_completion_wait(struct amd_iommu *iommu) +{ + long addr = paging_hvirt2phys(&per_cpu(this_cpu_id())->amd_iommu_sem); + union buf_entry completion_wait = {{ 0 }}; + + this_cpu_data()->amd_iommu_sem = 1; + + completion_wait.raw32[0] = (addr & BIT_MASK(31, 3)) | + CMD_COMPL_WAIT_STORE; + completion_wait.raw32[1] = (addr & BIT_MASK(51, 32)) >> 32; + completion_wait.type = CMD_COMPL_WAIT; + + amd_iommu_submit_command(iommu, &completion_wait, true); + mmio_write64(iommu->mmio_base + AMD_CMD_BUF_TAIL_REG, + iommu->cmd_tail_ptr); + + wait_for_zero(&this_cpu_data()->amd_iommu_sem, -1); +} + +static void amd_iommu_init_fault_nmi(void) +{ + union x86_msi_vector msi_vec = {{ 0 }}; + struct public_per_cpu *target_data; + union pci_msi_registers msi_reg; + struct amd_iommu *iommu; + int n; + + target_data = iommu_select_fault_reporting_cpu(); + + /* Send NMI to fault reporting CPU */ + msi_vec.native.address = MSI_ADDRESS_VALUE; + msi_vec.native.destination = target_data->apic_id; + + msi_reg.msg32.enable = 1; + msi_reg.msg64.address = msi_vec.raw.address; + msi_reg.msg64.data = MSI_DM_NMI; + + for_each_iommu(iommu) { + struct jailhouse_iommu *cfg = + &system_config->platform_info.iommu_units[iommu->idx]; + + /* Disable MSI during interrupt reprogramming. */ + pci_write_config(cfg->amd.bdf, cfg->amd.msi_cap + 2, 0, 2); + + /* + * Write new MSI capability block, re-enabling interrupts with + * the last word. + */ + for (n = 3; n >= 0; n--) + pci_write_config(cfg->amd.bdf, cfg->amd.msi_cap + 4 * n, + msi_reg.raw[n], 4); + } + + /* + * There is a race window in between we change fault_reporting_cpu_id + * and actually reprogram the MSI. To prevent event loss, signal an + * interrupt when done, so iommu_check_pending_faults() is called + * upon completion even if no further NMIs due to events would occurr. + * + * Note we can't simply use CMD_COMPL_WAIT_INT_MASK in + * amd_iommu_completion_wait(), as it seems that IOMMU either signal + * an interrupt or do memory write, but not both. + */ + apic_send_nmi_ipi(target_data); +} + +void iommu_config_commit(struct cell *cell_added_removed) +{ + struct amd_iommu *iommu; + + // HACK for QEMU + if (iommu_units_count == 0) + return; + + /* Ensure we'll get NMI on completion, or if anything goes wrong. */ + if (cell_added_removed) + amd_iommu_init_fault_nmi(); + + for_each_iommu(iommu) { + /* Flush caches */ + if (cell_added_removed) { + amd_iommu_invalidate_pages(iommu, + cell_added_removed->config->id & 0xffff); + amd_iommu_invalidate_pages(iommu, + root_cell.config->id & 0xffff); + } + /* Execute all commands in the buffer */ + amd_iommu_completion_wait(iommu); + } +} + +struct apic_irq_message iommu_get_remapped_root_int(unsigned int iommu, + u16 device_id, + unsigned int vector, + unsigned int remap_index) +{ + struct apic_irq_message dummy = { .valid = 0 }; + + /* TODO: Implement */ + return dummy; +} + +int iommu_map_interrupt(struct cell *cell, u16 device_id, unsigned int vector, + struct apic_irq_message irq_msg) +{ + /* TODO: Implement */ + return -ENOSYS; +} + +static void amd_iommu_print_event(struct amd_iommu *iommu, + union buf_entry *entry) +{ + printk("AMD IOMMU %d reported event\n", iommu->idx); + printk(" EventCode: %x, Operand 1: %llx, Operand 2: %llx\n", + entry->type, entry->raw64[0], entry->raw64[1]); + switch (entry->type) { + case EVENT_TYPE_ILL_DEV_TAB_ENTRY...EVENT_TYPE_PAGE_TAB_HW_ERR: + case EVENT_TYPE_IOTLB_INV_TIMEOUT...EVENT_TYPE_INV_PPR_REQ: + printk(" DeviceId (bus:dev.func): %02x:%02x.%x\n", + PCI_BDF_PARAMS(entry->raw32[0] & 0xffff)); + break; + case EVENT_TYPE_ILL_CMD_ERR: + case EVENT_TYPE_CMD_HW_ERR: + panic_printk("FATAL: IOMMU %d command error\n", + iommu->idx); + panic_stop(); + } +} + +static void amd_iommu_restart_event_log(struct amd_iommu *iommu) +{ + void *base = iommu->mmio_base; + + wait_for_zero(base + AMD_STATUS_REG, AMD_STATUS_EVT_LOG_RUN); + + mmio_write64_field(base + AMD_CONTROL_REG, AMD_CONTROL_EVT_LOG_EN, 0); + + /* Simply start from the scratch */ + mmio_write64(base + AMD_EVT_LOG_HEAD_REG, 0); + mmio_write64(base + AMD_EVT_LOG_TAIL_REG, 0); + + /* Clear EventOverflow (RW1C) */ + mmio_write64_field(base + AMD_STATUS_REG, AMD_STATUS_EVT_OVERFLOW, 1); + + /* Bring logging back */ + mmio_write64_field(base + AMD_CONTROL_REG, AMD_CONTROL_EVT_LOG_EN, 1); +} + +static void amd_iommu_poll_events(struct amd_iommu *iommu) +{ + union buf_entry *evt; + u32 head, tail; + u64 status; + + status = mmio_read64(iommu->mmio_base + AMD_STATUS_REG); + + if (status & AMD_STATUS_EVT_OVERFLOW) { + printk("IOMMU %d: Event Log overflow occurred, " + "some events were lost!\n", iommu->idx); + amd_iommu_restart_event_log(iommu); + } + + while (status & AMD_STATUS_EVT_LOG_INT) { + /* Clear EventLogInt (RW1C) */ + mmio_write64_field(iommu->mmio_base + AMD_STATUS_REG, + AMD_STATUS_EVT_LOG_INT, 1); + + head = mmio_read32(iommu->mmio_base + AMD_EVT_LOG_HEAD_REG); + tail = mmio_read32(iommu->mmio_base + AMD_EVT_LOG_TAIL_REG); + + while (head != tail) { + evt = (union buf_entry *)(iommu->evt_log_base + head); + amd_iommu_print_event(iommu, evt); + head = (head + sizeof(*evt)) % EVT_LOG_SIZE; + } + + mmio_write32(iommu->evt_log_base + AMD_EVT_LOG_HEAD_REG, head); + + /* Re-read status to catch new events, as Linux does */ + status = mmio_read64(iommu->mmio_base + AMD_STATUS_REG); + } +} + +static void amd_iommu_handle_hardware_event(struct amd_iommu *iommu) +{ + union buf_entry hev_entry; + u64 hev; + + hev = mmio_read64(iommu->mmio_base + AMD_HEV_STATUS_REG); + + /* Check if hardware event is present and print it */ + if (hev & AMD_HEV_VALID) { + if (hev & AMD_HEV_OVERFLOW) + printk("IOMMU %d: Hardware Event Overflow occurred, " + "some events were lost!\n", iommu->idx); + hev_entry.raw64[0] = + mmio_read64(iommu->mmio_base + AMD_HEV_UPPER_REG); + hev_entry.raw64[1] = + mmio_read64(iommu->mmio_base + AMD_HEV_LOWER_REG); + + amd_iommu_print_event(iommu, &hev_entry); + + /* Clear Hardware Event */ + mmio_write64(iommu->mmio_base + AMD_HEV_STATUS_REG, 0); + } +} + +void iommu_check_pending_faults(void) +{ + struct amd_iommu *iommu; + + if (this_cpu_id() != fault_reporting_cpu_id) + return; + + for_each_iommu(iommu) { + if (iommu->he_supported) + amd_iommu_handle_hardware_event(iommu); + amd_iommu_poll_events(iommu); + } +} + +static int amd_iommu_init_pci(struct amd_iommu *entry, + struct jailhouse_iommu *iommu) +{ + u64 caps_header, hi, lo; + + /* Check alignment */ + if (iommu->size & (iommu->size - 1)) + return trace_error(-EINVAL); + + /* Check that EFR is supported */ + caps_header = pci_read_config(iommu->amd.bdf, iommu->amd.base_cap, 4); + if (!(caps_header & CAPS_IOMMU_EFR_SUP)) + return trace_error(-EIO); + + lo = pci_read_config(iommu->amd.bdf, + iommu->amd.base_cap + CAPS_IOMMU_BASE_LOW_REG, 4); + hi = pci_read_config(iommu->amd.bdf, + iommu->amd.base_cap + CAPS_IOMMU_BASE_HI_REG, 4); + + if (lo & CAPS_IOMMU_ENABLE && + ((hi << 32) | lo) != (iommu->base | CAPS_IOMMU_ENABLE)) { + printk("FATAL: IOMMU %d config is locked in invalid state.\n", + entry->idx); + return trace_error(-EPERM); + } + + /* Should be configured by BIOS, but we want to be sure */ + pci_write_config(iommu->amd.bdf, + iommu->amd.base_cap + CAPS_IOMMU_BASE_HI_REG, + (u32)(iommu->base >> 32), 4); + pci_write_config(iommu->amd.bdf, + iommu->amd.base_cap + CAPS_IOMMU_BASE_LOW_REG, + (u32)(iommu->base & 0xffffffff) | CAPS_IOMMU_ENABLE, + 4); + + /* Allocate and map MMIO space */ + entry->mmio_base = paging_map_device(iommu->base, iommu->size); + if (!entry->mmio_base) + return -ENOMEM; + + return 0; +} + +static int amd_iommu_init_features(struct amd_iommu *entry, + struct jailhouse_iommu *iommu) +{ + u64 efr = mmio_read64(entry->mmio_base + AMD_EXT_FEATURES_REG); + unsigned char smi_filter_regcnt; + u64 val, ctrl_reg = 0, smi_freg = 0; + unsigned int n; + void *reg_base; + + /* + * Require SMI Filter support. Enable and lock filter but + * mark all entries as invalid to disable SMI delivery. + */ + if ((efr & AMD_EXT_FEAT_SMI_FSUP_MASK) != AMD_EXT_FEAT_SMI_FSUP) + return trace_error(-EIO); + + /* Figure out if hardware events are supported. */ + if (iommu->amd.features) + entry->he_supported = + iommu->amd.features & ACPI_REPORTING_HE_SUP; + else + entry->he_supported = efr & AMD_EXT_FEAT_HE_SUP; + + smi_filter_regcnt = (1 << (efr & AMD_EXT_FEAT_SMI_FRC_MASK) >> + AMD_EXT_FEAT_SMI_FRC_SHIFT); + for (n = 0; n < smi_filter_regcnt; n++) { + reg_base = entry->mmio_base + AMD_SMI_FILTER0_REG + (n << 3); + smi_freg = mmio_read64(reg_base); + + if (!(smi_freg & AMD_SMI_FILTER_LOCKED)) { + /* + * Program unlocked register the way we need: + * invalid and locked. + */ + mmio_write64(reg_base, AMD_SMI_FILTER_LOCKED); + } else if (smi_freg & AMD_SMI_FILTER_VALID) { + /* + * The register is locked and programed + * the way we don't want - error. + */ + printk("ERROR: SMI Filter register %d is locked " + "and can't be reprogrammed.\n" + "Reboot and check no other component uses the " + "IOMMU %d.\n", n, entry->idx); + return trace_error(-EPERM); + } + /* + * The register is locked, but programmed + * the way we need - OK to go. + */ + } + + ctrl_reg |= (AMD_CONTROL_SMIF_EN | AMD_CONTROL_SMIFLOG_EN); + + /* Enable maximum Device Table segmentation possible */ + entry->dev_tbl_seg_sup = (efr & AMD_EXT_FEAT_SEG_SUP_MASK) >> + AMD_EXT_FEAT_SEG_SUP_SHIFT; + if (entry->dev_tbl_seg_sup) { + val = (u64)entry->dev_tbl_seg_sup << AMD_CONTROL_SEG_EN_SHIFT; + ctrl_reg |= val & AMD_CONTROL_SEG_EN_MASK; + } + + mmio_write64(entry->mmio_base + AMD_CONTROL_REG, ctrl_reg); + + return 0; +} + +static int amd_iommu_init_buffers(struct amd_iommu *entry, + struct jailhouse_iommu *iommu) +{ + /* Allocate and configure command buffer */ + entry->cmd_buf_base = page_alloc(&mem_pool, PAGES(CMD_BUF_SIZE)); + if (!entry->cmd_buf_base) + return -ENOMEM; + + mmio_write64(entry->mmio_base + AMD_CMD_BUF_BASE_REG, + paging_hvirt2phys(entry->cmd_buf_base) | + ((u64)CMD_BUF_LEN_EXPONENT << BUF_LEN_EXPONENT_SHIFT)); + + entry->cmd_tail_ptr = 0; + + /* Allocate and configure event log */ + entry->evt_log_base = page_alloc(&mem_pool, PAGES(EVT_LOG_SIZE)); + if (!entry->evt_log_base) + return -ENOMEM; + + mmio_write64(entry->mmio_base + AMD_EVT_LOG_BASE_REG, + paging_hvirt2phys(entry->evt_log_base) | + ((u64)EVT_LOG_LEN_EXPONENT << BUF_LEN_EXPONENT_SHIFT)); + + return 0; +} + +static void amd_iommu_enable_command_processing(struct amd_iommu *iommu) +{ + u64 ctrl_reg; + + ctrl_reg = mmio_read64(iommu->mmio_base + AMD_CONTROL_REG); + ctrl_reg |= AMD_CONTROL_IOMMU_EN | AMD_CONTROL_CMD_BUF_EN | + AMD_CONTROL_EVT_LOG_EN | AMD_CONTROL_EVT_INT_EN; + mmio_write64(iommu->mmio_base + AMD_CONTROL_REG, ctrl_reg); +} + +static int amd_iommu_init(void) +{ + struct jailhouse_iommu *iommu; + struct amd_iommu *entry; + unsigned int n; + int err; + + iommu = &system_config->platform_info.iommu_units[0]; + for (n = 0; iommu->base && n < iommu_count_units(); iommu++, n++) { + if (iommu->type != JAILHOUSE_IOMMU_AMD) + return trace_error(-EINVAL); + + entry = &iommu_units[iommu_units_count]; + + entry->idx = n; + + printk("AMD IOMMU @0x%llx/0x%x\n", iommu->base, iommu->size); + + /* Initialize PCI registers and MMIO space */ + err = amd_iommu_init_pci(entry, iommu); + if (err) + return err; + + /* Setup IOMMU features */ + err = amd_iommu_init_features(entry, iommu); + if (err) + return err; + + /* Initialize command buffer and event log */ + err = amd_iommu_init_buffers(entry, iommu); + if (err) + return err; + + /* Enable the IOMMU */ + amd_iommu_enable_command_processing(entry); + + iommu_units_count++; + } + + return amd_iommu_cell_init(&root_cell); +} + +void iommu_prepare_shutdown(void) +{ + struct amd_iommu *iommu; + u64 ctrl_reg; + + for_each_iommu(iommu) { + /* Disable the IOMMU */ + ctrl_reg = mmio_read64(iommu->mmio_base + AMD_CONTROL_REG); + ctrl_reg &= ~(AMD_CONTROL_IOMMU_EN | AMD_CONTROL_CMD_BUF_EN | + AMD_CONTROL_EVT_LOG_EN | AMD_CONTROL_EVT_INT_EN); + mmio_write64(iommu->mmio_base + AMD_CONTROL_REG, ctrl_reg); + } +} + +DEFINE_UNIT_SHUTDOWN_STUB(amd_iommu); +DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(amd_iommu); +DEFINE_UNIT(amd_iommu, "AMD IOMMU"); diff --git a/hypervisor/arch/x86/apic.c b/hypervisor/arch/x86/apic.c new file mode 100644 index 0000000000000000000000000000000000000000..e861ec2f51cc9fc99eac582abc6f7c6b45bdc5d3 --- /dev/null +++ b/hypervisor/arch/x86/apic.c @@ -0,0 +1,632 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XAPIC_REG(x2apic_reg) ((x2apic_reg) << 4) + + /** + * Modern x86 processors are equipped with a local APIC that handles delivery + * of external interrupts. The APIC can work in two modes: + * - xAPIC: programmed via memory mapped I/O (MMIO) + * - x2APIC: programmed throughs model-specific registers (MSRs) + */ +bool using_x2apic; + +/** + * Mapping from a physical APIC ID to the logical CPU ID as used by Jailhouse. + */ +static u8 apic_to_cpu_id[] = { [0 ... APIC_MAX_PHYS_ID] = CPU_ID_INVALID }; + +/* Initialized for x2APIC, adjusted for xAPIC during init */ +static u32 apic_reserved_bits[] = { + [0x00 ... 0x07] = -1, + [0x08] = 0xffffff00, /* TPR */ + [0x09 ... 0x0a] = -1, + [0x0b] = 0, /* EOI */ + [0x0c ... 0x0e] = -1, + [0x0f] = 0xfffffc00, /* SVR */ + [0x10 ... 0x2e] = -1, + [0x2f] = 0xfffee800, /* CMCI */ + [0x30] = 0xfff33000, /* ICR (0..31) */ + [0x31] = -1, + [0x32] = 0xfff8ef00, /* Timer */ + [0x33 ... 0x34] = 0xfffee800, /* Thermal, Perf */ + [0x35 ... 0x36] = 0xfff0e800, /* LINT0, LINT1 */ + [0x37] = 0xfffeef00, /* Error */ + [0x38] = 0, /* Initial Counter */ + [0x39 ... 0x3d] = -1, + [0x3e] = 0xfffffff4, /* DCR */ + [0x3f] = 0xffffff00, /* Self IPI */ + [0x40 ... 0x53] = -1, /* Extended APIC Register Space */ +}; +static void *xapic_page; + +static struct { + u32 (*read)(unsigned int reg); + u32 (*read_id)(void); + void (*write)(unsigned int reg, u32 val); + void (*send_ipi)(u32 apic_id, u32 icr_lo); +} apic_ops; + +void arch_send_event(struct public_per_cpu *target_data) + __attribute__((alias("apic_send_nmi_ipi"))); + +static u32 read_xapic(unsigned int reg) +{ + return mmio_read32(xapic_page + XAPIC_REG(reg)); +} + +static u32 read_xapic_id(void) +{ + return mmio_read32_field(xapic_page + XAPIC_REG(APIC_REG_ID), + XAPIC_DEST_MASK); +} + +static void write_xapic(unsigned int reg, u32 val) +{ + mmio_write32(xapic_page + XAPIC_REG(reg), val); +} + +static void send_xapic_ipi(u32 apic_id, u32 icr_lo) +{ + while (read_xapic(APIC_REG_ICR) & APIC_ICR_DS_PENDING) + cpu_relax(); + /* + * No need for an explicit barrier, the mmio access serves as + * implicit one. + */ + mmio_write32(xapic_page + XAPIC_REG(APIC_REG_ICR_HI), + apic_id << XAPIC_DEST_SHIFT); + mmio_write32(xapic_page + XAPIC_REG(APIC_REG_ICR), icr_lo); +} + +static u32 read_x2apic(unsigned int reg) +{ + return read_msr(MSR_X2APIC_BASE + reg); +} + +static u32 read_x2apic_id(void) +{ + return read_msr(MSR_X2APIC_BASE + APIC_REG_ID); +} + +static void write_x2apic(unsigned int reg, u32 val) +{ + write_msr(MSR_X2APIC_BASE + reg, val); +} + +static void send_x2apic_ipi(u32 apic_id, u32 icr_lo) +{ + /* + * Intel SDM, Volume 3, 10.12.3: + * We either have to execute a serializing instruction or the + * mfence;lfence sequence to publish data changes before the IPI goes + * out. The latter is clearer and likely also faster. + */ + asm volatile("mfence; lfence" : : : "memory"); + write_msr(MSR_X2APIC_BASE + APIC_REG_ICR, + ((unsigned long)apic_id) << 32 | icr_lo); +} + +static u32 apic_ext_features(void) +{ + if (apic_ops.read(APIC_REG_LVR) & APIC_LVR_EAS) + return apic_ops.read(APIC_REG_XFEAT); + else + /* Set extended feature bits to all-zeroes */ + return 0; +} + +unsigned long phys_processor_id(void) +{ + return apic_ops.read_id(); +} + +int apic_cpu_init(struct per_cpu *cpu_data) +{ + unsigned int xlc = MAX((apic_ext_features() >> 16) & 0xff, + APIC_REG_XLVT3 - APIC_REG_XLVT0 + 1); + unsigned int apic_id = (unsigned int)phys_processor_id(); + unsigned int cpu_id = cpu_data->public.cpu_id; + unsigned int n; + u32 ldr; + + printk("(APIC ID %d) ", apic_id); + + if (apic_id > APIC_MAX_PHYS_ID || cpu_id == CPU_ID_INVALID) + return trace_error(-ERANGE); + if (apic_to_cpu_id[apic_id] != CPU_ID_INVALID) + return trace_error(-EBUSY); + /* only flat mode with LDR corresponding to logical ID supported */ + if (!using_x2apic) { + ldr = apic_ops.read(APIC_REG_LDR); + if (apic_ops.read(APIC_REG_DFR) != 0xffffffff || + (ldr != 0 && ldr != 1UL << (cpu_id + XAPIC_DEST_SHIFT))) + return trace_error(-EIO); + } + + apic_to_cpu_id[apic_id] = cpu_id; + cpu_data->public.apic_id = apic_id; + + cpu_data->public.sipi_vector = -1; + + /* + * Extended APIC Register Space (currently, AMD thus xAPIC only). + * + * Can't do it in apic_init(), as apic_ext_features() accesses + * the APIC page that is only accessible after switching to + * hv_paging_structs. + */ + for (n = 0; n < xlc; n++) + apic_reserved_bits[APIC_REG_XLVT0 + n] = 0xfffef800; + + return 0; +} + +int apic_init(void) +{ + unsigned long apicbase = read_msr(MSR_IA32_APICBASE); + u8 apic_mode = system_config->platform_info.x86.apic_mode; + + if (apicbase & APIC_BASE_EXTD && + apic_mode != JAILHOUSE_APIC_MODE_XAPIC) { + /* x2APIC mode */ + apic_ops.read = read_x2apic; + apic_ops.read_id = read_x2apic_id; + apic_ops.write = write_x2apic; + apic_ops.send_ipi = send_x2apic_ipi; + using_x2apic = true; + } else if (apicbase & APIC_BASE_EN && + apic_mode != JAILHOUSE_APIC_MODE_X2APIC) { + /* xAPIC mode */ + xapic_page = paging_map_device(XAPIC_BASE, PAGE_SIZE); + if (!xapic_page) + return -ENOMEM; + apic_ops.read = read_xapic; + apic_ops.read_id = read_xapic_id; + apic_ops.write = write_xapic; + apic_ops.send_ipi = send_xapic_ipi; + + /* adjust reserved bits to xAPIC mode */ + apic_reserved_bits[APIC_REG_ID] = 0; /* writes are ignored */ + apic_reserved_bits[APIC_REG_LDR] = 0; /* separately filtered */ + apic_reserved_bits[APIC_REG_DFR] = 0; /* separately filtered */ + apic_reserved_bits[APIC_REG_ICR_HI] = 0x00ffffff; + apic_reserved_bits[APIC_REG_SELF_IPI] = -1; /* not available */ + } else + return trace_error(-EIO); + + printk("Using x%sAPIC\n", using_x2apic ? "2" : ""); + + return 0; +} + +void apic_send_nmi_ipi(struct public_per_cpu *target_data) +{ + apic_ops.send_ipi(target_data->apic_id, + APIC_ICR_DLVR_NMI | + APIC_ICR_DEST_PHYSICAL | + APIC_ICR_LV_ASSERT | + APIC_ICR_TM_EDGE | + APIC_ICR_SH_NONE); +} + +/** + * Return whether an interrupt's destination CPU is within a given cell. Also + * return a filtered destination mask. + * + * @param cell Target cell + * @param irq_msg Pointer to the irq message to be checked + * The data structure might get adjusted by calling this + * function. + * + * @see x2apic_filter_logical_dest + * + * @return "true" if the interrupt is for the given cell, "false" if not. + */ +bool apic_filter_irq_dest(struct cell *cell, struct apic_irq_message *irq_msg) +{ + u32 dest = irq_msg->destination; + + if (irq_msg->dest_logical) { + if (using_x2apic) + dest = x2apic_filter_logical_dest(cell, dest); + else + dest &= cell->cpu_set->bitmap[0]; + /* + * Linux may have programmed inactive vectors with too broad + * destination masks. Return the adjusted mask and do not fail. + */ + if (dest != irq_msg->destination && cell != &root_cell) + return false; + irq_msg->destination = dest; + } else if (dest > APIC_MAX_PHYS_ID || + !cell_owns_cpu(cell, apic_to_cpu_id[dest])) { + return false; + } + return true; +} + +void apic_send_irq(struct apic_irq_message irq_msg) +{ + u32 delivery_mode = irq_msg.delivery_mode << APIC_ICR_DLVR_SHIFT; + + /* IA-32 SDM 10.6: "lowest priority IPI [...] should be avoided" */ + if (delivery_mode == APIC_ICR_DLVR_LOWPRI) { + delivery_mode = APIC_ICR_DLVR_FIXED; + /* Fixed mode performs a multicast, so reduce the number of + * receivers to one. */ + if (irq_msg.dest_logical && irq_msg.destination != 0) + irq_msg.destination = 1UL << ffsl(irq_msg.destination); + } + apic_ops.send_ipi(irq_msg.destination, + irq_msg.vector | delivery_mode | + (irq_msg.dest_logical ? APIC_ICR_DEST_LOGICAL : 0) | + APIC_ICR_LV_ASSERT | + (irq_msg.level_triggered ? APIC_ICR_TM_LEVEL : 0) | + APIC_ICR_SH_NONE); +} + +void apic_irq_handler(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + + cpu_data->num_clear_apic_irqs++; + if (cpu_data->num_clear_apic_irqs > 256) + /* + * Do not try to ack infinitely. Once we should have handled + * all possible vectors, raise the task priority to prevent + * further interrupts. TPR will be cleared again on exit from + * apic_clear(). This way we will leave with some bits in IRR + * set - better than spinning endlessly. + */ + apic_ops.write(APIC_REG_TPR, 0xff); + + apic_ops.write(APIC_REG_EOI, APIC_EOI_ACK); +} + +static void apic_mask_lvt(unsigned int reg) +{ + unsigned int val = apic_ops.read(reg); + + if (!(val & APIC_LVT_MASKED)) + apic_ops.write(reg, val | APIC_LVT_MASKED); +} + +void apic_clear(void) +{ + unsigned int maxlvt = (apic_ops.read(APIC_REG_LVR) >> 16) & 0xff; + unsigned int xlc = (apic_ext_features() >> 16) & 0xff; + unsigned int n; + + /* Enable the APIC - the cell may have turned it off */ + apic_ops.write(APIC_REG_SVR, APIC_SVR_ENABLE_APIC | 0xff); + + /* Mask all available LVTs */ + apic_mask_lvt(APIC_REG_LVTERR); + if (maxlvt >= 6) + apic_mask_lvt(APIC_REG_LVTCMCI); + apic_mask_lvt(APIC_REG_LVTT); + if (maxlvt >= 5) + apic_mask_lvt(APIC_REG_LVTTHMR); + if (maxlvt >= 4) + apic_mask_lvt(APIC_REG_LVTPC); + apic_mask_lvt(APIC_REG_LVT0); + apic_mask_lvt(APIC_REG_LVT1); + for (n = 0; n < xlc; n++) + apic_mask_lvt(APIC_REG_XLVT0 + n); + + /* Clear ISR. This is done in reverse direction as EOI + * clears highest-priority interrupt ISR bit. */ + for (n = APIC_NUM_INT_REGS; n > 0; n--) + while (apic_ops.read(APIC_REG_ISR0 + n - 1) != 0) + apic_ops.write(APIC_REG_EOI, APIC_EOI_ACK); + + /* Consume pending interrupts to clear IRR. + * Need to reset TPR to ensure interrupt delivery. */ + apic_ops.write(APIC_REG_TPR, 0); + this_cpu_data()->num_clear_apic_irqs = 0; + enable_irq(); + cpu_relax(); + disable_irq(); + + /* Finally, reset the TPR again and disable the APIC */ + apic_ops.write(APIC_REG_TPR, 0); + apic_ops.write(APIC_REG_SVR, 0xff); +} + +static void apic_send_ipi(unsigned int target_cpu_id, u32 orig_icr_hi, + u32 icr_lo) +{ + if (!cell_owns_cpu(this_cell(), target_cpu_id)) { + printk("WARNING: CPU %d specified IPI destination outside " + "cell boundaries, ICR.hi=%x\n", + this_cpu_id(), orig_icr_hi); + return; + } + + switch (icr_lo & APIC_ICR_DLVR_MASK) { + case APIC_ICR_DLVR_NMI: + /* + * Correctly virtualized NMI injection is a non-trivial task, + * specifically on AMD. Therefore, we ignore NMI IPIs for now. + */ + printk("Ignoring NMI IPI to CPU %d\n", target_cpu_id); + break; + case APIC_ICR_DLVR_INIT: + x86_send_init_sipi(target_cpu_id, X86_INIT, -1); + break; + case APIC_ICR_DLVR_SIPI: + x86_send_init_sipi(target_cpu_id, X86_SIPI, + icr_lo & APIC_ICR_VECTOR_MASK); + break; + default: + apic_ops.send_ipi(public_per_cpu(target_cpu_id)->apic_id, + icr_lo); + } +} + +static void apic_send_logical_dest_ipi(u32 lo_val, u32 hi_val) +{ + unsigned int target_cpu_id = CPU_ID_INVALID; + unsigned long dest = hi_val; + unsigned int logical_id; + unsigned int cluster_id; + unsigned int apic_id; + + if (using_x2apic) { + cluster_id = (dest & X2APIC_DEST_CLUSTER_ID_MASK) >> + X2APIC_DEST_CLUSTER_ID_SHIFT; + dest &= X2APIC_DEST_LOGICAL_ID_MASK; + while (dest != 0) { + logical_id = ffsl(dest); + dest &= ~(1UL << logical_id); + apic_id = logical_id | + (cluster_id << X2APIC_CLUSTER_ID_SHIFT); + if (apic_id <= APIC_MAX_PHYS_ID) + target_cpu_id = apic_to_cpu_id[apic_id]; + apic_send_ipi(target_cpu_id, hi_val, lo_val); + } + } else + while (dest != 0) { + target_cpu_id = ffsl(dest); + dest &= ~(1UL << target_cpu_id); + apic_send_ipi(target_cpu_id, hi_val, lo_val); + } +} + +static void apic_send_ipi_all(u32 lo_val, int except_cpu) +{ + unsigned int cpu; + + /* This implicitly selects APIC_ICR_SH_NONE. */ + lo_val &= APIC_ICR_LVTM_MASK | APIC_ICR_DLVR_MASK | + APIC_ICR_VECTOR_MASK; + for_each_cpu_except(cpu, this_cell()->cpu_set, except_cpu) + apic_send_ipi(cpu, 0, lo_val); +} + +/** + * Handle ICR write request. + * @param lo_val Lower 32 bits of ICR + * @param hi_val Higher 32 bits of ICR (x2APIC format, ID in bits 0..7) + * + * @return True if request was successfully validated and executed. + */ +static bool apic_handle_icr_write(u32 lo_val, u32 hi_val) +{ + u32 shorthand = lo_val & APIC_ICR_SH_MASK; + unsigned int target_cpu_id; + + switch (lo_val & APIC_ICR_DLVR_MASK) { + case APIC_ICR_DLVR_FIXED: + break; + case APIC_ICR_DLVR_INIT: + case APIC_ICR_DLVR_LOWPRI: + case APIC_ICR_DLVR_NMI: + case APIC_ICR_DLVR_SIPI: + if (shorthand == APIC_ICR_SH_NONE || + shorthand == APIC_ICR_SH_ALLOTHER) + break; + /* fall through */ + default: + panic_printk("FATAL: Unsupported/invalid APIC delivery mode, " + "ICR.lo=%x\n", lo_val); + return false; + } + + switch (shorthand) { + case APIC_ICR_SH_SELF: + apic_ops.write(APIC_REG_ICR, lo_val); + return true; + case APIC_ICR_SH_ALL: + apic_send_ipi_all(lo_val, -1); + return true; + case APIC_ICR_SH_ALLOTHER: + apic_send_ipi_all(lo_val, this_cpu_id()); + return true; + } + + if (lo_val & APIC_ICR_DEST_LOGICAL) { + lo_val &= ~APIC_ICR_DEST_LOGICAL; + apic_send_logical_dest_ipi(lo_val, hi_val); + } else { + target_cpu_id = CPU_ID_INVALID; + if (hi_val <= APIC_MAX_PHYS_ID) + target_cpu_id = apic_to_cpu_id[hi_val]; + apic_send_ipi(target_cpu_id, hi_val, lo_val); + } + return true; +} + +static bool apic_accessing_reserved_bits(unsigned int reg, u32 val) +{ + /* Unlisted registers are implicitly reserved */ + if (reg >= ARRAY_SIZE(apic_reserved_bits)) + return true; + + if ((apic_reserved_bits[reg] & val) == 0) + return false; + + printk("FATAL: Trying to set reserved APIC bits " + "(reg %02x, value %08x)\n", reg, val); + return true; +} + +static bool apic_invalid_lvt_delivery_mode(unsigned int reg, u32 val) +{ + if (val & APIC_LVT_MASKED || + (val & APIC_LVT_DLVR_MASK) == APIC_LVT_DLVR_FIXED || + (val & APIC_LVT_DLVR_MASK) == APIC_LVT_DLVR_NMI) + return false; + + printk("FATAL: Setting invalid LVT delivery mode " + "(reg %02x, value %08x)\n", reg, val); + return true; +} + +unsigned int apic_mmio_access(const struct guest_paging_structures *pg_structs, + unsigned int reg, bool is_write) +{ + struct mmio_instruction inst; + u32 val, dest; + + if (using_x2apic) { + panic_printk("FATAL: xAPIC access in x2APIC mode\n"); + return 0; + } + + inst = x86_mmio_parse(pg_structs, is_write); + if (inst.inst_len == 0) + return 0; + if (inst.access_size != 4) { + panic_printk("FATAL: Unsupported APIC access width %d\n", + inst.access_size); + return 0; + } + if (is_write) { + val = inst.out_val; + + if (apic_accessing_reserved_bits(reg, val)) + return 0; + + if (reg == APIC_REG_ICR) { + dest = apic_ops.read(APIC_REG_ICR_HI) >> 24; + if (!apic_handle_icr_write(val, dest)) + return 0; + } else if (reg == APIC_REG_LDR && + val != 1UL << (this_cpu_id() + XAPIC_DEST_SHIFT)) { + panic_printk("FATAL: Unsupported change to LDR: %x\n", + val); + return 0; + } else if (reg == APIC_REG_DFR && val != 0xffffffff) { + panic_printk("FATAL: Unsupported change to DFR: %x\n", + val); + return 0; + } else if (reg >= APIC_REG_LVTCMCI && reg <= APIC_REG_LVTERR && + apic_invalid_lvt_delivery_mode(reg, val)) + return 0; + else if (reg >= APIC_REG_XLVT0 && reg <= APIC_REG_XLVT3 && + apic_invalid_lvt_delivery_mode(reg, val)) + return 0; + else if (reg != APIC_REG_ID) + apic_ops.write(reg, val); + } else { + val = apic_ops.read(reg); + this_cpu_data()->guest_regs.by_index[inst.in_reg_num] = val; + } + return inst.inst_len; +} + +bool x2apic_handle_write(void) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + u32 *stats = this_cpu_public()->stats; + u32 reg = guest_regs->rcx - MSR_X2APIC_BASE; + u32 val = guest_regs->rax; + + if (apic_accessing_reserved_bits(reg, val)) + return false; + + if (reg == APIC_REG_ICR) { + stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_X2APIC_ICR]++; + return apic_handle_icr_write(val, guest_regs->rdx); + } + + stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + + if (reg == APIC_REG_SELF_IPI) + /* TODO: emulate */ + printk("Unhandled x2APIC self IPI write\n"); + else if (reg >= APIC_REG_LVTCMCI && reg <= APIC_REG_LVTERR && + apic_invalid_lvt_delivery_mode(reg, val)) + return false; + else + apic_ops.write(reg, val); + return true; +} + +/* must only be called for readable registers */ +void x2apic_handle_read(void) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + u32 reg = guest_regs->rcx - MSR_X2APIC_BASE; + u32 *stats = this_cpu_public()->stats; + + if (reg == APIC_REG_ID) + guest_regs->rax = apic_ops.read_id(); + else + guest_regs->rax = apic_ops.read(reg); + + if (reg == APIC_REG_ICR) { + stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_X2APIC_ICR]++; + guest_regs->rdx = apic_ops.read(reg + 1); + } else { + stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + guest_regs->rdx = 0; + } +} + +/** + * Filter a logical destination mask against the cell's CPU set. + * @param cell Target cell + * @param destination Logical destination mask (redirection hint enabled) + * + * @return Logical destination mask with invalid target CPUs removed. + */ +u32 x2apic_filter_logical_dest(struct cell *cell, u32 destination) +{ + unsigned int apic_id, logical_id, cluster_id; + u32 dest; + + cluster_id = (destination & X2APIC_DEST_CLUSTER_ID_MASK) >> + X2APIC_DEST_CLUSTER_ID_SHIFT; + dest = destination & X2APIC_DEST_LOGICAL_ID_MASK; + while (dest != 0) { + logical_id = ffsl(dest); + dest &= ~(1UL << logical_id); + apic_id = logical_id | (cluster_id << X2APIC_CLUSTER_ID_SHIFT); + if (apic_id > APIC_MAX_PHYS_ID || + !cell_owns_cpu(cell, apic_to_cpu_id[apic_id])) + destination &= ~(1UL << logical_id); + } + return destination; +} diff --git a/hypervisor/arch/x86/asm-defines.c b/hypervisor/arch/x86/asm-defines.c new file mode 100644 index 0000000000000000000000000000000000000000..bbb38e9cc33c9d97066eab73704f332dcbc46e4a --- /dev/null +++ b/hypervisor/arch/x86/asm-defines.c @@ -0,0 +1,36 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +void common(void); + +void common(void) +{ + OFFSET(PERCPU_LINUX_SP, per_cpu, linux_sp); + BLANK(); + + OFFSET(PERCPU_VMCB_RAX, per_cpu, vmcb.rax); + BLANK(); + + /* GCC evaluates constant expressions involving built-ins + * at compilation time, so this yields computed value. + */ + DEFINE(PERCPU_STACK_END, + __builtin_offsetof(struct per_cpu, stack) + \ + FIELD_SIZEOF(struct per_cpu, stack)); + DEFINE(PERCPU_SIZE_ASM, sizeof(struct per_cpu)); + DEFINE(LOCAL_CPU_BASE_ASM, LOCAL_CPU_BASE); +} diff --git a/hypervisor/arch/x86/cat.c b/hypervisor/arch/x86/cat.c new file mode 100644 index 0000000000000000000000000000000000000000..051ac2968263015f49146dc76205942b4b3b8129 --- /dev/null +++ b/hypervisor/arch/x86/cat.c @@ -0,0 +1,229 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#include + +#define CAT_ROOT_COS 0 + +static unsigned int cbm_max; +static int cos_max = -1; +static u64 orig_root_mask, freed_mask; + +void cat_update(void) +{ + struct cell *cell = this_cell(); + + write_msr(MSR_IA32_PQR_ASSOC, + (u64)cell->arch.cos << PQR_ASSOC_COS_SHIFT); + write_msr(MSR_IA32_L3_MASK_0 + cell->arch.cos, cell->arch.cat_mask); +} + +/* root cell has to be stopped */ +static void cat_update_cell(struct cell *cell) +{ + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + if (cpu == this_cpu_id()) + cat_update(); + else + public_per_cpu(cpu)->update_cat = true; +} + +static u32 get_free_cos(void) +{ + struct cell *cell; + u32 cos = 0; + +retry: + for_each_cell(cell) + if (cell->arch.cos == cos) { + cos++; + goto retry; + } + + return cos; +} + +static bool merge_freed_mask_to_root(void) +{ + bool updated = false; + unsigned int n; + u64 bit; + +restart: + for (n = 0, bit = 1; n < 64; n++, bit <<= 1) + /* unless the root mask is empty, merge only neighboring bits */ + if (freed_mask & bit && (root_cell.arch.cat_mask & (bit << 1) || + root_cell.arch.cat_mask & (bit >> 1) || + root_cell.arch.cat_mask == 0)) { + root_cell.arch.cat_mask |= bit; + freed_mask &= ~bit; + updated = true; + + goto restart; + } + + return updated; +} + +static bool shrink_root_cell_mask(u64 cell_mask) +{ + unsigned int lo_mask_start, lo_mask_len; + u64 lo_mask; + + if ((root_cell.arch.cat_mask & ~cell_mask) == 0) { + /* + * Try to refill the root mask from the freed mask. The root + * mask must not become empty, so check this first. + */ + if (freed_mask == 0) + return false; + + root_cell.arch.cat_mask = 0; + merge_freed_mask_to_root(); + } else { + /* Shrink the root cell's mask. */ + root_cell.arch.cat_mask &= ~cell_mask; + + /* + * Ensure that the root mask is still contiguous: + * + * Check if taking out the new cell's mask from the root mask + * created two halves there. Then shrink the root mask + * additionally by the lower half and add that part to the + * freed mask. + * + * Always removing the lower half simplifies this algorithm at + * the price of possibly choosing the smaller sub-mask. Cell + * configurations can avoid this by locating non-root cell + * masks at the beginning of the L3 cache. + */ + lo_mask_start = ffsl(root_cell.arch.cat_mask); + lo_mask_len = ffzl(root_cell.arch.cat_mask >> lo_mask_start); + lo_mask = BIT_MASK(lo_mask_start + lo_mask_len - 1, + lo_mask_start); + + if (root_cell.arch.cat_mask & ~lo_mask) { + root_cell.arch.cat_mask &= ~lo_mask; + freed_mask |= lo_mask; + } + } + + printk("CAT: Shrunk root cell bitmask to %08llx\n", + root_cell.arch.cat_mask); + cat_update_cell(&root_cell); + + /* Drop this mask from the freed mask in case it was queued there. */ + freed_mask &= ~cell_mask; + + return true; +} + +static int cat_cell_init(struct cell *cell) +{ + const struct jailhouse_cache *cache; + + cell->arch.cos = CAT_ROOT_COS; + + /* NOTE: the EBUSY check below relies on this */ + if (cos_max < 0) + return 0; + + if (cell->config->num_cache_regions > 0) { + if (cell != &root_cell) { + cell->arch.cos = get_free_cos(); + if (cell->arch.cos > (u32)cos_max) + return trace_error(-EBUSY); + } + + cache = jailhouse_cell_cache_regions(cell->config); + + if (cell->config->num_cache_regions != 1 || + cache->type != JAILHOUSE_CACHE_L3 || + cache->size == 0 || + (cache->start + cache->size - 1) > cbm_max) + return trace_error(-EINVAL); + + cell->arch.cat_mask = + BIT_MASK(cache->start + cache->size - 1, cache->start); + + if (cell != &root_cell && + !(cache->flags & JAILHOUSE_CACHE_ROOTSHARED) && + (root_cell.arch.cat_mask & cell->arch.cat_mask) != 0) + if (!shrink_root_cell_mask(cell->arch.cat_mask)) + return trace_error(-EINVAL); + + cat_update_cell(cell); + } else { + /* + * The root cell always occupies COS0, using the whole cache if + * no restriction is specified. Cells without own cache regions + * share these settings. + */ + cell->arch.cat_mask = (cell == &root_cell) ? + BIT_MASK(cbm_max, 0) : root_cell.arch.cat_mask; + } + + printk("CAT: Using COS %d with bitmask %08llx for cell %s\n", + cell->arch.cos, cell->arch.cat_mask, cell->config->name); + + return 0; +} + +static void cat_cell_exit(struct cell *cell) +{ + /* + * Only release the mask of cells with an own partition. + * cos is also CAT_ROOT_COS if CAT is unsupported. + */ + if (cell->arch.cos == CAT_ROOT_COS) + return; + + /* + * Queue bits of released mask for returning to root that were in the + * original root mask as well. + */ + freed_mask |= cell->arch.cat_mask & orig_root_mask; + + if (merge_freed_mask_to_root()) { + printk("CAT: Extended root cell bitmask to %08llx\n", + root_cell.arch.cat_mask); + cat_update_cell(&root_cell); + } +} + +static int cat_init(void) +{ + int err; + + if (cpuid_ebx(7, 0) & X86_FEATURE_CAT && + cpuid_ebx(0x10, 0) & (1 << CAT_RESID_L3)) { + cbm_max = cpuid_eax(0x10, CAT_RESID_L3) & CAT_CBM_LEN_MASK; + cos_max = cpuid_edx(0x10, CAT_RESID_L3) & CAT_COS_MAX_MASK; + } + + err = cat_cell_init(&root_cell); + orig_root_mask = root_cell.arch.cat_mask; + + return err; +} + +DEFINE_UNIT_SHUTDOWN_STUB(cat); +DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(cat); +DEFINE_UNIT(cat, "Cache Allocation Technology"); diff --git a/hypervisor/arch/x86/control.c b/hypervisor/arch/x86/control.c new file mode 100644 index 0000000000000000000000000000000000000000..2bc47a6aed8da517bfef6a947f10f84a7353d1d4 --- /dev/null +++ b/hypervisor/arch/x86/control.c @@ -0,0 +1,269 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct exception_frame { + u64 vector; + u64 error; + u64 rip; + u64 cs; + u64 flags; + u64 rsp; + u64 ss; +}; + +int arch_cell_create(struct cell *cell) +{ + int err; + + err = vcpu_cell_init(cell); + if (err) + return err; + + return 0; +} + +int arch_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + int err; + + err = vcpu_map_memory_region(cell, mem); + if (err) + return err; + + err = iommu_map_memory_region(cell, mem); + if (err) + vcpu_unmap_memory_region(cell, mem); + return err; +} + +int arch_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + int err; + + err = iommu_unmap_memory_region(cell, mem); + if (err) + return err; + + return vcpu_unmap_memory_region(cell, mem); +} + +void arch_flush_cell_vcpu_caches(struct cell *cell) +{ + unsigned int cpu; + + for_each_cpu(cpu, cell->cpu_set) + if (cpu == this_cpu_id()) { + vcpu_tlb_flush(); + } else { + public_per_cpu(cpu)->flush_vcpu_caches = true; + apic_send_nmi_ipi(public_per_cpu(cpu)); + } +} + +void arch_cell_destroy(struct cell *cell) +{ + vcpu_cell_exit(cell); +} + +void arch_cell_reset(struct cell *cell) +{ + struct jailhouse_comm_region *comm_region = &cell->comm_page.comm_region; + unsigned int cpu; + + comm_region->pm_timer_address = + system_config->platform_info.x86.pm_timer_address; + /* comm_region, and hence num_cpus, is zero-initialised */ + for_each_cpu(cpu, cell->cpu_set) + comm_region->num_cpus++; + comm_region->tsc_khz = system_config->platform_info.x86.tsc_khz; + comm_region->apic_khz = system_config->platform_info.x86.apic_khz; + + ioapic_cell_reset(cell); +} + +void arch_config_commit(struct cell *cell_added_removed) +{ + iommu_config_commit(cell_added_removed); + ioapic_config_commit(cell_added_removed); +} + +void arch_prepare_shutdown(void) +{ + ioapic_prepare_handover(); + iommu_prepare_shutdown(); +} + +void arch_reset_cpu(unsigned int cpu_id) +{ + public_per_cpu(cpu_id)->sipi_vector = APIC_BSP_PSEUDO_SIPI; + + resume_cpu(cpu_id); +} + +void arch_park_cpu(unsigned int cpu_id) +{ + public_per_cpu(cpu_id)->init_signaled = true; + + resume_cpu(cpu_id); +} + +void x86_send_init_sipi(unsigned int cpu_id, enum x86_init_sipi type, + int sipi_vector) +{ + struct public_per_cpu *target_data = public_per_cpu(cpu_id); + bool send_nmi = false; + + spin_lock(&target_data->control_lock); + + if (type == X86_INIT) { + if (!target_data->wait_for_sipi && + !target_data->init_signaled) { + target_data->init_signaled = true; + send_nmi = true; + } + } else if (target_data->wait_for_sipi) { + target_data->sipi_vector = sipi_vector; + send_nmi = true; + } + + spin_unlock(&target_data->control_lock); + + if (send_nmi) + apic_send_nmi_ipi(target_data); + + /* + * On real hardware, the Delivery Status flag signals that the + * INIT request has not yet arrived. But we can't easily associate that + * flag on the sender side with the target state. Therefore, emulate + * this feedback channel by delaying the requester during submission. + */ + if (type == X86_INIT) { + while (target_data->init_signaled) { + x86_check_events(); + cpu_relax(); + } + } +} + +/* control_lock has to be held */ +static void x86_enter_wait_for_sipi(struct public_per_cpu *cpu_public) +{ + cpu_public->init_signaled = false; + cpu_public->wait_for_sipi = true; +} + +void __attribute__((weak)) cat_update(void) +{ +} + +void x86_check_events(void) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + int sipi_vector = -1; + + spin_lock(&cpu_public->control_lock); + + while (cpu_public->suspend_cpu) { + cpu_public->cpu_suspended = true; + + spin_unlock(&cpu_public->control_lock); + + while (cpu_public->suspend_cpu) + cpu_relax(); + + spin_lock(&cpu_public->control_lock); + } + + cpu_public->cpu_suspended = false; + + if (cpu_public->init_signaled) { + x86_enter_wait_for_sipi(cpu_public); + } else if (cpu_public->sipi_vector >= 0) { + if (!cpu_public->failed) { + cpu_public->wait_for_sipi = false; + sipi_vector = cpu_public->sipi_vector; + } + cpu_public->sipi_vector = -1; + } + + if (cpu_public->flush_vcpu_caches) { + cpu_public->flush_vcpu_caches = false; + vcpu_tlb_flush(); + } + + if (cpu_public->update_cat) { + cpu_public->update_cat = false; + cat_update(); + } + + spin_unlock(&cpu_public->control_lock); + + /* wait_for_sipi is only modified on this CPU, so checking outside of + * control_lock is fine */ + if (cpu_public->wait_for_sipi) { + vcpu_park(); + } else if (sipi_vector >= 0) { + printk("CPU %d received SIPI, vector %x\n", this_cpu_id(), + sipi_vector); + apic_clear(); + vcpu_reset(sipi_vector); + } + + iommu_check_pending_faults(); +} + +void __attribute__((noreturn)) +x86_exception_handler(struct exception_frame *frame) +{ + panic_printk("FATAL: Jailhouse triggered exception #%lld\n", + frame->vector); + if (frame->error != EXCEPTION_NO_ERROR) + panic_printk("Error code: %llx\n", frame->error); + panic_printk("Physical CPU ID: %lu\n", phys_processor_id()); + panic_printk("RIP: 0x%016llx RSP: 0x%016llx FLAGS: %llx\n", frame->rip, + frame->rsp, frame->flags); + if (frame->vector == PF_VECTOR) + panic_printk("CR2: 0x%016lx\n", read_cr2()); + + panic_stop(); +} + +void __attribute__((noreturn)) arch_panic_stop(void) +{ + /* no lock required here as we won't change to false anymore */ + this_cpu_public()->cpu_suspended = true; + asm volatile("1: hlt; jmp 1b"); + __builtin_unreachable(); +} + +void arch_panic_park(void) +{ + struct public_per_cpu *cpu_public = this_cpu_public(); + + spin_lock(&cpu_public->control_lock); + x86_enter_wait_for_sipi(cpu_public); + spin_unlock(&cpu_public->control_lock); + + vcpu_park(); +} diff --git a/hypervisor/arch/x86/dbg-write.c b/hypervisor/arch/x86/dbg-write.c new file mode 100644 index 0000000000000000000000000000000000000000..4f53bff4e7117d2dbce93b872d92e7e5bf6add19 --- /dev/null +++ b/hypervisor/arch/x86/dbg-write.c @@ -0,0 +1,53 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Jan Kiszka + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +static void reg_out_pio(struct uart_chip *chip, unsigned int reg, u32 value) +{ + outb(value, (u16)(unsigned long long)chip->virt_base + reg); +} + +static u32 reg_in_pio(struct uart_chip *chip, unsigned int reg) +{ + return inb((u16)(unsigned long long)chip->virt_base + reg); +} + +void arch_dbg_write_init(void) +{ + u32 dbg_type = system_config->debug_console.type; + + if (dbg_type == JAILHOUSE_CON_TYPE_8250) { + uart = &uart_8250_ops; + + uart->debug_console = &system_config->debug_console; + if (CON_IS_MMIO(system_config->debug_console.flags)) { + uart->virt_base = hypervisor_header.debug_console_base; + } else { + uart->virt_base = + (void *)system_config->debug_console.address; + uart->reg_out = reg_out_pio; + uart->reg_in = reg_in_pio; + } + uart->init(uart); + arch_dbg_write = uart_write; + } else if (dbg_type == JAILHOUSE_CON_TYPE_EFIFB) { + efifb_init(); + arch_dbg_write = efifb_write; + } +} diff --git a/hypervisor/arch/x86/efifb.c b/hypervisor/arch/x86/efifb.c new file mode 100644 index 0000000000000000000000000000000000000000..372cf7909afe00bc6d197192d3938393fb6bf7a5 --- /dev/null +++ b/hypervisor/arch/x86/efifb.c @@ -0,0 +1,116 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +#define EFIFB_MAX_WIDTH 1920 +#define EFIFB_MAX_HEIGHT 1080 +#define EFIFB_FONT_WIDTH 8 +#define EFIFB_FONT_HEIGHT 16 +#define EFIFB_LINE_LEN (EFIFB_FONT_WIDTH * efifb_width) +#define EFIFB_FG_COLOR 0x00ff00 /* green */ +#define EFIFB_BG_COLOR 0x000000 /* black */ + +asm( +" .pushsection \".rodata\"\n" +"font8x16:\n" +" .incbin \"altc-8x16\"\n" +" .popsection\n" +); + +extern const u8 font8x16[]; + +static unsigned int efifb_width, efifb_height; +static char efifb_buffer[EFIFB_MAX_HEIGHT][EFIFB_MAX_WIDTH]; +static u32 row_line; + +static void efifb_write_char(unsigned int line, unsigned int row, char c) +{ + unsigned int x, y, font_line, color, offs; + + for (y = 0; y < EFIFB_FONT_HEIGHT; y++) { + font_line = font8x16[c * EFIFB_FONT_HEIGHT + y]; + + for (x = 0; x < EFIFB_FONT_WIDTH; x++) { + if (font_line & (1 << (EFIFB_FONT_WIDTH - x))) + color = EFIFB_FG_COLOR; + else + color = EFIFB_BG_COLOR; + offs = (row * EFIFB_FONT_WIDTH) + x + + (line * EFIFB_FONT_HEIGHT + y) * EFIFB_LINE_LEN; + ((u32 *)hypervisor_header.debug_console_base)[offs] = + color; + } + } + + efifb_buffer[line][row] = c; +} + +static void efifb_scroll(void) +{ + unsigned int row, line; + + for (line = 0; line < (efifb_height - 1); line++) + for (row = 0; row < efifb_width; row++) + efifb_write_char(line, row, + efifb_buffer[line + 1][row]); + + for (row = 0; row < efifb_width; row++) + efifb_write_char(efifb_height - 1, row, ' '); +} + +void efifb_write(const char *msg) +{ + /* + * panic_printk() avoids locking 'printk_lock' due to a potential + * deadlock in case a crash occurs while holding it. For avoiding + * a data race between printk and panic_printk, we take a local + * snapshot of both static variables and update them on return. + */ + u16 row = (u16)(row_line >> 16); + u16 line = (u16)row_line; + + while (*msg != 0) { + if (panic_in_progress && panic_cpu != phys_processor_id()) + return; + + if (row == efifb_width || *msg == '\n') { + row = 0; + if (line == efifb_height - 1) + efifb_scroll(); + else + line++; + } + + if (*msg != '\n' && *msg != '\r') { + efifb_write_char(line, row, *msg); + row++; + } + msg++; + } + + row_line = ((u32)row << 16) | (u32)line; +} + +void efifb_init(void) +{ + if (FB_IS_1920x1080(system_config->debug_console.flags)) { + efifb_width = 1920 / EFIFB_FONT_WIDTH; + efifb_height = 1080 / EFIFB_FONT_HEIGHT; + } else { + efifb_width = 1024 / EFIFB_FONT_WIDTH; + efifb_height = 768 / EFIFB_FONT_HEIGHT; + } +} diff --git a/hypervisor/arch/x86/entry.S b/hypervisor/arch/x86/entry.S new file mode 100644 index 0000000000000000000000000000000000000000..295f0845f504dd5f4a46f4cdc16566719d4c4692 --- /dev/null +++ b/hypervisor/arch/x86/entry.S @@ -0,0 +1,143 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +/* Entry point for Linux loader module on JAILHOUSE_ENABLE */ + .text + .globl arch_entry +arch_entry: + cli + + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + + /* Locate the per_cpu region for the given CPU ID */ + mov %rdi,%rsi + imul $PERCPU_SIZE_ASM,%rsi,%rsi + lea __page_pool(%rip),%rax + add %rax,%rsi + + /* Save the Linux stack pointer inside the per_cpu region */ + mov %rsp,PERCPU_LINUX_SP(%rsi) + + /* Set the Jailhouse stack pointer */ + lea PERCPU_STACK_END-8(%rsi),%rsp + + push %rsi + + /* + * Call the architecture-independent entry(cpuid, struct per_cpu*) + * function. + */ + call entry + + pop %rsi + + mov PERCPU_LINUX_SP(%rsi),%rsp + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbx + pop %rbp + + ret + + +/* Exception/interrupt entry points */ +.macro common_exception_entry vector + .cfi_startproc + .cfi_def_cfa_offset 16 + pushq $\vector + .cfi_adjust_cfa_offset 8 + mov %rsp,%rdi + call x86_exception_handler +1: jmp 1b + .cfi_endproc +.endm + +.macro no_error_entry vector + .balign 16 + pushq $(EXCEPTION_NO_ERROR) + common_exception_entry \vector +.endm + +.macro error_entry vector + .balign 16 + common_exception_entry \vector +.endm + + .global exception_entries + .balign 16 +exception_entries: + no_error_entry 0 + no_error_entry 1 +vector=3 +.rept 5 + no_error_entry vector + vector=vector+1 +.endr + error_entry 8 + no_error_entry 9 +vector=10 +.rept 5 + error_entry vector + vector=vector+1 +.endr + no_error_entry 16 + error_entry 17 + no_error_entry 18 + no_error_entry 19 + + +.macro interrupt_entry func + push %rax + push %rcx + push %rdx + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + + call \func + + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rdx + pop %rcx + pop %rax + + iretq +.endm + + .global nmi_entry + .balign 16 +nmi_entry: + interrupt_entry vcpu_nmi_handler + + .global irq_entry + .balign 16 +irq_entry: + interrupt_entry apic_irq_handler diff --git a/hypervisor/arch/x86/i8042.c b/hypervisor/arch/x86/i8042.c new file mode 100644 index 0000000000000000000000000000000000000000..d98b690392ee4a23306f98493cbbe00c3b16d2d5 --- /dev/null +++ b/hypervisor/arch/x86/i8042.c @@ -0,0 +1,47 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#include + +int i8042_access_handler(u16 port, bool dir_in, unsigned int size) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + u8 val; + + if (port == I8042_CMD_REG && this_cell()->arch.pio_i8042_allowed) { + if (size != 1) + goto invalid_access; + if (dir_in) { + guest_regs->rax &= ~BYTE_MASK(1); + guest_regs->rax |= inb(I8042_CMD_REG); + } else { + val = (u8)guest_regs->rax; + if (val == I8042_CMD_WRITE_CTRL_PORT || + (val & I8042_CMD_PULSE_CTRL_PORT) == + I8042_CMD_PULSE_CTRL_PORT) + goto invalid_access; + outb(val, I8042_CMD_REG); + } + return 1; + } + return 0; + +invalid_access: + panic_printk("FATAL: Invalid write to i8042 controller port\n"); + return -1; +} diff --git a/hypervisor/arch/x86/include/asm/amd_iommu.h b/hypervisor/arch/x86/include/asm/amd_iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..92bd85289a9bcb58e2192aa12d7729b30e41a16c --- /dev/null +++ b/hypervisor/arch/x86/include/asm/amd_iommu.h @@ -0,0 +1,34 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014, 2015 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Valentine Sinitsyn + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_AMD_IOMMU_H +#define _JAILHOUSE_ASM_AMD_IOMMU_H + +#include +#include + +#include + +#define AMD_IOMMU_PTE_P (1ULL << 0) +#define AMD_IOMMU_PTE_PG_MODE(level) ((level) << 9) +#define AMD_IOMMU_PTE_PG_MODE_MASK BIT_MASK(11, 9) +#define AMD_IOMMU_PTE_IR (1ULL << 61) +#define AMD_IOMMU_PTE_IW (1ULL << 62) + +#define AMD_IOMMU_PAGE_DEFAULT_FLAGS (AMD_IOMMU_PTE_IW | AMD_IOMMU_PTE_IR | \ + AMD_IOMMU_PTE_P) + +u64 amd_iommu_get_memory_region_flags(const struct jailhouse_memory *mem); + +#endif diff --git a/hypervisor/arch/x86/include/asm/apic.h b/hypervisor/arch/x86/include/asm/apic.h new file mode 100644 index 0000000000000000000000000000000000000000..5bddf4da713d04ba7bdfcb13a649531639346162 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/apic.h @@ -0,0 +1,174 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_APIC_H +#define _JAILHOUSE_ASM_APIC_H + +#include +#include +#include + +/* currently our limit due to fixed-size APID ID map */ +#define APIC_MAX_PHYS_ID 254 +#define CPU_ID_INVALID 255 + +#define XAPIC_BASE 0xfee00000 + +#define APIC_BASE_EXTD (1 << 10) +#define APIC_BASE_EN (1 << 11) + +#define APIC_NUM_INT_REGS (256/32) + +#define APIC_REG_ID 0x02 +#define APIC_REG_LVR 0x03 +#define APIC_REG_TPR 0x08 +#define APIC_REG_EOI 0x0b +#define APIC_REG_LDR 0x0d +#define APIC_REG_DFR 0x0e +#define APIC_REG_SVR 0x0f +#define APIC_REG_ISR0 0x10 +#define APIC_REG_LVTCMCI 0x2f +#define APIC_REG_ICR 0x30 +#define APIC_REG_ICR_HI 0x31 +#define APIC_REG_LVTT 0x32 +#define APIC_REG_LVTTHMR 0x33 +#define APIC_REG_LVTPC 0x34 +#define APIC_REG_LVT0 0x35 +#define APIC_REG_LVT1 0x36 +#define APIC_REG_LVTERR 0x37 +#define APIC_REG_SELF_IPI 0x3f +#define APIC_REG_XFEAT 0x40 +#define APIC_REG_XLVT0 0x50 +#define APIC_REG_XLVT3 0x53 + +#define APIC_EOI_ACK 0 +#define APIC_SVR_ENABLE_APIC (1 << 8) +#define APIC_ICR_VECTOR_MASK BIT_MASK(7, 0) +#define APIC_ICR_DLVR_MASK BIT_MASK(10, 8) +#define APIC_ICR_DLVR_SHIFT 8 +#define APIC_ICR_DLVR_FIXED (0b000 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DLVR_LOWPRI (0b001 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DLVR_SMI (0b010 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DLVR_NMI (0b100 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DLVR_INIT (0b101 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DLVR_SIPI (0b110 << APIC_ICR_DLVR_SHIFT) +#define APIC_ICR_DEST_PHYSICAL (0 << 11) +#define APIC_ICR_DEST_LOGICAL (1 << 11) +#define APIC_ICR_DS_PENDING (1 << 12) +#define APIC_ICR_LVTM_MASK BIT_MASK(15, 14) +#define APIC_ICR_LV_DEASSERT (0 << 14) +#define APIC_ICR_LV_ASSERT (1 << 14) +#define APIC_ICR_TM_EDGE (0 << 15) +#define APIC_ICR_TM_LEVEL (1 << 15) +#define APIC_ICR_SH_MASK BIT_MASK(19, 18) +#define APIC_ICR_SH_NONE (0b00 << 18) +#define APIC_ICR_SH_SELF (0b01 << 18) +#define APIC_ICR_SH_ALL (0b10 << 18) +#define APIC_ICR_SH_ALLOTHER (0b11 << 18) + +#define APIC_LVT_DLVR_MASK BIT_MASK(10, 8) +#define APIC_LVT_DLVR_FIXED (0b000 << 8) +#define APIC_LVT_DLVR_NMI (0b100 << 8) +#define APIC_LVT_MASKED (1 << 16) + +#define APIC_LVR_EAS (1 << 31) + +#define XAPIC_DEST_MASK BIT_MASK(31, 24) +#define XAPIC_DEST_SHIFT 24 + +#define X2APIC_DEST_LOGICAL_ID_MASK BIT_MASK(15, 0) +#define X2APIC_DEST_CLUSTER_ID_MASK BIT_MASK(31, 16) +#define X2APIC_DEST_CLUSTER_ID_SHIFT 16 + +#define X2APIC_CLUSTER_ID_SHIFT 4 + +#define APIC_BSP_PSEUDO_SIPI 0x100 + +/** + * @ingroup X86 + * @defgroup X86-APIC APIC + * + * The x86 Advanced Programmable Interrupt Controller supports xAPIC and x2APIC. + * + * @{ + */ + +union x86_msi_vector { + struct { + u64 unused:2, + dest_logical:1, + redir_hint:1, + reserved1:8, + destination:8, + address:44; + u32 vector:8, + delivery_mode:3, + reserved:21; + } __attribute__((packed)) native; + struct { + u64 unused:2, + int_index15:1, + shv:1, + remapped:1, + int_index:15, + address:44; + u16 subhandle; + u16 zero; + } __attribute__((packed)) remap; + struct { + u64 address; + u32 data; + } __attribute__((packed)) raw; +} __attribute__((packed)); + +/* MSI delivery modes */ +#define MSI_DM_NMI (0x4 << 8) + +#define MSI_ADDRESS_VALUE 0xfee + +/* APIC IRQ message: delivery modes */ +#define APIC_MSG_DLVR_FIXED 0x0 +#define APIC_MSG_DLVR_LOWPRI 0x1 + +struct apic_irq_message { + u8 vector; + u8 delivery_mode:3; + u8 dest_logical:1; + u8 level_triggered:1; + u8 redir_hint:1; + u8 valid:1; + u32 destination; +}; + +extern bool using_x2apic; + +int apic_init(void); +int apic_cpu_init(struct per_cpu *cpu_data); + +void apic_clear(void); + +void apic_send_nmi_ipi(struct public_per_cpu *target_data); +bool apic_filter_irq_dest(struct cell *cell, struct apic_irq_message *irq_msg); +void apic_send_irq(struct apic_irq_message irq_msg); + +void apic_irq_handler(void); + +unsigned int apic_mmio_access(const struct guest_paging_structures *pg_structs, + unsigned int reg, bool is_write); + +bool x2apic_handle_write(void); +void x2apic_handle_read(void); + +u32 x2apic_filter_logical_dest(struct cell *cell, u32 destination); + +/** @} */ +#endif /* !_JAILHOUSE_ASM_APIC_H */ diff --git a/hypervisor/arch/x86/include/asm/bitops.h b/hypervisor/arch/x86/include/asm/bitops.h new file mode 100644 index 0000000000000000000000000000000000000000..140aad3aec0429b478fc32940f507aad506f31ab --- /dev/null +++ b/hypervisor/arch/x86/include/asm/bitops.h @@ -0,0 +1,75 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * This file is based on linux/arch/x86/include/asm/bitops.h: + * + * Copyright 1992, Linus Torvalds. + * Copyright (c) Linux kernel developers, 2013 + */ + +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) +/* Technically wrong, but this avoids compilation errors on some gcc + versions. */ +#define BITOP_ADDR(x) "=m" (*(volatile long *) (x)) +#else +#define BITOP_ADDR(x) "+m" (*(volatile long *) (x)) +#endif + +static inline __attribute__((always_inline)) int +constant_test_bit(unsigned int nr, const volatile unsigned long *addr) +{ + return ((1UL << (nr % BITS_PER_LONG)) & + (addr[nr / BITS_PER_LONG])) != 0; +} + +static inline int variable_test_bit(int nr, volatile const unsigned long *addr) +{ + int oldbit; + + asm volatile("bt %2,%1\n\t" + "sbb %0,%0" + : "=r" (oldbit) + : "m" (*(unsigned long *)addr), "Ir" (nr)); + + return oldbit; +} + +#define test_bit(nr, addr) \ + (__builtin_constant_p((nr)) \ + ? constant_test_bit((nr), (addr)) \ + : variable_test_bit((nr), (addr))) + +static inline int atomic_test_and_set_bit(int nr, volatile unsigned long *addr) +{ + int oldbit; + + asm volatile("lock btsq %2,%1\n\t" + "sbb %0,%0" : "=r" (oldbit), BITOP_ADDR(addr) + : "Ir" (nr) : "memory"); + + return oldbit; +} + +static inline unsigned long ffzl(unsigned long word) +{ + asm("rep; bsf %1,%0" + : "=r" (word) + : "r" (~word)); + return word; +} + +static inline unsigned long ffsl(unsigned long word) +{ + asm("rep; bsf %1,%0" + : "=r" (word) + : "rm" (word)); + return word; +} diff --git a/hypervisor/arch/x86/include/asm/cat.h b/hypervisor/arch/x86/include/asm/cat.h new file mode 100644 index 0000000000000000000000000000000000000000..847c02776ddd6b2a3bb52c3abbcb2d72e4a4e5b4 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/cat.h @@ -0,0 +1,13 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +void cat_update(void); diff --git a/hypervisor/arch/x86/include/asm/cell.h b/hypervisor/arch/x86/include/asm/cell.h new file mode 100644 index 0000000000000000000000000000000000000000..6c5151a5a2e26de29c9374ff64ffbf99801c00bc --- /dev/null +++ b/hypervisor/arch/x86/include/asm/cell.h @@ -0,0 +1,67 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_CELL_H +#define _JAILHOUSE_ASM_CELL_H + +#include + +struct cell_ioapic; + +/** x86-specific cell states. */ +struct arch_cell { + /** Buffer for the EPT/NPT root-level page table. */ + u8 __attribute__((aligned(PAGE_SIZE))) root_table_page[PAGE_SIZE]; + + bool pio_i8042_allowed; + + /* Intel: PIO access bitmap. + * AMD: I/O Permissions Map. */ + u8 *io_bitmap; + union { + struct { + /** Paging structures used for cell CPUs. */ + struct paging_structures ept_structs; + } vmx; /**< Intel VMX-specific fields. */ + struct { + /** Paging structures used for cell CPUs and IOMMU. */ + struct paging_structures npt_iommu_structs; + } svm; /**< AMD SVM-specific fields. */ + }; + + union { + struct { + /** Paging structures used for DMA requests. */ + struct paging_structures pg_structs; + /** True if interrupt remapping support is emulated for this + * cell. */ + bool ir_emulation; + } vtd; /**< Intel VT-d specific fields. */ + }; + + /** Shadow value of PCI config space address port register. */ + u32 pci_addr_port_val; + + /** List of IOAPICs assigned to this cell. */ + struct cell_ioapic *ioapics; + /** Number of assigned IOAPICs. */ + unsigned int num_ioapics; + + /** Class Of Service for cache allocation (Intel only). */ + u32 cos; + /** Allocated L3 cache region (Intel only). */ + u64 cat_mask; +}; + +#endif /* !_JAILHOUSE_ASM_CELL_H */ diff --git a/hypervisor/arch/x86/include/asm/control.h b/hypervisor/arch/x86/include/asm/control.h new file mode 100644 index 0000000000000000000000000000000000000000..2566e115189add51dd379b1d747854852aa6f655 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/control.h @@ -0,0 +1,25 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +struct exception_frame; + +enum x86_init_sipi { X86_INIT, X86_SIPI }; + +void x86_send_init_sipi(unsigned int cpu_id, enum x86_init_sipi type, + int sipi_vector); + +void x86_check_events(void); + +void __attribute__((noreturn)) +x86_exception_handler(struct exception_frame *frame); diff --git a/hypervisor/arch/x86/include/asm/efifb.h b/hypervisor/arch/x86/include/asm/efifb.h new file mode 100644 index 0000000000000000000000000000000000000000..6a6440c5221407bcfbcb062af337be286281c6e0 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/efifb.h @@ -0,0 +1,14 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +void efifb_init(void); +void efifb_write(const char *msg); diff --git a/hypervisor/arch/x86/include/asm/i8042.h b/hypervisor/arch/x86/include/asm/i8042.h new file mode 100644 index 0000000000000000000000000000000000000000..6bd746991d50b87981a39b9d99f8ef0c36750547 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/i8042.h @@ -0,0 +1,24 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_I8042_H +#define _JAILHOUSE_ASM_I8042_H + +#include + +#define I8042_CMD_REG 0x64 +# define I8042_CMD_WRITE_CTRL_PORT 0xd1 +# define I8042_CMD_PULSE_CTRL_PORT 0xf0 + +int i8042_access_handler(u16 port, bool dir_in, unsigned int size); + +#endif /* !_JAILHOUSE_ASM_I8042_H */ diff --git a/hypervisor/arch/x86/include/asm/io.h b/hypervisor/arch/x86/include/asm/io.h new file mode 100644 index 0000000000000000000000000000000000000000..2d33d88f2b9c820b5109c68d5f68bfad0c891a82 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/io.h @@ -0,0 +1,75 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/** + * @ingroup IO + * @defgroup IO-X86 x86 + * @{ + */ + +/** + * Read 8 (b), 16(w) or 32-bit (l) value from a port. + * @param port Port number. + * + * @return Read value. + * @{ + */ +static inline u8 inb(u16 port) +{ + u8 v; + + asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline u16 inw(u16 port) +{ + u16 v; + + asm volatile("inw %w1,%0" : "=a" (v) : "Nd" (port)); + return v; +} + +static inline u32 inl(u16 port) +{ + u32 v; + + asm volatile("inl %1,%0" : "=a" (v) : "dN" (port)); + return v; +} +/** @} */ + +/** + * Write 8 (b), 16(w) or 32-bit (l) value to a port. + * @param value Value to write + * @param port Port number. + * @{ + */ +static inline void outb(u8 value, u16 port) +{ + asm volatile("outb %0,%1" : : "a" (value), "dN" (port)); +} + +static inline void outw(u16 value, u16 port) +{ + asm volatile("outw %w0,%w1" : : "a" (value), "Nd" (port)); +} + +static inline void outl(u32 value, u16 port) +{ + asm volatile("outl %0,%1" : : "a" (value), "Nd" (port)); +} +/** @} */ + +/** @} */ diff --git a/hypervisor/arch/x86/include/asm/ioapic.h b/hypervisor/arch/x86/include/asm/ioapic.h new file mode 100644 index 0000000000000000000000000000000000000000..f58ea2fce381319b17ba2ab80270bea1bbd6760c --- /dev/null +++ b/hypervisor/arch/x86/include/asm/ioapic.h @@ -0,0 +1,96 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +/* + * There can be up to 240 pins according to the specs, but it remains unclear + * how those can be addressed because only an 8-bit index register is specified + * so far. Therefore, we limit ourselves to implementations with up to 120 pins. + * That has the additional advantage that we can continue to use only a single + * struct jailhouse_irqchip to describe an IOAPIC so that we can keep a 1:1 + * relationship with struct cell_ioapic. + */ +#define IOAPIC_MAX_PINS 120 + +union ioapic_redir_entry { + struct { + u8 vector; + u8 delivery_mode:3; + u8 dest_logical:1; + u8 delivery_status:1; + u8 pin_polarity:1; + u8 remote_irr:1; + u8 level_triggered:1; + u32 mask:1; + u32 reserved:31; + u8 edid; + u8 destination; + } __attribute__((packed)) native; + struct { + u8 vector; + u8 zero:3; + u8 int_index15:1; + u8 delivery_status:1; + u8 pin_polarity:1; + u8 remote_irr:1; + u8 level_triggered:1; + u32 mask:1; + u32 reserved:31; + u16 remapped:1; + u16 int_index:15; + } __attribute__((packed)) remap; + u32 raw[2]; +} __attribute__((packed)); + +/** + * Global physical IOAPIC irqchip state. + */ +struct phys_ioapic { + /** Physical address to identify the instance. */ + unsigned long base_addr; + /** Virtual address of mapped registers. */ + void *reg_base; + /** Number of supported pins. */ + unsigned int pins; + /** Lock protecting physical accesses. */ + spinlock_t lock; + /** Shadow state of redirection entries as seen by the cells. */ + union ioapic_redir_entry shadow_redir_table[IOAPIC_MAX_PINS]; +}; + +/** + * Per-cell IOAPIC irqchip state. + */ +struct cell_ioapic { + /** Reference to static irqchip configuration. */ + const struct jailhouse_irqchip *info; + /** Cell owning at least one pin of the IOAPIC. */ + struct cell *cell; + /** Reference to corresponding physical IOAPIC */ + struct phys_ioapic *phys_ioapic; + + /** Shadow value of index register. */ + u32 index_reg_val; + /** Bitmap of pins currently assigned to this cell. */ + u32 pin_bitmap[(IOAPIC_MAX_PINS + 31) / 32]; +}; + +void ioapic_prepare_handover(void); + +int ioapic_get_or_add_phys(const struct jailhouse_irqchip *irqchip, + struct phys_ioapic **phys_ioapic_ptr); + +void ioapic_cell_reset(struct cell *cell); + +void ioapic_config_commit(struct cell *cell_added_removed); diff --git a/hypervisor/arch/x86/include/asm/iommu.h b/hypervisor/arch/x86/include/asm/iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..848feb77ed8dff80b1cee5ed11835d65051b1563 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/iommu.h @@ -0,0 +1,53 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_IOMMU_H +#define _JAILHOUSE_ASM_IOMMU_H + +#include +#include +#include +#include +#include +#include +#include + +extern unsigned int fault_reporting_cpu_id; + +unsigned int iommu_count_units(void); + +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +int iommu_add_pci_device(struct cell *cell, struct pci_device *device); +void iommu_remove_pci_device(struct pci_device *device); + +struct apic_irq_message iommu_get_remapped_root_int(unsigned int iommu, + u16 device_id, + unsigned int vector, + unsigned int remap_index); +int iommu_map_interrupt(struct cell *cell, + u16 device_id, + unsigned int vector, + struct apic_irq_message irq_msg); + +void iommu_config_commit(struct cell *cell_added_removed); + +void iommu_prepare_shutdown(void); + +struct public_per_cpu *iommu_select_fault_reporting_cpu(void); +void iommu_check_pending_faults(void); + +bool iommu_cell_emulates_ir(struct cell *cell); + +#endif diff --git a/hypervisor/arch/x86/include/asm/ivshmem.h b/hypervisor/arch/x86/include/asm/ivshmem.h new file mode 100644 index 0000000000000000000000000000000000000000..69662b701a8ef9a1e7452c2f7aab097fcc9519c7 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/ivshmem.h @@ -0,0 +1,17 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +struct arch_ivshmem_irq_cache { + struct apic_irq_message msg[IVSHMEM_MSIX_VECTORS]; +}; diff --git a/hypervisor/arch/x86/include/asm/jailhouse_header.h b/hypervisor/arch/x86/include/asm/jailhouse_header.h new file mode 100644 index 0000000000000000000000000000000000000000..020af0292c368efc7c60ba6b226fb5f893acb0d9 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/jailhouse_header.h @@ -0,0 +1,14 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define JAILHOUSE_BASE __JH_CONST_UL(0xfffffffff0000000) +#define JAILHOUSE_BORROW_ROOT_PT 1 diff --git a/hypervisor/arch/x86/include/asm/mmio.h b/hypervisor/arch/x86/include/asm/mmio.h new file mode 100644 index 0000000000000000000000000000000000000000..4b3b2ea880484633b0e194a5c9c08f8ca01c8d61 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/mmio.h @@ -0,0 +1,51 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +/** + * @ingroup IO + * @addtogroup IO-X86 x86 + * @{ + */ + +/** Information about MMIO instruction performing an access. */ +struct mmio_instruction { + /** Length of the MMIO access instruction, 0 for invalid or unsupported + * access. */ + unsigned int inst_len; + /** Size of the access. */ + unsigned int access_size; + /** Number of the register that should receive the input. */ + unsigned int in_reg_num; + /** Output value, already copied either from a register or + * from an immediate value */ + unsigned long out_val; + /** A read must not clear the upper bits of registers, if the access + * width is smaller than 32 bit. This mask describes the bits that have + * to be preserved. + */ + unsigned long reg_preserve_mask; +}; + +/** + * Parse instruction causing an intercepted MMIO access on a cell CPU. + * @param pg_structs Currently active guest (cell) paging structures. + * @param is_write True if write access, false for read. + * + * @return MMIO instruction information. mmio_instruction::inst_len is 0 on + * invalid or unsupported access. + */ +struct mmio_instruction +x86_mmio_parse(const struct guest_paging_structures *pg_structs, bool is_write); + +/** @} */ diff --git a/hypervisor/arch/x86/include/asm/paging.h b/hypervisor/arch/x86/include/asm/paging.h new file mode 100644 index 0000000000000000000000000000000000000000..065bac9bea351d3177ecd14fb132547ecdb8b9b6 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/paging.h @@ -0,0 +1,72 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PAGING_H +#define _JAILHOUSE_ASM_PAGING_H + +#include +#include +#include + +#define PAGE_SHIFT 12 + +#define MAX_PAGE_TABLE_LEVELS 4 + +#define PAGE_FLAG_PRESENT 0x01 +#define PAGE_FLAG_RW 0x02 +#define PAGE_FLAG_US 0x04 +#define PAGE_FLAG_FRAMEBUFFER 0x08 /* write-combining */ +#define PAGE_FLAG_DEVICE 0x10 /* uncached */ +#define PAGE_FLAG_NOEXECUTE 0x8000000000000000UL + +#define PAGE_DEFAULT_FLAGS (PAGE_FLAG_PRESENT | PAGE_FLAG_RW) +#define PAGE_READONLY_FLAGS PAGE_FLAG_PRESENT +#define PAGE_PRESENT_FLAGS PAGE_FLAG_PRESENT +/* + * Set the higher physical address bits so that non-present mappings point to a + * non-existing physical address, hardening against the L1TF disaster. + */ +#define PAGE_NONPRESENT_FLAGS (INVALID_PHYS_ADDR & BIT_MASK(51, 30)) + +#define INVALID_PHYS_ADDR (~0UL) + +/** + * Location of per-CPU temporary mapping region in hypervisor address space. + */ +#define TEMPORARY_MAPPING_BASE 0x0000008000000000UL +#define NUM_TEMPORARY_PAGES 16 + +#define REMAP_BASE 0xffffff8000000000UL +#define NUM_REMAP_BITMAP_PAGES 4 + +#define CELL_ROOT_PT_PAGES 1 + +#ifndef __ASSEMBLY__ + +typedef unsigned long *pt_entry_t; + +static inline void arch_paging_flush_page_tlbs(unsigned long page_addr) +{ + asm volatile("invlpg (%0)" : : "r" (page_addr)); +} + +extern unsigned long cache_line_size; + +static inline void arch_paging_flush_cpu_caches(void *addr, long size) +{ + for (; size > 0; size -= cache_line_size, addr += cache_line_size) + asm volatile("clflush %0" : "+m" (*(char *)addr)); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PAGING_H */ diff --git a/hypervisor/arch/x86/include/asm/paging_modes.h b/hypervisor/arch/x86/include/asm/paging_modes.h new file mode 100644 index 0000000000000000000000000000000000000000..d4ce40971253c45d7f2299aa7f4e2ccae79c8e0c --- /dev/null +++ b/hypervisor/arch/x86/include/asm/paging_modes.h @@ -0,0 +1,17 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +extern const struct paging x86_64_paging[]; +extern const struct paging pae_paging[]; +extern const struct paging i386_paging[]; diff --git a/hypervisor/arch/x86/include/asm/pci.h b/hypervisor/arch/x86/include/asm/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..5d0c95c79a427e98c30ba100a287d84cd11f34b2 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/pci.h @@ -0,0 +1,42 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Ivan Kolchin + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_PCI_H +#define _JAILHOUSE_ASM_PCI_H + +#include +#include + +/* --- PCI configuration ports --- */ +#define PCI_REG_ADDR_PORT 0xcf8 +#define PCI_REG_DATA_PORT 0xcfc + +/* --- Address register fields --- */ +#define PCI_ADDR_ENABLE (1UL << 31) +#define PCI_ADDR_BDF_SHIFT 8 +#define PCI_ADDR_REGNUM_MASK BIT_MASK(7, 2) + +/** + * @ingroup PCI + * @defgroup PCI-X86 x86 + * @{ + */ + +int x86_pci_config_handler(u16 port, bool dir_in, unsigned int size); + +struct apic_irq_message +x86_pci_translate_msi(struct pci_device *device, unsigned int vector, + unsigned int legacy_vectors, union x86_msi_vector msi); + +/** @} */ +#endif /* !_JAILHOUSE_ASM_PCI_H */ diff --git a/hypervisor/arch/x86/include/asm/percpu.h b/hypervisor/arch/x86/include/asm/percpu.h new file mode 100644 index 0000000000000000000000000000000000000000..d87a2ba637b56050369941d014e1f2dc8be45596 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/percpu.h @@ -0,0 +1,117 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define NUM_ENTRY_REGS 6 + +#define STACK_SIZE PAGE_SIZE + +#define ARCH_PUBLIC_PERCPU_FIELDS \ + /** Physical APIC ID. */ \ + u32 apic_id; \ + \ + /** \ + * Lock protecting CPU state changes done for control tasks. \ + * \ + * The lock protects the following fields (unless CPU is \ + * suspended): \ + * @li public_per_cpu::suspend_cpu \ + * @li public_per_cpu::cpu_suspended (except for spinning on it \ + * to become true) \ + * @li public_per_cpu::wait_for_sipi \ + * @li public_per_cpu::init_signaled \ + * @li public_per_cpu::sipi_vector \ + * @li public_per_cpu::flush_vcpu_caches \ + * @li public_per_cpu::update_cat \ + */ \ + spinlock_t control_lock; \ + \ + /** True if CPU is waiting for SIPI. */ \ + volatile bool wait_for_sipi; \ + /** Set to true for pending an INIT signal. */ \ + volatile bool init_signaled; \ + /** Pending SIPI vector; -1 if none is pending. */ \ + int sipi_vector; \ + /** Set to true for pending cache allocation updates (Intel \ + * only). */ \ + bool update_cat; + +#define ARCH_PERCPU_FIELDS \ + /** Linux stack pointer, used for handover to hypervisor. */ \ + unsigned long linux_sp; \ + \ + /** Linux states, used for handover to/from hypervisor. @{ */ \ + struct desc_table_reg linux_gdtr; \ + struct desc_table_reg linux_idtr; \ + unsigned long linux_reg[NUM_ENTRY_REGS]; \ + unsigned long linux_ip; \ + unsigned long linux_cr0; \ + unsigned long linux_cr3; \ + unsigned long linux_cr4; \ + struct segment linux_cs; \ + struct segment linux_ds; \ + struct segment linux_es; \ + struct segment linux_fs; \ + struct segment linux_gs; \ + struct segment linux_tss; \ + unsigned long linux_efer; \ + /** @} */ \ + \ + /** Shadow states. @{ */ \ + unsigned long pat; \ + unsigned long mtrr_def_type; \ + /** @} */ \ + \ + /** Cached PDPTEs, used by VMX for PAE guest paging mode. */ \ + unsigned long pdpte[4]; \ + \ + /* IOMMU request completion flags */ \ + union { \ + volatile u32 vtd_iq_completed; \ + volatile u64 amd_iommu_sem; \ + }; \ + \ + /** True when CPU is initialized by hypervisor. */ \ + bool initialized; \ + union { \ + /** VMX initialization state */ \ + enum vmx_state vmx_state; \ + /** SVM initialization state */ \ + enum {SVMOFF = 0, SVMON} svm_state; \ + }; \ + \ + /** Number of iterations to clear pending APIC IRQs. */ \ + unsigned int num_clear_apic_irqs; \ + \ + union { \ + struct { \ + /** VMXON region, required by VMX. */ \ + struct vmcs vmxon_region \ + __attribute__((aligned(PAGE_SIZE))); \ + /** VMCS of this CPU, required by VMX. */ \ + struct vmcs vmcs \ + __attribute__((aligned(PAGE_SIZE))); \ + }; \ + struct { \ + /** VMCB block, required by SVM. */ \ + struct vmcb vmcb \ + __attribute__((aligned(PAGE_SIZE))); \ + /** SVM Host save area; opaque to us. */ \ + u8 host_state[PAGE_SIZE] \ + __attribute__((aligned(PAGE_SIZE))); \ + }; \ + }; diff --git a/hypervisor/arch/x86/include/asm/processor.h b/hypervisor/arch/x86/include/asm/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..faba3ecc3dafdf5bb3985908ab1c66c6dda8fb30 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/processor.h @@ -0,0 +1,374 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * This file is based on linux/arch/x86/include/asm/special_insn.h and other + * kernel headers: + * + * Copyright (c) Linux kernel developers, 2013 + */ + +#ifndef _JAILHOUSE_ASM_PROCESSOR_H +#define _JAILHOUSE_ASM_PROCESSOR_H + +#include + +/* leaf 0x01, ECX */ +#define X86_FEATURE_VMX (1 << 5) +#define X86_FEATURE_XSAVE (1 << 26) +#define X86_FEATURE_OSXSAVE (1 << 27) +#define X86_FEATURE_HYPERVISOR (1 << 31) + +/* leaf 0x07, subleaf 0, EBX */ +#define X86_FEATURE_INVPCID (1 << 10) +#define X86_FEATURE_CAT (1 << 15) + +/* leaf 0x07, subleaf 0, ECX */ +#define X86_FEATURE_WAITPKG (1 << 5) + +/* leaf 0x0d, subleaf 1, EAX */ +#define X86_FEATURE_XSAVES (1 << 3) + +/* leaf 0x80000001, ECX */ +#define X86_FEATURE_SVM (1 << 2) + +/* leaf 0x80000001, EDX */ +#define X86_FEATURE_GBPAGES (1 << 26) +#define X86_FEATURE_RDTSCP (1 << 27) + +/* leaf 0x8000000a, EDX */ +#define X86_FEATURE_NP (1 << 0) +#define X86_FEATURE_FLUSH_BY_ASID (1 << 6) +#define X86_FEATURE_DECODE_ASSISTS (1 << 7) +#define X86_FEATURE_AVIC (1 << 13) + +#define X86_RFLAGS_VM (1 << 17) + +#define X86_CR0_PE (1UL << 0) +#define X86_CR0_MP (1UL << 1) +#define X86_CR0_TS (1UL << 3) +#define X86_CR0_ET (1UL << 4) +#define X86_CR0_NE (1UL << 5) +#define X86_CR0_WP (1UL << 16) +#define X86_CR0_NW (1UL << 29) +#define X86_CR0_CD (1UL << 30) +#define X86_CR0_PG (1UL << 31) +#define X86_CR0_RESERVED \ + (BIT_MASK(28, 19) | (1UL << 17) | BIT_MASK(15, 6)) + +#define X86_CR4_PAE (1UL << 5) +#define X86_CR4_VMXE (1UL << 13) +#define X86_CR4_OSXSAVE (1UL << 18) +#define X86_CR4_RESERVED \ + (BIT_MASK(31, 23) | (1UL << 19) | (1UL << 15) | (1UL << 12)) + +#define X86_XCR0_FP 0x00000001 + +#define MSR_IA32_APICBASE 0x0000001b +#define MSR_IA32_FEATURE_CONTROL 0x0000003a +#define MSR_IA32_PAT 0x00000277 +#define MSR_IA32_MTRR_DEF_TYPE 0x000002ff +#define MSR_IA32_SYSENTER_CS 0x00000174 +#define MSR_IA32_SYSENTER_ESP 0x00000175 +#define MSR_IA32_SYSENTER_EIP 0x00000176 +#define MSR_IA32_PERF_GLOBAL_CTRL 0x0000038f +#define MSR_IA32_VMX_BASIC 0x00000480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 +#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 +#define MSR_IA32_VMX_MISC 0x00000485 +#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 +#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 +#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 +#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b +#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c +#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e +#define MSR_X2APIC_BASE 0x00000800 +#define MSR_X2APIC_ICR 0x00000830 +#define MSR_X2APIC_END 0x0000083f +#define MSR_IA32_PQR_ASSOC 0x00000c8f +#define MSR_IA32_L3_MASK_0 0x00000c90 +#define MSR_EFER 0xc0000080 +#define MSR_STAR 0xc0000081 +#define MSR_LSTAR 0xc0000082 +#define MSR_CSTAR 0xc0000083 +#define MSR_SFMASK 0xc0000084 +#define MSR_FS_BASE 0xc0000100 +#define MSR_GS_BASE 0xc0000101 +#define MSR_KERNGS_BASE 0xc0000102 + +#define FEATURE_CONTROL_LOCKED (1 << 0) +#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1 << 2) + +#define PAT_RESET_VALUE 0x0007040600070406UL +/* PAT0: WB, PAT1: WC, PAT2: UC- */ +#define PAT_HOST_VALUE 0x070106UL + +#define MTRR_ENABLE (1UL << 11) + +#define EFER_LME 0x00000100 +#define EFER_LMA 0x00000400 +#define EFER_NXE 0x00000800 + +#define PQR_ASSOC_COS_SHIFT 32 + +#define CAT_RESID_L3 1 + +#define CAT_CBM_LEN_MASK BIT_MASK(4, 0) +#define CAT_COS_MAX_MASK BIT_MASK(15, 0) + +#define GDT_DESC_NULL 0 +#define GDT_DESC_CODE 1 +#define GDT_DESC_TSS 2 +#define GDT_DESC_TSS_HI 3 +/* + * Linux uses 16 entries, we only 4. But we need to be able to reload the Linux + * TSS from our GDT because Linux write-protects its GDT. So, leave some space. + */ +#define NUM_GDT_DESC 16 + +#define X86_INST_LEN_CPUID 2 +#define X86_INST_LEN_RDMSR 2 +#define X86_INST_LEN_WRMSR 2 +/* This covers both VMCALL and VMMCALL */ +#define X86_INST_LEN_HYPERCALL 3 +#define X86_INST_LEN_MOV_TO_CR 3 +#define X86_INST_LEN_XSETBV 3 + +#define X86_REX_CODE 4 + +#define X86_PREFIX_OP_SZ 0x66 +#define X86_PREFIX_ADDR_SZ 0x67 + +#define X86_OP_MOVZX_OPC1 0x0f +#define X86_OP_MOVZX_OPC2_B 0xb6 +#define X86_OP_MOVZX_OPC2_W 0xb7 +#define X86_OP_MOVB_TO_MEM 0x88 +#define X86_OP_MOV_TO_MEM 0x89 +#define X86_OP_MOVB_FROM_MEM 0x8a +#define X86_OP_MOV_FROM_MEM 0x8b +#define X86_OP_MOV_IMMEDIATE_TO_MEM 0xc7 +#define X86_OP_MOV_MEM_TO_AX 0xa1 +#define X86_OP_MOV_AX_TO_MEM 0xa3 + +#define DB_VECTOR 1 +#define NMI_VECTOR 2 +#define PF_VECTOR 14 +#define AC_VECTOR 17 + +#define EXCEPTION_NO_ERROR 0xffffffffffffffff + +#define DESC_TSS_BUSY (1UL << (9 + 32)) +#define DESC_PRESENT (1UL << (15 + 32)) +#define DESC_CODE_DATA (1UL << (12 + 32)) +#define DESC_PAGE_GRAN (1UL << (23 + 32)) + +#ifndef __ASSEMBLY__ + +/** + * @ingroup X86 + * @defgroup Processor Processor + * + * Low-level support for x86 processor configuration and status retrieval. + * + * @{ + */ + +union registers { + struct { + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long rdi; + unsigned long rsi; + unsigned long rbp; + unsigned long unused; + unsigned long rbx; + unsigned long rdx; + unsigned long rcx; + unsigned long rax; + }; + unsigned long by_index[16]; +}; + +struct desc_table_reg { + u16 limit; + u64 base; +} __attribute__((packed)); + +struct segment { + u64 base; + u32 limit; + u32 access_rights; + u16 selector; +}; + +static unsigned long __force_order; + +static inline void cpu_relax(void) +{ + asm volatile("rep; nop" : : : "memory"); +} + +static inline void memory_barrier(void) +{ + asm volatile("mfence" : : : "memory"); +} + +static inline void memory_load_barrier(void) +{ + asm volatile("lfence" : : : "memory"); +} + +static inline void cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (*eax), "2" (*ecx) + : "memory"); +} + +#define CPUID_REG(reg) \ +static inline unsigned int cpuid_##reg(unsigned int op, unsigned int sub) \ +{ \ + unsigned int eax, ebx, ecx, edx; \ + \ + eax = op; \ + ecx = sub; \ + cpuid(&eax, &ebx, &ecx, &edx); \ + return reg; \ +} + +CPUID_REG(eax) +CPUID_REG(ebx) +CPUID_REG(ecx) +CPUID_REG(edx) + +static inline unsigned long read_cr0(void) +{ + unsigned long cr0; + + asm volatile("mov %%cr0,%0" : "=r" (cr0), "=m" (__force_order)); + return cr0; +} + +static inline void write_cr0(unsigned long val) +{ + asm volatile("mov %0,%%cr0" : : "r" (val), "m" (__force_order)); +} + +static inline unsigned long read_cr2(void) +{ + unsigned long cr2; + + asm volatile("mov %%cr2,%0" : "=r" (cr2), "=m" (__force_order)); + return cr2; +} + +static inline unsigned long read_cr3(void) +{ + unsigned long cr3; + + asm volatile("mov %%cr3,%0" : "=r" (cr3), "=m" (__force_order)); + return cr3; +} + +static inline void write_cr3(unsigned long val) +{ + asm volatile("mov %0,%%cr3" : : "r" (val), "m" (__force_order)); +} + +static inline unsigned long read_cr4(void) +{ + unsigned long cr4; + + asm volatile("mov %%cr4,%0" : "=r" (cr4), "=m" (__force_order)); + return cr4; +} + +static inline void write_cr4(unsigned long val) +{ + asm volatile("mov %0,%%cr4" : : "r" (val), "m" (__force_order)); +} + +static inline unsigned long read_msr(unsigned int msr) +{ + u32 low, high; + + asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); + return low | ((unsigned long)high << 32); +} + +static inline void write_msr(unsigned int msr, unsigned long val) +{ + asm volatile("wrmsr" + : /* no output */ + : "c" (msr), "a" (val), "d" (val >> 32) + : "memory"); +} + +static inline void set_rdmsr_value(union registers *regs, unsigned long val) +{ + regs->rax = (u32)val; + regs->rdx = val >> 32; +} + +static inline unsigned long get_wrmsr_value(union registers *regs) +{ + return (u32)regs->rax | (regs->rdx << 32); +} + +static inline void read_gdtr(struct desc_table_reg *val) +{ + asm volatile("sgdtq %0" : "=m" (*val)); +} + +static inline void write_gdtr(struct desc_table_reg *val) +{ + asm volatile("lgdtq %0" : : "m" (*val)); +} + +static inline void read_idtr(struct desc_table_reg *val) +{ + asm volatile("sidtq %0" : "=m" (*val)); +} + +static inline void write_idtr(struct desc_table_reg *val) +{ + asm volatile("lidtq %0" : : "m" (*val)); +} + +/** + * Enable or disable interrupts delivery to the local CPU when in host mode. + * + * In some cases (AMD) changing IF isn't enough, so these are implemented on + * per-vendor basis. + * @{ + */ +void enable_irq(void); + +void disable_irq(void); +/** @} */ + +/** @} */ +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_ASM_PROCESSOR_H */ diff --git a/hypervisor/arch/x86/include/asm/sections.h b/hypervisor/arch/x86/include/asm/sections.h new file mode 100644 index 0000000000000000000000000000000000000000..aed71f8d136aca2695f7ad3be75d0a8b3f40801b --- /dev/null +++ b/hypervisor/arch/x86/include/asm/sections.h @@ -0,0 +1,14 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/* no special sections */ +#define ARCH_SECTIONS diff --git a/hypervisor/arch/x86/include/asm/spinlock.h b/hypervisor/arch/x86/include/asm/spinlock.h new file mode 100644 index 0000000000000000000000000000000000000000..ef884246e86f52c59e4500d0bbdbe0ad48239ae2 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/spinlock.h @@ -0,0 +1,49 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * This file is based on linux/arch/x86/include/asm/spinlock.h: + * + * Copyright (c) Linux kernel developers, 2014 + */ + +#ifndef _JAILHOUSE_ASM_SPINLOCK_H +#define _JAILHOUSE_ASM_SPINLOCK_H + +#include + +typedef struct { + u16 owner, next; +} spinlock_t; + +static inline void spin_lock(spinlock_t *lock) +{ + register spinlock_t inc = { .next = 1 }; + + asm volatile("lock xaddl %0, %1" + : "+r" (inc), "+m" (*lock) + : : "memory", "cc"); + + if (inc.owner != inc.next) + while (lock->owner != inc.next) + cpu_relax(); + + asm volatile("" : : : "memory"); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + asm volatile("addw %1, %0" + : "+m" (lock->owner) + : "ri" (1) + : "memory", "cc"); +} + +#endif /* !_JAILHOUSE_ASM_SPINLOCK_H */ diff --git a/hypervisor/arch/x86/include/asm/svm.h b/hypervisor/arch/x86/include/asm/svm.h new file mode 100644 index 0000000000000000000000000000000000000000..60342cfd46c5dfd25325372446e59b7717a4616f --- /dev/null +++ b/hypervisor/arch/x86/include/asm/svm.h @@ -0,0 +1,356 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) 2005-2007, Advanced Micro Devices, Inc + * Copyright (c) 2004, Intel Corporation. + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This file is partially derived from + * xvisor/arch/x86/cpu/x86_64/include/vm/amd_vmcb.h, which comes with + * Xvisor 0.2 (http://xhypervisor.org). + * + * Copyright (c) 2005-2007, Advanced Micro Devices, Inc + * Copyright (c) 2004, Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_SVM_H +#define _JAILHOUSE_ASM_SVM_H + +#include + +#define EFER_SVME (1UL << 12) +#define VM_CR_SVMDIS (1UL << 4) + +#define MSR_VM_CR 0xc0010114 +#define MSR_VM_HSAVE_PA 0xc0010117 + +#define SVM_MSRPM_0000 0 +#define SVM_MSRPM_C000 1 +#define SVM_MSRPM_C001 2 +#define SVM_MSRPM_RESV 3 + +#define SVM_TLB_FLUSH_ALL 0x01 +#define SVM_TLB_FLUSH_GUEST 0x03 + +#define SVM_EVENTINJ_EXCEPTION (3UL << 8) +#define SVM_EVENTINJ_ERR_VALID (1UL << 11) +#define SVM_EVENTINJ_VALID (1UL << 31) + +struct svm_segment { + u16 selector; + u16 attributes; + u32 limit; + u64 base; +} __attribute__((packed)); + +/* general 1 intercepts */ +enum generic_interrupt_1_bits { + GENERAL1_INTERCEPT_INTR = 1 << 0, + GENERAL1_INTERCEPT_NMI = 1 << 1, + GENERAL1_INTERCEPT_SMI = 1 << 2, + GENERAL1_INTERCEPT_INIT = 1 << 3, + GENERAL1_INTERCEPT_VINTR = 1 << 4, + GENERAL1_INTERCEPT_CR0_SEL_WRITE = 1 << 5, + GENERAL1_INTERCEPT_IDTR_READ = 1 << 6, + GENERAL1_INTERCEPT_GDTR_READ = 1 << 7, + GENERAL1_INTERCEPT_LDTR_READ = 1 << 8, + GENERAL1_INTERCEPT_TR_READ = 1 << 9, + GENERAL1_INTERCEPT_IDTR_WRITE = 1 << 10, + GENERAL1_INTERCEPT_GDTR_WRITE = 1 << 11, + GENERAL1_INTERCEPT_LDTR_WRITE = 1 << 12, + GENERAL1_INTERCEPT_TR_WRITE = 1 << 13, + GENERAL1_INTERCEPT_RDTSC = 1 << 14, + GENERAL1_INTERCEPT_RDPMC = 1 << 15, + GENERAL1_INTERCEPT_PUSHF = 1 << 16, + GENERAL1_INTERCEPT_POPF = 1 << 17, + GENERAL1_INTERCEPT_CPUID = 1 << 18, + GENERAL1_INTERCEPT_RSM = 1 << 19, + GENERAL1_INTERCEPT_IRET = 1 << 20, + GENERAL1_INTERCEPT_SWINT = 1 << 21, + GENERAL1_INTERCEPT_INVD = 1 << 22, + GENERAL1_INTERCEPT_PAUSE = 1 << 23, + GENERAL1_INTERCEPT_HLT = 1 << 24, + GENERAL1_INTERCEPT_INVLPG = 1 << 25, + GENERAL1_INTERCEPT_INVLPGA = 1 << 26, + GENERAL1_INTERCEPT_IOIO_PROT = 1 << 27, + GENERAL1_INTERCEPT_MSR_PROT = 1 << 28, + GENERAL1_INTERCEPT_TASK_SWITCH = 1 << 29, + GENERAL1_INTERCEPT_FERR_FREEZE = 1 << 30, + GENERAL1_INTERCEPT_SHUTDOWN_EVT = 1 << 31 +}; + +/* general 2 intercepts */ +enum generic_interrupts_2_bits { + GENERAL2_INTERCEPT_VMRUN = 1 << 0, + GENERAL2_INTERCEPT_VMMCALL = 1 << 1, + GENERAL2_INTERCEPT_VMLOAD = 1 << 2, + GENERAL2_INTERCEPT_VMSAVE = 1 << 3, + GENERAL2_INTERCEPT_STGI = 1 << 4, + GENERAL2_INTERCEPT_CLGI = 1 << 5, + GENERAL2_INTERCEPT_SKINIT = 1 << 6, + GENERAL2_INTERCEPT_RDTSCP = 1 << 7, + GENERAL2_INTERCEPT_ICEBP = 1 << 8, + GENERAL2_INTERCEPT_WBINVD = 1 << 9, + GENERAL2_INTERCEPT_MONITOR = 1 << 10, + GENERAL2_INTERCEPT_MWAIT = 1 << 11, + GENERAL2_INTERCEPT_MWAIT_CONDITIONAL = 1 << 12 +}; + +enum vm_exit_code { + /* control register read exitcodes */ + VMEXIT_CR0_READ = 0, + VMEXIT_CR1_READ = 1, + VMEXIT_CR2_READ = 2, + VMEXIT_CR3_READ = 3, + VMEXIT_CR4_READ = 4, + VMEXIT_CR5_READ = 5, + VMEXIT_CR6_READ = 6, + VMEXIT_CR7_READ = 7, + VMEXIT_CR8_READ = 8, + VMEXIT_CR9_READ = 9, + VMEXIT_CR10_READ = 10, + VMEXIT_CR11_READ = 11, + VMEXIT_CR12_READ = 12, + VMEXIT_CR13_READ = 13, + VMEXIT_CR14_READ = 14, + VMEXIT_CR15_READ = 15, + + /* control register write exitcodes */ + VMEXIT_CR0_WRITE = 16, + VMEXIT_CR1_WRITE = 17, + VMEXIT_CR2_WRITE = 18, + VMEXIT_CR3_WRITE = 19, + VMEXIT_CR4_WRITE = 20, + VMEXIT_CR5_WRITE = 21, + VMEXIT_CR6_WRITE = 22, + VMEXIT_CR7_WRITE = 23, + VMEXIT_CR8_WRITE = 24, + VMEXIT_CR9_WRITE = 25, + VMEXIT_CR10_WRITE = 26, + VMEXIT_CR11_WRITE = 27, + VMEXIT_CR12_WRITE = 28, + VMEXIT_CR13_WRITE = 29, + VMEXIT_CR14_WRITE = 30, + VMEXIT_CR15_WRITE = 31, + + /* debug register read exitcodes */ + VMEXIT_DR0_READ = 32, + VMEXIT_DR1_READ = 33, + VMEXIT_DR2_READ = 34, + VMEXIT_DR3_READ = 35, + VMEXIT_DR4_READ = 36, + VMEXIT_DR5_READ = 37, + VMEXIT_DR6_READ = 38, + VMEXIT_DR7_READ = 39, + VMEXIT_DR8_READ = 40, + VMEXIT_DR9_READ = 41, + VMEXIT_DR10_READ = 42, + VMEXIT_DR11_READ = 43, + VMEXIT_DR12_READ = 44, + VMEXIT_DR13_READ = 45, + VMEXIT_DR14_READ = 46, + VMEXIT_DR15_READ = 47, + + /* debug register write exitcodes */ + VMEXIT_DR0_WRITE = 48, + VMEXIT_DR1_WRITE = 49, + VMEXIT_DR2_WRITE = 50, + VMEXIT_DR3_WRITE = 51, + VMEXIT_DR4_WRITE = 52, + VMEXIT_DR5_WRITE = 53, + VMEXIT_DR6_WRITE = 54, + VMEXIT_DR7_WRITE = 55, + VMEXIT_DR8_WRITE = 56, + VMEXIT_DR9_WRITE = 57, + VMEXIT_DR10_WRITE = 58, + VMEXIT_DR11_WRITE = 59, + VMEXIT_DR12_WRITE = 60, + VMEXIT_DR13_WRITE = 61, + VMEXIT_DR14_WRITE = 62, + VMEXIT_DR15_WRITE = 63, + + /* processor exception exitcodes (VMEXIT_EXCP[0-31]) */ + VMEXIT_EXCEPTION_DE = 64, /* divide-by-zero-error */ + VMEXIT_EXCEPTION_DB = 65, /* debug */ + VMEXIT_EXCEPTION_NMI = 66, /* non-maskable-interrupt */ + VMEXIT_EXCEPTION_BP = 67, /* breakpoint */ + VMEXIT_EXCEPTION_OF = 68, /* overflow */ + VMEXIT_EXCEPTION_BR = 69, /* bound-range */ + VMEXIT_EXCEPTION_UD = 70, /* invalid-opcode*/ + VMEXIT_EXCEPTION_NM = 71, /* device-not-available */ + VMEXIT_EXCEPTION_DF = 72, /* double-fault */ + VMEXIT_EXCEPTION_09 = 73, /* unsupported (reserved) */ + VMEXIT_EXCEPTION_TS = 74, /* invalid-tss */ + VMEXIT_EXCEPTION_NP = 75, /* segment-not-present */ + VMEXIT_EXCEPTION_SS = 76, /* stack */ + VMEXIT_EXCEPTION_GP = 77, /* general-protection */ + VMEXIT_EXCEPTION_PF = 78, /* page-fault */ + VMEXIT_EXCEPTION_15 = 79, /* reserved */ + VMEXIT_EXCEPTION_MF = 80, /* x87 floating-point exception-pending */ + VMEXIT_EXCEPTION_AC = 81, /* alignment-check */ + VMEXIT_EXCEPTION_MC = 82, /* machine-check */ + VMEXIT_EXCEPTION_XF = 83, /* simd floating-point */ + + /* exceptions 20-31 (exitcodes 84-95) are reserved */ + + /* ...and the rest of the #VMEXITs */ + VMEXIT_INTR = 96, + VMEXIT_NMI = 97, + VMEXIT_SMI = 98, + VMEXIT_INIT = 99, + VMEXIT_VINTR = 100, + VMEXIT_CR0_SEL_WRITE = 101, + VMEXIT_IDTR_READ = 102, + VMEXIT_GDTR_READ = 103, + VMEXIT_LDTR_READ = 104, + VMEXIT_TR_READ = 105, + VMEXIT_IDTR_WRITE = 106, + VMEXIT_GDTR_WRITE = 107, + VMEXIT_LDTR_WRITE = 108, + VMEXIT_TR_WRITE = 109, + VMEXIT_RDTSC = 110, + VMEXIT_RDPMC = 111, + VMEXIT_PUSHF = 112, + VMEXIT_POPF = 113, + VMEXIT_CPUID = 114, + VMEXIT_RSM = 115, + VMEXIT_IRET = 116, + VMEXIT_SWINT = 117, + VMEXIT_INVD = 118, + VMEXIT_PAUSE = 119, + VMEXIT_HLT = 120, + VMEXIT_INVLPG = 121, + VMEXIT_INVLPGA = 122, + VMEXIT_IOIO = 123, + VMEXIT_MSR = 124, + VMEXIT_TASK_SWITCH = 125, + VMEXIT_FERR_FREEZE = 126, + VMEXIT_SHUTDOWN = 127, + VMEXIT_VMRUN = 128, + VMEXIT_VMMCALL = 129, + VMEXIT_VMLOAD = 130, + VMEXIT_VMSAVE = 131, + VMEXIT_STGI = 132, + VMEXIT_CLGI = 133, + VMEXIT_SKINIT = 134, + VMEXIT_RDTSCP = 135, + VMEXIT_ICEBP = 136, + VMEXIT_WBINVD = 137, + VMEXIT_MONITOR = 138, + VMEXIT_MWAIT = 139, + VMEXIT_MWAIT_CONDITIONAL = 140, + VMEXIT_XSETBV = 141, + VMEXIT_NPF = 1024, /* nested paging fault */ + VMEXIT_INVALID = -1 +}; + +enum clean_bits { + CLEAN_BITS_I = 1 << 0, + CLEAN_BITS_IOPM = 1 << 1, + CLEAN_BITS_ASID = 1 << 2, + CLEAN_BITS_TPR = 1 << 3, + CLEAN_BITS_NP = 1 << 4, + CLEAN_BITS_CRX = 1 << 5, + CLEAN_BITS_DRX = 1 << 6, + CLEAN_BITS_DT = 1 << 7, + CLEAN_BITS_SEG = 1 << 8, + CLEAN_BITS_CR2 = 1 << 9, + CLEAN_BITS_LBR = 1 << 10, + CLEAN_BITS_AVIC = 1 << 11 +}; + +typedef u64 vintr_t; +typedef u64 lbrctrl_t; + +struct vmcb { + u32 cr_intercepts; /* offset 0x00 */ + u32 dr_intercepts; /* offset 0x04 */ + u32 exception_intercepts; /* offset 0x08 */ + u32 general1_intercepts; /* offset 0x0C */ + u32 general2_intercepts; /* offset 0x10 */ + u32 res01; /* offset 0x14 */ + u64 res02; /* offset 0x18 */ + u64 res03; /* offset 0x20 */ + u64 res04; /* offset 0x28 */ + u64 res05; /* offset 0x30 */ + u32 res06; /* offset 0x38 */ + u16 res06a; /* offset 0x3C */ + u16 pause_filter_count; /* offset 0x3E */ + u64 iopm_base_pa; /* offset 0x40 */ + u64 msrpm_base_pa; /* offset 0x48 */ + u64 tsc_offset; /* offset 0x50 */ + u32 guest_asid; /* offset 0x58 */ + u8 tlb_control; /* offset 0x5C */ + u8 res07[3]; + vintr_t vintr; /* offset 0x60 */ + u64 interrupt_shadow; /* offset 0x68 */ + u64 exitcode; /* offset 0x70 */ + u64 exitinfo1; /* offset 0x78 */ + u64 exitinfo2; /* offset 0x80 */ + u64 exitintinfo; /* offset 0x88 */ + u64 np_enable; /* offset 0x90 */ + u64 res08[2]; + u32 eventinj; /* offset 0xA8 */ + u32 eventinj_err; /* offset 0xAC */ + u64 n_cr3; /* offset 0xB0 */ + lbrctrl_t lbr_control; /* offset 0xB8 */ + u64 clean_bits; /* offset 0xC0 */ + u64 nextrip; /* offset 0xC8 */ + u8 bytes_fetched; /* offset 0xD0 */ + u8 guest_bytes[15]; + u64 res10a[100]; /* offset 0xE0 pad to save area */ + + struct svm_segment es; /* offset 1024 */ + struct svm_segment cs; + struct svm_segment ss; + struct svm_segment ds; + struct svm_segment fs; + struct svm_segment gs; + struct svm_segment gdtr; + struct svm_segment ldtr; + struct svm_segment idtr; + struct svm_segment tr; + + u64 res10[5]; + u8 res11[3]; + u8 cpl; + u32 res12; + u64 efer; /* offset 1024 + 0xD0 */ + u64 res13[14]; + u64 cr4; /* loffset 1024 + 0x148 */ + u64 cr3; + u64 cr0; + u64 dr7; + u64 dr6; + u64 rflags; + u64 rip; + u64 res14[11]; + u64 rsp; + u64 res15[3]; + u64 rax; + u64 star; + u64 lstar; + u64 cstar; + u64 sfmask; + u64 kerngsbase; + u64 sysenter_cs; + u64 sysenter_esp; + u64 sysenter_eip; + u64 cr2; + u8 reserved[32]; + u64 g_pat; + u64 debugctlmsr; + u64 lastbranchfromip; + u64 lastbranchtoip; + u64 lastintfromip; + u64 lastinttoip; + u64 res16[301]; +} __attribute__((packed)); + +#endif diff --git a/hypervisor/arch/x86/include/asm/types.h b/hypervisor/arch/x86/include/asm/types.h new file mode 100644 index 0000000000000000000000000000000000000000..657c47c7836925e4a7f3b3a7198b607fda1289c7 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/types.h @@ -0,0 +1,19 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/** + * @defgroup X86 x86 Architecture + * + * Documentation for the x86 processor architecture. + */ + +#define BITS_PER_LONG 64 diff --git a/hypervisor/arch/x86/include/asm/vcpu.h b/hypervisor/arch/x86/include/asm/vcpu.h new file mode 100644 index 0000000000000000000000000000000000000000..37c9630b841a5ad3fae211417c1eca119bf7d653 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/vcpu.h @@ -0,0 +1,120 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ASM_VCPU_H +#define _JAILHOUSE_ASM_VCPU_H + +#include +#include +#include +#include +#include +#include + +#define X86_CR0_HOST_STATE \ + (X86_CR0_PG | X86_CR0_WP | X86_CR0_NE | X86_CR0_ET | X86_CR0_TS | \ + X86_CR0_MP | X86_CR0_PE) +#define X86_CR4_HOST_STATE X86_CR4_PAE + +struct vcpu_io_intercept { + u16 port; + unsigned int size; + bool in; + unsigned int inst_len; + bool rep_or_str; +}; + +struct vcpu_mmio_intercept { + u64 phys_addr; + bool is_write; +}; + +int vcpu_early_init(void); + +int vcpu_vendor_early_init(void); + +int vcpu_cell_init(struct cell *cell); +int vcpu_vendor_cell_init(struct cell *cell); + +int vcpu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +int vcpu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); +void vcpu_cell_exit(struct cell *cell); +void vcpu_vendor_cell_exit(struct cell *cell); + +int vcpu_init(struct per_cpu *cpu_data); +void vcpu_exit(struct per_cpu *cpu_data); + +void __attribute__((noreturn)) vcpu_activate_vmm(void); +void __attribute__((noreturn)) vcpu_deactivate_vmm(void); + +void vcpu_handle_exit(struct per_cpu *cpu_data); + +void vcpu_park(void); + +void vcpu_nmi_handler(void); + +void vcpu_tlb_flush(void); + +/* + * vcpu_map_inst() and vcpu_get_inst_bytes() contract: + * + * On input, *size gives the number of bytes to get. + * On output, *size is the number of bytes available. + * + * If the function fails (returns NULL), *size is undefined. + */ + +const u8 *vcpu_map_inst(const struct guest_paging_structures *pg_structs, + unsigned long pc, unsigned int *size); + +const u8 *vcpu_get_inst_bytes(const struct guest_paging_structures *pg_structs, + unsigned long pc, unsigned int *size); + +void vcpu_skip_emulated_instruction(unsigned int inst_len); + +unsigned int vcpu_vendor_get_io_bitmap_pages(void); + +#define VCPU_CS_DPL_MASK BIT_MASK(6, 5) +#define VCPU_CS_L (1 << 13) +#define VCPU_CS_DB (1 << 14) + +u64 vcpu_vendor_get_efer(void); +u64 vcpu_vendor_get_rflags(void); +u64 vcpu_vendor_get_rip(void); +u16 vcpu_vendor_get_cs_attr(void); + +void vcpu_vendor_get_io_intercept(struct vcpu_io_intercept *io); +void vcpu_vendor_get_mmio_intercept(struct vcpu_mmio_intercept *mmio); + +unsigned long vcpu_vendor_get_guest_cr4(void); + +void vcpu_get_guest_paging_structs(struct guest_paging_structures *pg_structs); +pt_entry_t vcpu_pae_get_pdpte(page_table_t page_table, unsigned long virt); + +void vcpu_vendor_set_guest_pat(unsigned long val); + +void vcpu_handle_hypercall(void); + +bool vcpu_handle_io_access(void); +bool vcpu_handle_mmio_access(void); + +bool vcpu_handle_msr_read(void); +bool vcpu_handle_msr_write(void); + +void vcpu_handle_cpuid(void); + +void vcpu_reset(unsigned int sipi_vector); +void vcpu_vendor_reset(unsigned int sipi_vector); + +#endif diff --git a/hypervisor/arch/x86/include/asm/vmx.h b/hypervisor/arch/x86/include/asm/vmx.h new file mode 100644 index 0000000000000000000000000000000000000000..5b0c0653ef4de04c0c96ba0b28cdbbf2eb86ecd1 --- /dev/null +++ b/hypervisor/arch/x86/include/asm/vmx.h @@ -0,0 +1,333 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * File is based on linux/arch/x86/include/asm/vmx.h: + * + * Copyright (c) 2004, Intel Corporation. + * Copyright (c) 2006 Qumranet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _JAILHOUSE_ASM_VMX_H +#define _JAILHOUSE_ASM_VMX_H + +#include + +struct per_cpu; + +/* VMCS Encodings */ +enum vmcs_field { + VIRTUAL_PROCESSOR_ID = 0x00000000, + GUEST_ES_SELECTOR = 0x00000800, + GUEST_CS_SELECTOR = 0x00000802, + GUEST_SS_SELECTOR = 0x00000804, + GUEST_DS_SELECTOR = 0x00000806, + GUEST_FS_SELECTOR = 0x00000808, + GUEST_GS_SELECTOR = 0x0000080a, + GUEST_LDTR_SELECTOR = 0x0000080c, + GUEST_TR_SELECTOR = 0x0000080e, + HOST_ES_SELECTOR = 0x00000c00, + HOST_CS_SELECTOR = 0x00000c02, + HOST_SS_SELECTOR = 0x00000c04, + HOST_DS_SELECTOR = 0x00000c06, + HOST_FS_SELECTOR = 0x00000c08, + HOST_GS_SELECTOR = 0x00000c0a, + HOST_TR_SELECTOR = 0x00000c0c, + IO_BITMAP_A = 0x00002000, + IO_BITMAP_A_HIGH = 0x00002001, + IO_BITMAP_B = 0x00002002, + IO_BITMAP_B_HIGH = 0x00002003, + MSR_BITMAP = 0x00002004, + MSR_BITMAP_HIGH = 0x00002005, + VM_EXIT_MSR_STORE_ADDR = 0x00002006, + VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, + VM_EXIT_MSR_LOAD_ADDR = 0x00002008, + VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, + VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, + VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, + TSC_OFFSET = 0x00002010, + TSC_OFFSET_HIGH = 0x00002011, + VIRTUAL_APIC_PAGE_ADDR = 0x00002012, + VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, + APIC_ACCESS_ADDR = 0x00002014, + APIC_ACCESS_ADDR_HIGH = 0x00002015, + EPT_POINTER = 0x0000201a, + EPT_POINTER_HIGH = 0x0000201b, + GUEST_PHYSICAL_ADDRESS = 0x00002400, + GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, + VMCS_LINK_POINTER = 0x00002800, + VMCS_LINK_POINTER_HIGH = 0x00002801, + GUEST_IA32_DEBUGCTL = 0x00002802, + GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, + GUEST_IA32_PAT = 0x00002804, + GUEST_IA32_PAT_HIGH = 0x00002805, + GUEST_IA32_EFER = 0x00002806, + GUEST_IA32_EFER_HIGH = 0x00002807, + GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, + GUEST_IA32_PERF_GLOBAL_CTRL_HIGH= 0x00002809, + GUEST_PDPTR0 = 0x0000280a, + GUEST_PDPTR0_HIGH = 0x0000280b, + GUEST_PDPTR1 = 0x0000280c, + GUEST_PDPTR1_HIGH = 0x0000280d, + GUEST_PDPTR2 = 0x0000280e, + GUEST_PDPTR2_HIGH = 0x0000280f, + GUEST_PDPTR3 = 0x00002810, + GUEST_PDPTR3_HIGH = 0x00002811, + HOST_IA32_PAT = 0x00002c00, + HOST_IA32_PAT_HIGH = 0x00002c01, + HOST_IA32_EFER = 0x00002c02, + HOST_IA32_EFER_HIGH = 0x00002c03, + HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, + HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05, + PIN_BASED_VM_EXEC_CONTROL = 0x00004000, + CPU_BASED_VM_EXEC_CONTROL = 0x00004002, + EXCEPTION_BITMAP = 0x00004004, + PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, + PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, + CR3_TARGET_COUNT = 0x0000400a, + VM_EXIT_CONTROLS = 0x0000400c, + VM_EXIT_MSR_STORE_COUNT = 0x0000400e, + VM_EXIT_MSR_LOAD_COUNT = 0x00004010, + VM_ENTRY_CONTROLS = 0x00004012, + VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, + VM_ENTRY_INTR_INFO_FIELD = 0x00004016, + VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, + VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, + TPR_THRESHOLD = 0x0000401c, + SECONDARY_VM_EXEC_CONTROL = 0x0000401e, + PLE_GAP = 0x00004020, + PLE_WINDOW = 0x00004022, + VM_INSTRUCTION_ERROR = 0x00004400, + VM_EXIT_REASON = 0x00004402, + VM_EXIT_INTR_INFO = 0x00004404, + VM_EXIT_INTR_ERROR_CODE = 0x00004406, + IDT_VECTORING_INFO_FIELD = 0x00004408, + IDT_VECTORING_ERROR_CODE = 0x0000440a, + VM_EXIT_INSTRUCTION_LEN = 0x0000440c, + VMX_INSTRUCTION_INFO = 0x0000440e, + GUEST_ES_LIMIT = 0x00004800, + GUEST_CS_LIMIT = 0x00004802, + GUEST_SS_LIMIT = 0x00004804, + GUEST_DS_LIMIT = 0x00004806, + GUEST_FS_LIMIT = 0x00004808, + GUEST_GS_LIMIT = 0x0000480a, + GUEST_LDTR_LIMIT = 0x0000480c, + GUEST_TR_LIMIT = 0x0000480e, + GUEST_GDTR_LIMIT = 0x00004810, + GUEST_IDTR_LIMIT = 0x00004812, + GUEST_ES_AR_BYTES = 0x00004814, + GUEST_CS_AR_BYTES = 0x00004816, + GUEST_SS_AR_BYTES = 0x00004818, + GUEST_DS_AR_BYTES = 0x0000481a, + GUEST_FS_AR_BYTES = 0x0000481c, + GUEST_GS_AR_BYTES = 0x0000481e, + GUEST_LDTR_AR_BYTES = 0x00004820, + GUEST_TR_AR_BYTES = 0x00004822, + GUEST_INTERRUPTIBILITY_INFO = 0x00004824, + GUEST_ACTIVITY_STATE = 0x00004826, + GUEST_SYSENTER_CS = 0x0000482A, + VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, + HOST_IA32_SYSENTER_CS = 0x00004c00, + CR0_GUEST_HOST_MASK = 0x00006000, + CR4_GUEST_HOST_MASK = 0x00006002, + CR0_READ_SHADOW = 0x00006004, + CR4_READ_SHADOW = 0x00006006, + CR3_TARGET_VALUE0 = 0x00006008, + CR3_TARGET_VALUE1 = 0x0000600a, + CR3_TARGET_VALUE2 = 0x0000600c, + CR3_TARGET_VALUE3 = 0x0000600e, + EXIT_QUALIFICATION = 0x00006400, + GUEST_LINEAR_ADDRESS = 0x0000640a, + GUEST_CR0 = 0x00006800, + GUEST_CR3 = 0x00006802, + GUEST_CR4 = 0x00006804, + GUEST_ES_BASE = 0x00006806, + GUEST_CS_BASE = 0x00006808, + GUEST_SS_BASE = 0x0000680a, + GUEST_DS_BASE = 0x0000680c, + GUEST_FS_BASE = 0x0000680e, + GUEST_GS_BASE = 0x00006810, + GUEST_LDTR_BASE = 0x00006812, + GUEST_TR_BASE = 0x00006814, + GUEST_GDTR_BASE = 0x00006816, + GUEST_IDTR_BASE = 0x00006818, + GUEST_DR7 = 0x0000681a, + GUEST_RSP = 0x0000681c, + GUEST_RIP = 0x0000681e, + GUEST_RFLAGS = 0x00006820, + GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, + GUEST_SYSENTER_ESP = 0x00006824, + GUEST_SYSENTER_EIP = 0x00006826, + HOST_CR0 = 0x00006c00, + HOST_CR3 = 0x00006c02, + HOST_CR4 = 0x00006c04, + HOST_FS_BASE = 0x00006c06, + HOST_GS_BASE = 0x00006c08, + HOST_TR_BASE = 0x00006c0a, + HOST_GDTR_BASE = 0x00006c0c, + HOST_IDTR_BASE = 0x00006c0e, + HOST_IA32_SYSENTER_ESP = 0x00006c10, + HOST_IA32_SYSENTER_EIP = 0x00006c12, + HOST_RSP = 0x00006c14, + HOST_RIP = 0x00006c16, +}; + +struct vmcs { + u32 revision_id:31; + u32 shadow_indicator:1; + u32 abort_indicator; + u64 data[(PAGE_SIZE - 4 - 4) / 8]; +} __attribute__((packed)); + +enum vmx_state { VMXOFF = 0, VMXON, VMCS_READY }; + +#define GUEST_SEG_LIMIT (GUEST_ES_LIMIT - GUEST_ES_SELECTOR) +#define GUEST_SEG_AR_BYTES (GUEST_ES_AR_BYTES - GUEST_ES_SELECTOR) +#define GUEST_SEG_BASE (GUEST_ES_BASE - GUEST_ES_SELECTOR) + +#define GUEST_ACTIVITY_ACTIVE 0 +#define GUEST_ACTIVITY_HLT 1 + +#define VMX_MSR_BMP_0000_READ 0 +#define VMX_MSR_BMP_C000_READ 1 +#define VMX_MSR_BMP_0000_WRITE 2 +#define VMX_MSR_BMP_C000_WRITE 3 + +#define PIN_BASED_NMI_EXITING (1UL << 3) +#define PIN_BASED_VMX_PREEMPTION_TIMER (1UL << 6) + +#define CPU_BASED_CR3_LOAD_EXITING (1UL << 15) +#define CPU_BASED_CR3_STORE_EXITING (1UL << 16) +#define CPU_BASED_USE_IO_BITMAPS (1UL << 25) +#define CPU_BASED_USE_MSR_BITMAPS (1UL << 28) +#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS (1UL << 31) + +#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES (1UL << 0) +#define SECONDARY_EXEC_ENABLE_EPT (1UL << 1) +#define SECONDARY_EXEC_RDTSCP (1UL << 3) +#define SECONDARY_EXEC_UNRESTRICTED_GUEST (1UL << 7) +#define SECONDARY_EXEC_INVPCID (1UL << 12) +#define SECONDARY_EXEC_XSAVES (1UL << 20) +#define SECONDARY_EXEC_USR_WAIT_PAUSE (1UL << 26) + +#define VM_EXIT_HOST_ADDR_SPACE_SIZE (1UL << 9) +#define VM_EXIT_SAVE_IA32_PAT (1UL << 18) +#define VM_EXIT_LOAD_IA32_PAT (1UL << 19) +#define VM_EXIT_SAVE_IA32_EFER (1UL << 20) +#define VM_EXIT_LOAD_IA32_EFER (1UL << 21) + +#define VM_ENTRY_IA32E_MODE (1UL << 9) +#define VM_ENTRY_LOAD_IA32_PAT (1UL << 14) +#define VM_ENTRY_LOAD_IA32_EFER (1UL << 15) + +#define VMX_MISC_ACTIVITY_HLT (1UL << 6) + +#define INTR_INFO_INTR_TYPE_MASK BIT_MASK(10, 8) +#define INTR_INFO_UNBLOCK_NMI (1UL << 12) + +#define INTR_TYPE_NMI_INTR (2UL << 8) + +#define INTR_TO_VECTORING_INFO_MASK ((1UL << 31) | BIT_MASK(11, 0)) + +#define EXIT_REASONS_FAILED_VMENTRY (1UL << 31) + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 +#define EXIT_REASON_INIT_SIGNAL 3 +#define EXIT_REASON_SIPI 4 +#define EXIT_REASON_IO_SMI 5 +#define EXIT_REASON_OTHER_SMI 6 +#define EXIT_REASON_PENDING_INTERRUPT 7 +#define EXIT_REASON_NMI_WINDOW 8 +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVD 13 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMXOFF 26 +#define EXIT_REASON_VMXON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_INVALID_STATE 33 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_MONITOR_INSTRUCTION 39 +#define EXIT_REASON_PAUSE_INSTRUCTION 40 +#define EXIT_REASON_MCE_DURING_VMENTRY 41 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_EPT_VIOLATION 48 +#define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_INVEPT 50 +#define EXIT_REASON_PREEMPTION_TIMER 52 +#define EXIT_REASON_WBINVD 54 +#define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_INVPCID 58 + +#define EPT_PAGE_DIR_LEVELS 4 + +#define EPT_FLAG_READ 0x001 +#define EPT_FLAG_WRITE 0x002 +#define EPT_FLAG_EXECUTE 0x004 +#define EPT_FLAG_WB_TYPE 0x030 + +#define EPT_TYPE_UNCACHEABLE 0 +#define EPT_TYPE_WRITEBACK 6 +#define EPT_PAGE_WALK_LEN ((4-1) << 3) + +#define EPT_PAGE_WALK_4 (1UL << 6) +#define EPTP_WB (1UL << 14) +#define EPT_2M_PAGES (1UL << 16) +#define EPT_1G_PAGES (1UL << 17) +#define EPT_INVEPT (1UL << 20) +#define EPT_INVEPT_SINGLE (1UL << 25) +#define EPT_INVEPT_GLOBAL (1UL << 26) +#define EPT_MANDATORY_FEATURES (EPT_PAGE_WALK_4 | EPTP_WB | \ + EPT_INVEPT) + +#define VMX_INVEPT_SINGLE 1 +#define VMX_INVEPT_GLOBAL 2 + +#define APIC_ACCESS_OFFSET_MASK 0x00000fff +#define APIC_ACCESS_TYPE_MASK 0x0000f000 +#define APIC_ACCESS_TYPE_LINEAR_READ 0x00000000 +#define APIC_ACCESS_TYPE_LINEAR_WRITE 0x00001000 + +void vmx_entry_failure(void); + +void vmx_vmexit(void); + +#endif /* !_JAILHOUSE_ASM_VMX_H */ diff --git a/hypervisor/arch/x86/ioapic.c b/hypervisor/arch/x86/ioapic.c new file mode 100644 index 0000000000000000000000000000000000000000..65ac00f2a6124f6753589418bcfd443ff85f9023 --- /dev/null +++ b/hypervisor/arch/x86/ioapic.c @@ -0,0 +1,492 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define IOAPIC_MAX_CHIPS (PAGE_SIZE / sizeof(struct cell_ioapic)) + +#define IOAPIC_REG_INDEX 0x00 +#define IOAPIC_REG_DATA 0x10 +#define IOAPIC_REG_EOI 0x40 +#define IOAPIC_VER 0x01 +# define IOPAPIC_VER_MRE(ver) (((ver) & BIT_MASK(23, 16)) >> 16) +#define IOAPIC_REDIR_TBL_START 0x10 +# define IOAPIC_REDIR_MASK (1 << 16) + +enum ioapic_handover {PINS_ACTIVE, PINS_MASKED}; + +#define for_each_phys_ioapic(ioapic, counter) \ + for ((ioapic) = &phys_ioapics[0], (counter) = 0; \ + (counter) < num_phys_ioapics; \ + (ioapic)++, (counter)++) + +#define for_each_cell_ioapic(ioapic, cell, counter) \ + for ((ioapic) = (cell)->arch.ioapics, (counter) = 0; \ + (counter) < (cell)->arch.num_ioapics; \ + (ioapic)++, (counter)++) + +static struct phys_ioapic phys_ioapics[IOAPIC_MAX_CHIPS]; +static unsigned int num_phys_ioapics; + +static unsigned int ioapic_mmio_count_regions(struct cell *cell) +{ + return cell->config->num_irqchips; +} + +static u32 ioapic_reg_read(struct phys_ioapic *ioapic, unsigned int reg) +{ + u32 value; + + spin_lock(&ioapic->lock); + + mmio_write32(ioapic->reg_base + IOAPIC_REG_INDEX, reg); + value = mmio_read32(ioapic->reg_base + IOAPIC_REG_DATA); + + spin_unlock(&ioapic->lock); + + return value; +} + +static void ioapic_reg_write(struct phys_ioapic *ioapic, unsigned int reg, + u32 value) +{ + spin_lock(&ioapic->lock); + + mmio_write32(ioapic->reg_base + IOAPIC_REG_INDEX, reg); + mmio_write32(ioapic->reg_base + IOAPIC_REG_DATA, value); + + spin_unlock(&ioapic->lock); +} + +static struct apic_irq_message +ioapic_translate_redir_entry(struct cell_ioapic *ioapic, unsigned int pin, + union ioapic_redir_entry entry) +{ + struct apic_irq_message irq_msg = { .valid = 0 }; + unsigned int idx, ioapic_id; + + if (iommu_cell_emulates_ir(ioapic->cell)) { + if (!entry.remap.remapped) + return irq_msg; + + idx = entry.remap.int_index | (entry.remap.int_index15 << 15); + ioapic_id = ioapic->info->id; + + return iommu_get_remapped_root_int(ioapic_id >> 16, + (u16)ioapic_id, pin, idx); + } + + irq_msg.vector = entry.native.vector; + irq_msg.delivery_mode = entry.native.delivery_mode; + irq_msg.level_triggered = entry.native.level_triggered; + irq_msg.dest_logical = entry.native.dest_logical; + /* allow dest_logical under VT-d by enabling redirection */ + irq_msg.redir_hint = 1; + irq_msg.valid = 1; + irq_msg.destination = entry.native.destination; + + return irq_msg; +} + +static int ioapic_virt_redir_write(struct cell_ioapic *ioapic, + unsigned int reg, u32 value) +{ + unsigned int pin = (reg - IOAPIC_REDIR_TBL_START) / 2; + struct phys_ioapic *phys_ioapic = ioapic->phys_ioapic; + struct apic_irq_message irq_msg; + union ioapic_redir_entry entry; + int result = 0xffff; + + entry = phys_ioapic->shadow_redir_table[pin]; + entry.raw[reg & 1] = value; + phys_ioapic->shadow_redir_table[pin] = entry; + + /* + * Do not map the interrupt while masked. It may contain invalid state. + * Rather write the invalid index 0xffff. That will not be used anyway + * while the mask is set. + */ + if (!entry.native.mask) { + irq_msg = ioapic_translate_redir_entry(ioapic, pin, entry); + + result = iommu_map_interrupt(ioapic->cell, + (u16)ioapic->info->id, pin, + irq_msg); + // HACK for QEMU + if (result == -ENOSYS) { + /* see regular update below, lazy version */ + ioapic_reg_write(phys_ioapic, reg | 1, entry.raw[1]); + ioapic_reg_write(phys_ioapic, reg, entry.raw[reg & 1]); + return 0; + } + if (result < 0) + return result; + } + + /* + * Write all 64 bits on updates of the lower 32 bits when unmasked to + * ensure the consistency of an entry. + * + * The index information in the higher bits does not change when the + * guest programs an unmasked entry, but they need to be initialized + * when taking their ownership (always out of masked state, see + * ioapic_prepare_handover). + */ + if ((reg & 1) == 0) { + entry.remap.zero = 0; + entry.remap.int_index15 = result >> 15; + entry.remap.remapped = 1; + entry.remap.int_index = result; + + if (!entry.native.mask) + ioapic_reg_write(phys_ioapic, reg | 1, entry.raw[1]); + ioapic_reg_write(phys_ioapic, reg, entry.raw[0]); + } + + return 0; +} + +static void ioapic_mask_cell_pins(struct cell_ioapic *ioapic, + enum ioapic_handover handover) +{ + struct phys_ioapic *phys_ioapic = ioapic->phys_ioapic; + unsigned int pin, reg; + + for (pin = 0; pin < phys_ioapic->pins; pin++) { + if (!test_bit(pin, (unsigned long *)ioapic->pin_bitmap)) + continue; + + if (phys_ioapic->shadow_redir_table[pin].native.mask) + continue; + + reg = IOAPIC_REDIR_TBL_START + pin * 2; + ioapic_reg_write(phys_ioapic, reg, IOAPIC_REDIR_MASK); + + if (handover == PINS_MASKED) + phys_ioapic->shadow_redir_table[pin].native.mask = 1; + } +} + +void ioapic_prepare_handover(void) +{ + struct cell_ioapic *ioapic; + unsigned int n; + + for_each_cell_ioapic(ioapic, &root_cell, n) + ioapic_mask_cell_pins(ioapic, PINS_ACTIVE); +} + +int ioapic_get_or_add_phys(const struct jailhouse_irqchip *irqchip, + struct phys_ioapic **phys_ioapic_ptr) +{ + struct phys_ioapic *phys_ioapic; + unsigned int n, index; + int err; + + for_each_phys_ioapic(phys_ioapic, n) + if (phys_ioapic->base_addr == irqchip->address) + goto done; + + /* + * phys_ioapic now points to the first free slot in phys_ioapics, + * provided there is one. + */ + if (num_phys_ioapics == IOAPIC_MAX_CHIPS) + return trace_error(-ERANGE); + + phys_ioapic->reg_base = paging_map_device(irqchip->address, PAGE_SIZE); + if (!phys_ioapic->reg_base) + return -ENOMEM; + + phys_ioapic->pins = + IOPAPIC_VER_MRE(ioapic_reg_read(phys_ioapic, IOAPIC_VER)) + 1; + if (phys_ioapic->pins > IOAPIC_MAX_PINS) { + err = trace_error(-EIO); + goto error_paging_destroy; + } + + phys_ioapic->base_addr = irqchip->address; + num_phys_ioapics++; + + for (index = 0; index < phys_ioapic->pins * 2; index++) + phys_ioapic->shadow_redir_table[index / 2].raw[index % 2] = + ioapic_reg_read(phys_ioapic, + IOAPIC_REDIR_TBL_START + index); + +done: + *phys_ioapic_ptr = phys_ioapic; + return 0; + +error_paging_destroy: + paging_unmap_device(irqchip->address, phys_ioapic->reg_base, PAGE_SIZE); + return err; +} + +static struct cell_ioapic *ioapic_find_by_address(struct cell *cell, + unsigned long address) +{ + struct cell_ioapic *ioapic; + unsigned int n; + + for_each_cell_ioapic(ioapic, cell, n) + if (address == ioapic->info->address) + return ioapic; + return NULL; +} + +static enum mmio_result ioapic_access_handler(void *arg, + struct mmio_access *mmio) +{ + union ioapic_redir_entry *shadow_table; + struct cell_ioapic *ioapic = arg; + u32 index, entry; + + switch (mmio->address) { + case IOAPIC_REG_INDEX: + if (mmio->is_write) + ioapic->index_reg_val = mmio->value; + else + mmio->value = ioapic->index_reg_val; + return MMIO_HANDLED; + case IOAPIC_REG_DATA: + index = ioapic->index_reg_val; + + if (index < IOAPIC_REDIR_TBL_START) { + if (mmio->is_write) + goto invalid_access; + mmio->value = ioapic_reg_read(ioapic->phys_ioapic, + index); + return MMIO_HANDLED; + } + + if (index >= (IOAPIC_REDIR_TBL_START + + ioapic->phys_ioapic->pins * 2)) + goto invalid_access; + + entry = (index - IOAPIC_REDIR_TBL_START) / 2; + if (!test_bit(entry, (unsigned long *)ioapic->pin_bitmap)) { + /* ignore access */ + mmio->value = 0; + return MMIO_HANDLED; + } + + if (mmio->is_write) { + if (ioapic_virt_redir_write(ioapic, index, + mmio->value) < 0) + goto invalid_access; + } else { + index -= IOAPIC_REDIR_TBL_START; + shadow_table = ioapic->phys_ioapic->shadow_redir_table; + mmio->value = shadow_table[index / 2].raw[index % 2]; + } + return MMIO_HANDLED; + case IOAPIC_REG_EOI: + if (!mmio->is_write || (((u64 *)ioapic->pin_bitmap)[0] == 0 && + ((u64 *)ioapic->pin_bitmap)[1] == 0)) + goto invalid_access; + /* + * Just write the EOI if the cell has any assigned pin. It + * would be complex to virtualize it in a way that cells are + * unable to ack vectors of other cells. It is therefore not + * recommended to use level-triggered IOAPIC interrupts in + * non-root cells. + */ + mmio_write32(ioapic->phys_ioapic->reg_base + IOAPIC_REG_EOI, + mmio->value); + return MMIO_HANDLED; + } + +invalid_access: + panic_printk("FATAL: Invalid IOAPIC %s, reg: %lx, index: %x\n", + mmio->is_write ? "write" : "read", mmio->address, + ioapic->index_reg_val); + return MMIO_ERROR; +} + +static void ioapic_cell_exit(struct cell *cell); + +static int ioapic_cell_init(struct cell *cell) +{ + const struct jailhouse_irqchip *irqchip = + jailhouse_cell_irqchips(cell->config); + struct cell_ioapic *ioapic, *root_ioapic; + struct phys_ioapic *phys_ioapic; + unsigned int n, pos; + int err; + + if (cell->config->num_irqchips == 0) + return 0; + if (cell->config->num_irqchips > IOAPIC_MAX_CHIPS) + return trace_error(-ERANGE); + + cell->arch.ioapics = page_alloc(&mem_pool, 1); + if (!cell->arch.ioapics) + return -ENOMEM; + + for (n = 0; n < cell->config->num_irqchips; n++, irqchip++) { + err = ioapic_get_or_add_phys(irqchip, &phys_ioapic); + if (err) { + ioapic_cell_exit(cell); + return err; + } + + if (irqchip->pin_base != 0) + return trace_error(-EINVAL); + + ioapic = &cell->arch.ioapics[n]; + ioapic->info = irqchip; + ioapic->cell = cell; + ioapic->phys_ioapic = phys_ioapic; + memcpy(ioapic->pin_bitmap, irqchip->pin_bitmap, + sizeof(ioapic->pin_bitmap)); + cell->arch.num_ioapics++; + + mmio_region_register(cell, irqchip->address, PAGE_SIZE, + ioapic_access_handler, ioapic); + + if (cell == &root_cell) + continue; + + root_ioapic = ioapic_find_by_address(&root_cell, + irqchip->address); + if (!root_ioapic) + continue; + + for (pos = 0; pos < ARRAY_SIZE(irqchip->pin_bitmap); pos++) + root_ioapic->pin_bitmap[pos] &= + ~irqchip->pin_bitmap[pos]; + } + + return 0; +} + +void ioapic_cell_reset(struct cell *cell) +{ + struct cell_ioapic *ioapic; + unsigned int n; + + for_each_cell_ioapic(ioapic, cell, n) + ioapic_mask_cell_pins(ioapic, PINS_MASKED); +} + +static void ioapic_cell_exit(struct cell *cell) +{ + struct cell_ioapic *ioapic, *root_ioapic; + const struct jailhouse_irqchip *irqchip; + unsigned int n, pos; + + for_each_cell_ioapic(ioapic, cell, n) { + ioapic_mask_cell_pins(ioapic, PINS_MASKED); + + irqchip = ioapic->info; + root_ioapic = ioapic_find_by_address(&root_cell, + irqchip->address); + if (!root_ioapic) + continue; + + for (pos = 0; pos < ARRAY_SIZE(irqchip->pin_bitmap); pos++) + root_ioapic->pin_bitmap[pos] |= + irqchip->pin_bitmap[pos] & + root_ioapic->info->pin_bitmap[pos]; + } + + page_free(&mem_pool, cell->arch.ioapics, 1); +} + +void ioapic_config_commit(struct cell *cell_added_removed) +{ + struct apic_irq_message irq_msg; + union ioapic_redir_entry entry; + struct cell_ioapic *ioapic; + unsigned int pin, reg, n; + + if (!cell_added_removed) + return; + + for_each_cell_ioapic(ioapic, &root_cell, n) + for (pin = 0; pin < ioapic->phys_ioapic->pins; pin++) { + if (!test_bit(pin, (unsigned long *)ioapic->pin_bitmap)) + continue; + + entry = ioapic->phys_ioapic->shadow_redir_table[pin]; + reg = IOAPIC_REDIR_TBL_START + pin * 2; + + /* + * Writing the lower half will unmask the pin and + * update the upper one as well. + */ + if (ioapic_virt_redir_write(ioapic, reg, + entry.raw[0]) < 0) { + panic_printk("FATAL: Unsupported IOAPIC " + "state, pin %d\n", pin); + panic_stop(); + } + + if (cell_added_removed != &root_cell || + entry.native.level_triggered) + continue; + + /* + * Inject edge-triggered interrupts to avoid losing + * events while suppressed (masked). Linux can handle + * rare spurious interrupts. + */ + irq_msg = ioapic_translate_redir_entry(ioapic, pin, + entry); + if (irq_msg.valid) + apic_send_irq(irq_msg); + } +} + +static int ioapic_init(void) +{ + int err; + + err = ioapic_cell_init(&root_cell); + if (err) + return err; + + ioapic_prepare_handover(); + + return 0; +} + +static void ioapic_shutdown(void) +{ + union ioapic_redir_entry *shadow_table; + struct phys_ioapic *phys_ioapic; + unsigned int n; + int index; + + for_each_phys_ioapic(phys_ioapic, n) { + shadow_table = phys_ioapic->shadow_redir_table; + + /* write in reverse order to preserve the mask as long as + * needed */ + for (index = phys_ioapic->pins * 2 - 1; index >= 0; index--) + ioapic_reg_write(phys_ioapic, + IOAPIC_REDIR_TBL_START + index, + shadow_table[index / 2].raw[index % 2]); + } +} + +DEFINE_UNIT(ioapic, "IOAPIC"); diff --git a/hypervisor/arch/x86/iommu.c b/hypervisor/arch/x86/iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..1ecf857a94d0cff0b201569061bf43bc4cf2f32f --- /dev/null +++ b/hypervisor/arch/x86/iommu.c @@ -0,0 +1,40 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +unsigned int fault_reporting_cpu_id; + +unsigned int iommu_count_units(void) +{ + unsigned int units = 0; + + while (units < JAILHOUSE_MAX_IOMMU_UNITS && + system_config->platform_info.iommu_units[units].base) + units++; + return units; +} + +struct public_per_cpu *iommu_select_fault_reporting_cpu(void) +{ + /* + * The selection process assumes that at least one bit is set somewhere + * because we don't support configurations where Linux is left with no + * CPUs. + * Save this value globally to avoid multiple reports of the same + * case from different CPUs. + */ + fault_reporting_cpu_id = first_cpu(root_cell.cpu_set); + + return public_per_cpu(fault_reporting_cpu_id); +} diff --git a/hypervisor/arch/x86/ivshmem.c b/hypervisor/arch/x86/ivshmem.c new file mode 100644 index 0000000000000000000000000000000000000000..62c1808e5dd8bde8da01e357b2626fde905d36be --- /dev/null +++ b/hypervisor/arch/x86/ivshmem.c @@ -0,0 +1,63 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2019 + * + * Author: + * Henning Schild + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +void arch_ivshmem_trigger_interrupt(struct ivshmem_endpoint *ive, + unsigned int vector) +{ + if (ive->irq_cache.msg[vector].valid) + apic_send_irq(ive->irq_cache.msg[vector]); +} + +int arch_ivshmem_update_msix(struct ivshmem_endpoint *ive, unsigned int vector, + bool enabled) +{ + struct apic_irq_message irq_msg = { .valid = 0 }; + struct pci_device *device = ive->device; + union x86_msi_vector msi; + + if (enabled) { + msi.raw.address = device->msix_vectors[vector].address; + msi.raw.data = device->msix_vectors[vector].data; + + irq_msg = x86_pci_translate_msi(device, vector, 0, msi); + + if (irq_msg.valid && + !apic_filter_irq_dest(device->cell, &irq_msg)) { + panic_printk("FATAL: ivshmem MSI-X target outside of " + "cell \"%s\" device %02x:%02x.%x\n", + device->cell->config->name, + PCI_BDF_PARAMS(device->info->bdf)); + return -EPERM; + } + } + + /* + * Lock used as barrier, ensuring all interrupts triggered after return + * use the new setting. + */ + spin_lock(&ive->irq_lock); + ive->irq_cache.msg[vector] = irq_msg; + spin_unlock(&ive->irq_lock); + + return 0; +} + +void arch_ivshmem_update_intx(struct ivshmem_endpoint *ive, bool enabled) +{ +} diff --git a/hypervisor/arch/x86/mmio.c b/hypervisor/arch/x86/mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..ef73317762c9812c1946597bed2414eb32f701e4 --- /dev/null +++ b/hypervisor/arch/x86/mmio.c @@ -0,0 +1,309 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2018 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +#define X86_MAX_INST_LEN 15 + +/* + * There are a few instructions that can have 8-byte immediate values + * on 64-bit mode, but they are not supported/expected here, so we are + * safe. + */ +#define IMMEDIATE_SIZE 4 + +union opcode { + u8 raw; + struct { /* REX */ + u8 b:1, x:1, r:1, w:1; + u8 code:4; + } __attribute__((packed)) rex; + struct { + u8 rm:3; + u8 reg:3; + u8 mod:2; + } __attribute__((packed)) modrm; + struct { + u8 base:3; + u8 index:3; + u8 ss:2; + } __attribute__((packed)) sib; +}; + +struct parse_context { + unsigned int remaining; + unsigned int count; + unsigned int size; + const u8 *inst; + bool has_immediate; + bool does_write; + bool has_rex_w; + bool has_rex_r; + bool has_addrsz_prefix; + bool has_opsz_prefix; + bool zero_extend; +}; + +static bool ctx_update(struct parse_context *ctx, u64 *pc, unsigned int advance, + const struct guest_paging_structures *pg) +{ + ctx->inst += advance; + ctx->count += advance; + if (ctx->size > advance) { + ctx->size -= advance; + } else { + ctx->size = ctx->remaining; + ctx->inst = vcpu_get_inst_bytes(pg, *pc, &ctx->size); + if (!ctx->inst) + return false; + ctx->remaining -= ctx->size; + *pc += ctx->size; + } + return true; +} + +static void parse_widths(struct parse_context *ctx, + struct mmio_instruction *inst, bool parse_addr_width) +{ + u16 cs_attr = vcpu_vendor_get_cs_attr(); + bool cs_db = !!(cs_attr & VCPU_CS_DB); + bool long_mode = + (vcpu_vendor_get_efer() & EFER_LMA) && (cs_attr & VCPU_CS_L); + + /* Op size prefix is ignored if rex.w = 1 */ + if (ctx->has_rex_w) { + inst->access_size = 8; + } else { + /* CS.d is ignored in long mode */ + if (long_mode) + inst->access_size = ctx->has_opsz_prefix ? 2 : 4; + else + inst->access_size = + (cs_db ^ ctx->has_opsz_prefix) ? 4 : 2; + } + + if (parse_addr_width) { + if (long_mode) + inst->inst_len += ctx->has_addrsz_prefix ? 4 : 8; + else + inst->inst_len += + (cs_db ^ ctx->has_addrsz_prefix) ? 4 : 2; + } +} + +struct mmio_instruction +x86_mmio_parse(const struct guest_paging_structures *pg_structs, bool is_write) +{ + struct parse_context ctx = { .remaining = X86_MAX_INST_LEN, + .count = 1 }; + union registers *guest_regs = &this_cpu_data()->guest_regs; + struct mmio_instruction inst = { 0 }; + u64 pc = vcpu_vendor_get_rip(); + unsigned int n, skip_len = 0; + union opcode op[4] = { }; + + if (!ctx_update(&ctx, &pc, 0, pg_structs)) + goto error_noinst; + +restart: + op[0].raw = *ctx.inst; + if (op[0].rex.code == X86_REX_CODE) { + if (op[0].rex.w) + ctx.has_rex_w = true; + if (op[0].rex.r) + ctx.has_rex_r = true; + if (op[0].rex.x) + goto error_unsupported; + + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + goto restart; + } + switch (op[0].raw) { + case X86_PREFIX_ADDR_SZ: + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + ctx.has_addrsz_prefix = true; + goto restart; + case X86_PREFIX_OP_SZ: + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + ctx.has_opsz_prefix = true; + goto restart; + case X86_OP_MOVZX_OPC1: + ctx.zero_extend = true; + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + op[1].raw = *ctx.inst; + if (op[1].raw == X86_OP_MOVZX_OPC2_B) + inst.access_size = 1; + else if (op[1].raw == X86_OP_MOVZX_OPC2_W) + inst.access_size = 2; + else + goto error_unsupported; + break; + case X86_OP_MOVB_TO_MEM: + inst.access_size = 1; + ctx.does_write = true; + break; + case X86_OP_MOV_TO_MEM: + parse_widths(&ctx, &inst, false); + ctx.does_write = true; + break; + case X86_OP_MOVB_FROM_MEM: + inst.access_size = 1; + break; + case X86_OP_MOV_FROM_MEM: + parse_widths(&ctx, &inst, false); + break; + case X86_OP_MOV_IMMEDIATE_TO_MEM: + parse_widths(&ctx, &inst, false); + ctx.has_immediate = true; + ctx.does_write = true; + break; + case X86_OP_MOV_MEM_TO_AX: + parse_widths(&ctx, &inst, true); + inst.in_reg_num = 15; + goto final; + case X86_OP_MOV_AX_TO_MEM: + parse_widths(&ctx, &inst, true); + inst.out_val = guest_regs->by_index[15]; + ctx.does_write = true; + goto final; + default: + goto error_unsupported; + } + + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + + op[2].raw = *ctx.inst; + + /* + * reg_preserve_mask defaults to 0, and only needs to be set in case of + * reads + */ + if (!ctx.does_write) { + /* + * MOVs on 32 or 64 bit destination registers need no + * adjustment of the reg_preserve_mask, all upper bits will + * always be cleared. + * + * In case of 16 or 8 bit registers, the instruction must only + * modify bits within that width. Therefore, reg_preserve_mask + * may be set to preserve upper bits. + * + * For regular instructions, this is the case if access_size < 4. + * + * For zero-extend instructions, this is the case if the + * operand size override prefix is set. + */ + if (!ctx.zero_extend && inst.access_size < 4) { + /* + * Restrict access to the width of the access_size, and + * preserve all other bits + */ + inst.reg_preserve_mask = ~BYTE_MASK(inst.access_size); + } else if (ctx.zero_extend && ctx.has_opsz_prefix) { + /* + * Always preserve bits 16-63. Potential zero-extend of + * bits 8-15 is ensured by access_size + */ + inst.reg_preserve_mask = ~BYTE_MASK(2); + } + } + + /* ensure that we are actually talking about mov imm, */ + if (op[0].raw == X86_OP_MOV_IMMEDIATE_TO_MEM && op[2].modrm.reg != 0) + goto error_unsupported; + + switch (op[2].modrm.mod) { + case 0: + if (op[2].modrm.rm == 4) { /* SIB */ + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + + op[3].raw = *ctx.inst; + if (op[3].sib.base == 5) + skip_len = 4; + } else if (op[2].modrm.rm == 5) { /* 32-bit displacement */ + skip_len = 4; + } + break; + case 1: + case 2: + skip_len = op[2].modrm.mod == 1 ? 1 : 4; + if (op[2].modrm.rm == 4) /* SIB */ + skip_len++; + break; + default: + goto error_unsupported; + } + + if (ctx.has_rex_r) + inst.in_reg_num = 7 - op[2].modrm.reg; + else if (op[2].modrm.reg == 4) + goto error_unsupported; + else + inst.in_reg_num = 15 - op[2].modrm.reg; + + if (ctx.has_immediate) { + /* walk any not yet retrieved SIB or displacement bytes */ + if (!ctx_update(&ctx, &pc, skip_len, pg_structs)) + goto error_noinst; + + /* retrieve immediate value */ + for (n = 0; n < IMMEDIATE_SIZE; n++) { + if (!ctx_update(&ctx, &pc, 1, pg_structs)) + goto error_noinst; + inst.out_val |= (unsigned long)*ctx.inst << (n * 8); + } + + /* sign-extend immediate if the target is 64-bit */ + if (ctx.has_rex_w) + inst.out_val = (s64)(s32)inst.out_val; + } else { + inst.inst_len += skip_len; + if (ctx.does_write) + inst.out_val = guest_regs->by_index[inst.in_reg_num]; + } + +final: + if (ctx.does_write != is_write) + goto error_inconsitent; + + inst.inst_len += ctx.count; + + return inst; + +error_noinst: + panic_printk("FATAL: unable to get MMIO instruction\n"); + goto error; + +error_unsupported: + panic_printk("FATAL: unsupported instruction " + "(0x%02x 0x%02x 0x%02x 0x%02x)\n", + op[0].raw, op[1].raw, op[2].raw, op[3].raw); + goto error; + +error_inconsitent: + panic_printk("FATAL: inconsistent access, expected %s instruction\n", + is_write ? "write" : "read"); +error: + inst.inst_len = 0; + return inst; +} diff --git a/hypervisor/arch/x86/paging.c b/hypervisor/arch/x86/paging.c new file mode 100644 index 0000000000000000000000000000000000000000..cb7ff929adc3a3fd52d5d74185c461434c85e1d8 --- /dev/null +++ b/hypervisor/arch/x86/paging.c @@ -0,0 +1,256 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define X86_FLAG_HUGEPAGE 0x80 + +static struct paging hv_paging[MAX_PAGE_TABLE_LEVELS]; + +static bool x86_64_entry_valid(pt_entry_t pte, unsigned long flags) +{ + return (*pte & flags) == flags; +} + +static unsigned long x86_64_get_flags(pt_entry_t pte) +{ + return *pte & (BIT_MASK(63, 52) | BIT_MASK(11, 8) | BIT_MASK(6, 0)); +} + +static void x86_64_set_next_pt(pt_entry_t pte, unsigned long next_pt) +{ + *pte = (next_pt & BIT_MASK(51, 12)) | PAGE_DEFAULT_FLAGS; +} + +static void x86_64_clear_entry(pt_entry_t pte) +{ + *pte = PAGE_NONPRESENT_FLAGS; +} + +static bool x86_64_page_table_empty(page_table_t page_table) +{ + pt_entry_t pte; + unsigned int n; + + for (n = 0, pte = page_table; n < PAGE_SIZE / sizeof(u64); n++, pte++) + if (x86_64_entry_valid(pte, PAGE_FLAG_PRESENT)) + return false; + return true; +} + +static pt_entry_t x86_64_get_entry_l4(page_table_t page_table, + unsigned long virt) +{ + return &page_table[(virt >> 39) & 0x1ff]; +} + +static pt_entry_t x86_64_get_entry_l3(page_table_t page_table, + unsigned long virt) +{ + return &page_table[(virt >> 30) & 0x1ff]; +} + +static pt_entry_t x86_64_get_entry_l2(page_table_t page_table, + unsigned long virt) +{ + return &page_table[(virt >> 21) & 0x1ff]; +} + +static pt_entry_t x86_64_get_entry_l1(page_table_t page_table, + unsigned long virt) +{ + return &page_table[(virt >> 12) & 0x1ff]; +} + +static void x86_64_set_terminal_l3(pt_entry_t pte, unsigned long phys, + unsigned long flags) +{ + *pte = (phys & BIT_MASK(51, 30)) | X86_FLAG_HUGEPAGE | flags; +} + +static void x86_64_set_terminal_l2(pt_entry_t pte, unsigned long phys, + unsigned long flags) +{ + *pte = (phys & BIT_MASK(51, 21)) | X86_FLAG_HUGEPAGE | flags; +} + +static void x86_64_set_terminal_l1(pt_entry_t pte, unsigned long phys, + unsigned long flags) +{ + *pte = (phys & BIT_MASK(51, 12)) | flags; +} + +static unsigned long x86_64_get_phys_l3(pt_entry_t pte, unsigned long virt) +{ + if (!(*pte & X86_FLAG_HUGEPAGE)) + return INVALID_PHYS_ADDR; + return (*pte & BIT_MASK(51, 30)) | (virt & BIT_MASK(29, 0)); +} + +static unsigned long x86_64_get_phys_l2(pt_entry_t pte, unsigned long virt) +{ + if (!(*pte & X86_FLAG_HUGEPAGE)) + return INVALID_PHYS_ADDR; + return (*pte & BIT_MASK(51, 21)) | (virt & BIT_MASK(20, 0)); +} + +static unsigned long x86_64_get_phys_l1(pt_entry_t pte, unsigned long virt) +{ + return (*pte & BIT_MASK(51, 12)) | (virt & BIT_MASK(11, 0)); +} + +static unsigned long x86_64_get_next_pt(pt_entry_t pte) +{ + return *pte & BIT_MASK(51, 12); +} + +#define X86_64_PAGING_COMMON \ + .entry_valid = x86_64_entry_valid, \ + .get_flags = x86_64_get_flags, \ + .set_next_pt = x86_64_set_next_pt, \ + .clear_entry = x86_64_clear_entry, \ + .page_table_empty = x86_64_page_table_empty + +const struct paging x86_64_paging[] = { + { + X86_64_PAGING_COMMON, + .get_entry = x86_64_get_entry_l4, + /* set_terminal not valid */ + .get_phys = paging_get_phys_invalid, + .get_next_pt = x86_64_get_next_pt, + }, + { + .page_size = 1024 * 1024 * 1024, + X86_64_PAGING_COMMON, + .get_entry = x86_64_get_entry_l3, + .set_terminal = x86_64_set_terminal_l3, + .get_phys = x86_64_get_phys_l3, + .get_next_pt = x86_64_get_next_pt, + }, + { + .page_size = 2 * 1024 * 1024, + X86_64_PAGING_COMMON, + .get_entry = x86_64_get_entry_l2, + .set_terminal = x86_64_set_terminal_l2, + .get_phys = x86_64_get_phys_l2, + .get_next_pt = x86_64_get_next_pt, + }, + { + .page_size = PAGE_SIZE, + X86_64_PAGING_COMMON, + .get_entry = x86_64_get_entry_l1, + .set_terminal = x86_64_set_terminal_l1, + .get_phys = x86_64_get_phys_l1, + /* get_next_pt not valid */ + }, +}; + +void arch_paging_init(void) +{ + memcpy(hv_paging, x86_64_paging, sizeof(x86_64_paging)); + if (!(cpuid_edx(0x80000001, 0) & X86_FEATURE_GBPAGES)) + hv_paging[1].page_size = 0; + + hv_paging_structs.root_paging = hv_paging; +} + +static bool i386_entry_valid(pt_entry_t pte, unsigned long flags) +{ + return (*(u32 *)pte & flags) == flags; +} + +static pt_entry_t i386_get_entry_l2(page_table_t page_table, + unsigned long virt) +{ + u32 *page_table32 = (u32 *)page_table; + + return (pt_entry_t)&page_table32[(virt >> 22) & 0x3ff]; +} + +static pt_entry_t i386_get_entry_l1(page_table_t page_table, + unsigned long virt) +{ + u32 *page_table32 = (u32 *)page_table; + + return (pt_entry_t)&page_table32[(virt >> 12) & 0x3ff]; +} + +static unsigned long i386_get_phys_l2(pt_entry_t pte, unsigned long virt) +{ + u32 pte32 = *(u32 *)pte; + + if (!(pte32 & X86_FLAG_HUGEPAGE)) + return INVALID_PHYS_ADDR; + return ((unsigned long)(pte32 & BIT_MASK(16, 13)) << (32 - 13)) | + (pte32 & BIT_MASK(31, 22)) | (virt & BIT_MASK(21, 0)); +} + +static unsigned long i386_get_phys_l1(pt_entry_t pte, unsigned long virt) +{ + return (*(u32 *)pte & BIT_MASK(31, 12)) | (virt & BIT_MASK(11, 0)); +} + +static unsigned long i386_get_next_pt(pt_entry_t pte) +{ + return *(u32 *)pte & BIT_MASK(31, 12); +} + +/* read-only, no page table construction supported */ +const struct paging i386_paging[] = { + { + .page_size = 4 * 1024 * 1024, + .entry_valid = i386_entry_valid, + .get_entry = i386_get_entry_l2, + .get_phys = i386_get_phys_l2, + .get_next_pt = i386_get_next_pt, + }, + { + .page_size = PAGE_SIZE, + .entry_valid = i386_entry_valid, + .get_entry = i386_get_entry_l1, + .get_phys = i386_get_phys_l1, + /* get_next_pt not valid */ + }, +}; + +/* Can be overridden in vendor-specific code if needed */ +pt_entry_t __attribute__((weak)) vcpu_pae_get_pdpte(page_table_t page_table, + unsigned long virt) +{ + return &page_table[(virt >> 30) & 0x3]; +} + +/* read-only, no page table construction supported */ +const struct paging pae_paging[] = { + { + .entry_valid = x86_64_entry_valid, + .get_entry = vcpu_pae_get_pdpte, + .get_phys = paging_get_phys_invalid, + .get_next_pt = x86_64_get_next_pt, + }, + { + .page_size = 2 * 1024 * 1024, + .entry_valid = x86_64_entry_valid, + .get_entry = x86_64_get_entry_l2, + .get_phys = x86_64_get_phys_l2, + .get_next_pt = x86_64_get_next_pt, + }, + { + .page_size = PAGE_SIZE, + .entry_valid = x86_64_entry_valid, + .get_entry = x86_64_get_entry_l1, + .get_phys = x86_64_get_phys_l1, + /* get_next_pt not valid */ + }, +}; diff --git a/hypervisor/arch/x86/pci.c b/hypervisor/arch/x86/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..fbb8ebd568056255bbbb324a957fd23cb2edc1cc --- /dev/null +++ b/hypervisor/arch/x86/pci.c @@ -0,0 +1,419 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Ivan Kolchin + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** Protects the root bridge's PIO interface to the PCI config space. */ +static spinlock_t pci_lock; + +u32 arch_pci_read_config(u16 bdf, u16 address, unsigned int size) +{ + u16 port = PCI_REG_DATA_PORT + (address & 0x3); + u32 value; + + spin_lock(&pci_lock); + + outl(PCI_ADDR_ENABLE | (bdf << PCI_ADDR_BDF_SHIFT) | + (address & PCI_ADDR_REGNUM_MASK), PCI_REG_ADDR_PORT); + if (size == 1) + value = inb(port); + else if (size == 2) + value = inw(port); + else + value = inl(port); + + spin_unlock(&pci_lock); + + return value; +} + +void arch_pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size) +{ + u16 port = PCI_REG_DATA_PORT + (address & 0x3); + + spin_lock(&pci_lock); + + outl(PCI_ADDR_ENABLE | (bdf << PCI_ADDR_BDF_SHIFT) | + (address & PCI_ADDR_REGNUM_MASK), PCI_REG_ADDR_PORT); + if (size == 1) + outb(value, port); + else if (size == 2) + outw(value, port); + else + outl(value, port); + + spin_unlock(&pci_lock); +} + +/** + * Set value of RAX in current CPU's guest register set. + * @param value Value to be written. + * @param size Access size (1, 2 or 4 bytes). + * + * @private + */ +static void set_guest_rax_reg(u32 value, u8 size) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + /* 32-bit access is special since it clears all the upper part of RAX. + * Any other types of access leave it intact. */ + u64 mask = (size == 4 ? BYTE_MASK(8) : BYTE_MASK(size)); + + guest_regs->rax = (guest_regs->rax & ~mask) | (value & mask); +} + +/** + * Get value of RAX from current CPU's guest register set. + * @param size Access size (1, 2 or 4 bytes). + * + * @return Register value. + * + * @private + */ +static u32 get_guest_rax_reg(u8 size) +{ + return this_cpu_data()->guest_regs.rax & BYTE_MASK(size); +} + +/** + * Handler for IN accesses to data port. + * @param device Structure describing PCI device. + * @param address Config space access address. + * @param size Access size (1, 2 or 4 bytes). + * + * @return 1 if handled successfully, -1 on access error. + * + * @private + */ +static int data_port_in_handler(struct pci_device *device, u16 address, + unsigned int size) +{ + u32 reg_data; + + if (pci_cfg_read_moderate(device, address, + size, ®_data) == PCI_ACCESS_PERFORM) + reg_data = arch_pci_read_config(device->info->bdf, address, + size); + + set_guest_rax_reg(reg_data, size); + + return 1; +} + +/** + * Handler for OUT accesses to data port. + * @param device Structure describing PCI device. + * @param address Config space access address. + * @param size Access size (1, 2 or 4 bytes). + * + * @return 1 if handled successfully, -1 on access error. + * + * @private + */ +static int data_port_out_handler(struct pci_device *device, u16 address, + unsigned int size) +{ + u32 reg_data = get_guest_rax_reg(size); + enum pci_access access; + + access = pci_cfg_write_moderate(device, address, size, reg_data); + if (access == PCI_ACCESS_REJECT) + return -1; + if (access == PCI_ACCESS_PERFORM) + arch_pci_write_config(device->info->bdf, address, reg_data, + size); + return 1; +} + +/** + * Handler for accesses to PCI config space. + * @param port I/O port number of this access. + * @param dir_in True for input, false for output. + * @param size Size of access in bytes (1, 2 or 4 bytes). + * + * @return 1 if handled successfully, 0 if unhandled, -1 on access error. + */ +int x86_pci_config_handler(u16 port, bool dir_in, unsigned int size) +{ + struct cell *cell = this_cell(); + struct pci_device *device; + u32 addr_port_val; + u16 bdf, address; + int result = 0; + + if (port == PCI_REG_ADDR_PORT) { + /* only 4-byte accesses are valid */ + if (size != 4) + goto invalid_access; + + if (dir_in) + set_guest_rax_reg(cell->arch.pci_addr_port_val, size); + else + cell->arch.pci_addr_port_val = get_guest_rax_reg(size); + result = 1; + } else if (port >= PCI_REG_DATA_PORT && + port < (PCI_REG_DATA_PORT + 4)) { + /* overflowing accesses are invalid */ + if (port + size > PCI_REG_DATA_PORT + 4) + goto invalid_access; + + /* + * Decode which register in PCI config space is accessed. It is + * essential to store the address port value locally so that we + * are not affected by concurrent manipulations by other CPUs + * of this cell. + */ + addr_port_val = cell->arch.pci_addr_port_val; + + bdf = addr_port_val >> PCI_ADDR_BDF_SHIFT; + device = pci_get_assigned_device(cell, bdf); + + address = (addr_port_val & PCI_ADDR_REGNUM_MASK) + + port - PCI_REG_DATA_PORT; + + if (dir_in) + result = data_port_in_handler(device, address, size); + else + result = data_port_out_handler(device, address, size); + if (result < 0) { + panic_printk("FATAL: Invalid PCI config %s, device " + "%02x:%02x.%x, reg: 0x%x, size: %d\n", + dir_in ? "read" : "write", + PCI_BDF_PARAMS(bdf), address, size); + return -1; + } + } + + return result; + +invalid_access: + panic_printk("FATAL: Invalid PCI config %s, port: 0x%x, size: %d\n", + dir_in ? "read" : "write", port, size); + return -1; + +} + +int arch_pci_add_physical_device(struct cell *cell, struct pci_device *device) +{ + return iommu_add_pci_device(cell, device); +} + +void arch_pci_remove_physical_device(struct pci_device *device) +{ + iommu_remove_pci_device(device); +} + +static union x86_msi_vector pci_get_x86_msi_vector(struct pci_device *device) +{ + union pci_msi_registers *regs = &device->msi_registers; + bool msi_64bits = device->info->msi_64bits; + union x86_msi_vector msi; + + msi.raw.address = msi_64bits ? regs->msg64.address : + regs->msg32.address; + msi.raw.data = msi_64bits ? regs->msg64.data : regs->msg32.data; + return msi; +} + +/** + * Translate a given MSI vector into an IRQ message that can be sent to one + * or more APICs. (see apic_send_irq()) + * @param device Pointer to the pci device structure + * @param vector interrupt vector number + * @param legacy_vectors number of enabled MSI vectors of device + * see pci_enabled_msi_vectors() + * @param msi msi vector that should be translated + * + * @return an IRQ messages data structure + */ +struct apic_irq_message +x86_pci_translate_msi(struct pci_device *device, unsigned int vector, + unsigned int legacy_vectors, union x86_msi_vector msi) +{ + struct apic_irq_message irq_msg = { .valid = 0 }; + unsigned int idx; + + /* + * Ignore invalid target addresses, e.g. if the cell programmed the + * register to all-zero. + */ + if (msi.native.address != MSI_ADDRESS_VALUE) + return irq_msg; + + if (iommu_cell_emulates_ir(device->cell)) { + if (!msi.remap.remapped) + return irq_msg; + + idx = msi.remap.int_index | (msi.remap.int_index15 << 15); + if (msi.remap.shv) + idx += msi.remap.subhandle; + return iommu_get_remapped_root_int(device->info->iommu, + device->info->bdf, + vector, idx); + } + + irq_msg.vector = msi.native.vector; + if (legacy_vectors > 1) { + irq_msg.vector &= ~(legacy_vectors - 1); + irq_msg.vector |= vector; + } + irq_msg.delivery_mode = msi.native.delivery_mode; + irq_msg.level_triggered = 0; + irq_msg.dest_logical = msi.native.dest_logical; + irq_msg.redir_hint = msi.native.redir_hint; + irq_msg.valid = 1; + irq_msg.destination = msi.native.destination; + + return irq_msg; +} + +void arch_pci_set_suppress_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap, + bool suppress) +{ + unsigned int n, vectors = pci_enabled_msi_vectors(device); + const struct jailhouse_pci_device *info = device->info; + struct apic_irq_message irq_msg; + unsigned int mask_pos, mask = 0; + union x86_msi_vector msi = { + .native.dest_logical = 1, + .native.redir_hint = 1, + .native.address = MSI_ADDRESS_VALUE, + }; + + if (!(pci_read_config(info->bdf, PCI_CFG_COMMAND, 2) & PCI_CMD_MASTER)) + return; + + if (suppress) { + /* + * Disable delivery by setting no destination CPU bit in logical + * addressing mode. + */ + if (info->msi_64bits) + pci_write_config(info->bdf, cap->start + 8, 0, 4); + pci_write_config(info->bdf, cap->start + 4, + (u32)msi.raw.address, 4); + } else { + /* + * Inject MSI vectors to avoid losing events while suppressed. + * Linux can handle rare spurious interrupts. + */ + if (info->msi_maskable) { + mask_pos = cap->start + (info->msi_64bits ? 0x10 : 0xc); + mask = pci_read_config(info->bdf, mask_pos, 4); + } + msi = pci_get_x86_msi_vector(device); + for (n = 0; n < vectors; n++) { + irq_msg = x86_pci_translate_msi(device, n, vectors, + msi); + if ((mask & (1 << n)) == 0 && irq_msg.valid) + apic_send_irq(irq_msg); + } + } +} + +static u64 pci_get_x86_msi_remap_address(unsigned int index) +{ + union x86_msi_vector msi = { + .remap.int_index15 = index >> 15, + .remap.shv = 1, + .remap.remapped = 1, + .remap.int_index = index, + .remap.address = MSI_ADDRESS_VALUE, + }; + + return msi.raw.address; +} + +int arch_pci_update_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + unsigned int n, vectors = pci_enabled_msi_vectors(device); + union x86_msi_vector msi = pci_get_x86_msi_vector(device); + const struct jailhouse_pci_device *info = device->info; + struct apic_irq_message irq_msg; + u16 bdf = info->bdf; + int result = 0; + + if (vectors == 0) + return 0; + + for (n = 0; n < vectors; n++) { + irq_msg = x86_pci_translate_msi(device, n, vectors, msi); + result = iommu_map_interrupt(device->cell, bdf, n, irq_msg); + // HACK for QEMU + if (result == -ENOSYS) { + for (n = 1; n < (info->msi_64bits ? 4 : 3); n++) + pci_write_config(bdf, cap->start + n * 4, + device->msi_registers.raw[n], 4); + return 0; + } + if (result < 0) + return result; + } + + /* set result to the base index again */ + result -= vectors - 1; + + pci_write_config(bdf, cap->start + (info->msi_64bits ? 12 : 8), 0, 2); + + if (info->msi_64bits) + pci_write_config(bdf, cap->start + 8, 0, 4); + pci_write_config(bdf, cap->start + 4, + (u32)pci_get_x86_msi_remap_address(result), 4); + + return 0; +} + +int arch_pci_update_msix_vector(struct pci_device *device, unsigned int index) +{ + union x86_msi_vector msi = { + .raw.address = device->msix_vectors[index].address, + .raw.data = device->msix_vectors[index].data, + }; + struct apic_irq_message irq_msg; + int result; + + if (!device->msix_registers.enable || device->msix_registers.fmask || + device->msix_vectors[index].masked) + return 0; + + irq_msg = x86_pci_translate_msi(device, index, 0, msi); + result = iommu_map_interrupt(device->cell, device->info->bdf, index, + irq_msg); + // HACK for QEMU + if (result == -ENOSYS) { + mmio_write64_split(&device->msix_table[index].address, + device->msix_vectors[index].address); + mmio_write32(&device->msix_table[index].data, + device->msix_vectors[index].data); + return 0; + } + if (result < 0) + return result; + + mmio_write64_split(&device->msix_table[index].address, + pci_get_x86_msi_remap_address(result)); + mmio_write32(&device->msix_table[index].data, 0); + + return 0; +} diff --git a/hypervisor/arch/x86/setup.c b/hypervisor/arch/x86/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..a3e1f9ed71a7f34bb9107c3b0b0c5176546c7944 --- /dev/null +++ b/hypervisor/arch/x86/setup.c @@ -0,0 +1,275 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +#define IDT_PRESENT_INT 0x00008e00 + +#define NUM_IDT_DESC 256 +#define NUM_EXCP_DESC 20 +#define IRQ_DESC_START 32 + +static u64 gdt[NUM_GDT_DESC] = { + [GDT_DESC_NULL] = 0, + [GDT_DESC_CODE] = 0x00af9b000000ffffUL, + [GDT_DESC_TSS] = 0x0000890000000000UL, + [GDT_DESC_TSS_HI] = 0x0000000000000000UL, +}; + +extern u8 exception_entries[]; +extern u8 nmi_entry[]; +extern u8 irq_entry[]; + +unsigned long cache_line_size; +static u32 idt[NUM_IDT_DESC * 4]; + +static void set_idt_int_gate(unsigned int vector, unsigned long entry) +{ + idt[vector * 4] = (entry & 0xffff) | ((GDT_DESC_CODE * 8) << 16); + idt[vector * 4 + 1] = IDT_PRESENT_INT | (entry & 0xffff0000); + idt[vector * 4 + 2] = entry >> 32; +} + +int arch_init_early(void) +{ + unsigned long entry; + unsigned int vector; + int err; + + cache_line_size = (cpuid_ebx(1, 0) & 0xff00) >> 5; + + err = apic_init(); + if (err) + return err; + + entry = (unsigned long)exception_entries; + for (vector = 0; vector < NUM_EXCP_DESC; vector++) { + if (vector == NMI_VECTOR || vector == 15) + continue; + set_idt_int_gate(vector, entry); + entry += 16; + } + + set_idt_int_gate(NMI_VECTOR, (unsigned long)nmi_entry); + + for (vector = IRQ_DESC_START; vector < NUM_IDT_DESC; vector++) + set_idt_int_gate(vector, (unsigned long)irq_entry); + + return vcpu_early_init(); +} + +/* + * TODO: Current struct segment is VMX-specific (with 32-bit access rights). + * We need a generic struct segment for x86 that is converted to VMX/SVM one + * in the vmx.c/svm.c. + */ +static void read_descriptor(struct per_cpu *cpu_data, struct segment *seg) +{ + u64 *desc = (u64 *)(cpu_data->linux_gdtr.base + + (seg->selector & 0xfff8)); + + if (desc[0] & DESC_PRESENT) { + seg->base = ((desc[0] >> 16) & 0xffffff) | + ((desc[0] >> 32) & 0xff000000); + if (!(desc[0] & DESC_CODE_DATA)) + seg->base |= desc[1] << 32; + + seg->limit = (desc[0] & 0xffff) | ((desc[0] >> 32) & 0xf0000); + if (desc[0] & DESC_PAGE_GRAN) + seg->limit = (seg->limit << 12) | 0xfff; + + seg->access_rights = (desc[0] >> 40) & 0xf0ff; + } else { + seg->base = 0; + seg->limit = 0; + seg->access_rights = 0x10000; + } +} + +static void set_cs(u16 cs) +{ + asm volatile( + "lea 1f(%%rip),%%rax\n\t" + "push %0\n\t" + "push %%rax\n\t" + "lretq\n\t" + "1:" + : : "m" (cs) : "rax"); +} + +int arch_cpu_init(struct per_cpu *cpu_data) +{ + struct desc_table_reg dtr; + int err, n; + + /* read GDTR */ + read_gdtr(&cpu_data->linux_gdtr); + + /* read TR and TSS descriptor */ + asm volatile("str %0" : "=m" (cpu_data->linux_tss.selector)); + read_descriptor(cpu_data, &cpu_data->linux_tss); + + if (cpu_data->linux_tss.selector / 8 >= NUM_GDT_DESC) + return trace_error(-EINVAL); + + /* save CS as long as we have access to the Linux page table */ + asm volatile("mov %%cs,%0" : "=m" (cpu_data->linux_cs.selector)); + read_descriptor(cpu_data, &cpu_data->linux_cs); + + /* save segment registers - they may point to 32 or 16 bit segments */ + asm volatile("mov %%ds,%0" : "=m" (cpu_data->linux_ds.selector)); + read_descriptor(cpu_data, &cpu_data->linux_ds); + + asm volatile("mov %%es,%0" : "=m" (cpu_data->linux_es.selector)); + read_descriptor(cpu_data, &cpu_data->linux_es); + + asm volatile("mov %%fs,%0" : "=m" (cpu_data->linux_fs.selector)); + read_descriptor(cpu_data, &cpu_data->linux_fs); + cpu_data->linux_fs.base = read_msr(MSR_FS_BASE); + + asm volatile("mov %%gs,%0" : "=m" (cpu_data->linux_gs.selector)); + read_descriptor(cpu_data, &cpu_data->linux_gs); + cpu_data->linux_gs.base = read_msr(MSR_GS_BASE); + + /* read registers to restore on first VM-entry */ + for (n = 0; n < NUM_ENTRY_REGS; n++) + cpu_data->linux_reg[n] = + ((unsigned long *)cpu_data->linux_sp)[n]; + cpu_data->linux_ip = + ((unsigned long *)cpu_data->linux_sp)[NUM_ENTRY_REGS]; + + /* set GDTR */ + dtr.limit = NUM_GDT_DESC * 8 - 1; + dtr.base = (u64)&gdt; + write_gdtr(&dtr); + + set_cs(GDT_DESC_CODE * 8); + + /* swap IDTR */ + read_idtr(&cpu_data->linux_idtr); + dtr.limit = NUM_IDT_DESC * 16 - 1; + dtr.base = (u64)&idt; + write_idtr(&dtr); + + /* paranoid clearing of segment registers */ + asm volatile( + "mov %0,%%es\n\t" + "mov %0,%%ds\n\t" + "mov %0,%%ss" + : : "r" (0)); + + /* clear TSS busy flag set by previous loading, then set TR */ + gdt[GDT_DESC_TSS] &= ~DESC_TSS_BUSY; + asm volatile("ltr %%ax" : : "a" (GDT_DESC_TSS * 8)); + + cpu_data->linux_cr0 = read_cr0(); + cpu_data->linux_cr4 = read_cr4(); + + /* swap CR3 */ + cpu_data->linux_cr3 = read_cr3(); + write_cr3(paging_hvirt2phys(cpu_data->pg_structs.root_table)); + + cpu_data->pat = read_msr(MSR_IA32_PAT); + write_msr(MSR_IA32_PAT, PAT_HOST_VALUE); + + cpu_data->mtrr_def_type = read_msr(MSR_IA32_MTRR_DEF_TYPE); + + cpu_data->linux_efer = read_msr(MSR_EFER); + + cpu_data->initialized = true; + + err = apic_cpu_init(cpu_data); + if (err) + return err; + + return vcpu_init(cpu_data); +} + +void __attribute__((noreturn)) arch_cpu_activate_vmm(void) +{ + unsigned int cpu_id = this_cpu_id(); + + /* + * Switch the stack to the private mapping before deactivating the + * common one. + */ + asm volatile( + "add %0,%%rsp" + : : "g" (LOCAL_CPU_BASE - (unsigned long)per_cpu(cpu_id))); + + /* Revoke full per_cpu access now that everything is set up. */ + paging_map_all_per_cpu(cpu_id, false); + + vcpu_activate_vmm(); +} + +void arch_cpu_restore(unsigned int cpu_id, int return_code) +{ + static spinlock_t tss_lock; + struct per_cpu *cpu_data = per_cpu(cpu_id); + unsigned int tss_idx; + u64 *linux_gdt; + + if (!cpu_data->initialized) + return; + + vcpu_exit(cpu_data); + + write_msr(MSR_IA32_PAT, cpu_data->pat); + write_msr(MSR_EFER, cpu_data->linux_efer); + write_cr0(cpu_data->linux_cr0); + write_cr4(cpu_data->linux_cr4); + /* cr3 must be last in case cr4 enables PCID */ + write_cr3(cpu_data->linux_cr3); + + /* + * Copy Linux TSS descriptor into our GDT, clearing the busy flag, + * then reload TR from it. We can't use Linux' GDT as it is r/o. + * Access can happen concurrently on multiple CPUs, so we have to + * serialize the critical section. + */ + linux_gdt = (u64 *)cpu_data->linux_gdtr.base; + tss_idx = cpu_data->linux_tss.selector / 8; + + spin_lock(&tss_lock); + + gdt[tss_idx] = linux_gdt[tss_idx] & ~DESC_TSS_BUSY; + gdt[tss_idx + 1] = linux_gdt[tss_idx + 1]; + asm volatile("ltr %%ax" : : "a" (cpu_data->linux_tss.selector)); + + spin_unlock(&tss_lock); + + asm volatile("lgdtq %0" : : "m" (cpu_data->linux_gdtr)); + asm volatile("lidtq %0" : : "m" (cpu_data->linux_idtr)); + + set_cs(cpu_data->linux_cs.selector); + + asm volatile("mov %0,%%ds" : : "r" (cpu_data->linux_ds.selector)); + asm volatile("mov %0,%%es" : : "r" (cpu_data->linux_es.selector)); + asm volatile("mov %0,%%fs" : : "r" (cpu_data->linux_fs.selector)); + asm volatile( + "swapgs\n\t" + "mov %0,%%gs\n\t" + "mfence\n\t" + "swapgs\n\t" + : : "r" (cpu_data->linux_gs.selector)); + + write_msr(MSR_FS_BASE, cpu_data->linux_fs.base); + write_msr(MSR_GS_BASE, cpu_data->linux_gs.base); +} diff --git a/hypervisor/arch/x86/svm-vmexit.S b/hypervisor/arch/x86/svm-vmexit.S new file mode 100644 index 0000000000000000000000000000000000000000..53ac22633609e90badb3008afb9281d6c97aeeb8 --- /dev/null +++ b/hypervisor/arch/x86/svm-vmexit.S @@ -0,0 +1,61 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +/* SVM VM entry and handling of VM exit */ + .globl svm_vmentry +svm_vmentry: + vmrun %rax + + /* XXX: GIF is always cleared here */ + push -PERCPU_STACK_END+PERCPU_VMCB_RAX(%rsp) + push %rcx + push %rdx + push %rbx + sub $8,%rsp /* placeholder for rsp */ + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + mov $LOCAL_CPU_BASE_ASM,%rdi + push %rax + call vcpu_handle_exit + pop %rax + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + add $8,%rsp + pop %rbx + pop %rdx + pop %rcx + pop -PERCPU_STACK_END+PERCPU_VMCB_RAX(%rsp) + + jmp svm_vmentry diff --git a/hypervisor/arch/x86/svm.c b/hypervisor/arch/x86/svm.c new file mode 100644 index 0000000000000000000000000000000000000000..9b1664a57775e47f071c29aef786b19d0b72b8e7 --- /dev/null +++ b/hypervisor/arch/x86/svm.c @@ -0,0 +1,1051 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * Based on vmx.c written by Jan Kiszka. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * NW bit is ignored by all modern processors, however some + * combinations of NW and CD bits are prohibited by SVM (see APMv2, + * Sect. 15.5). To handle this, we always keep the NW bit off. + */ +#define SVM_CR0_ALLOWED_BITS (~X86_CR0_NW) + +/* IOPM size: two 4-K pages + 3 bits */ +#define IOPM_PAGES 3 + +#define NPT_IOMMU_PAGE_DIR_LEVELS 4 + +static bool has_avic, has_assists, has_flush_by_asid; + +static const struct segment invalid_seg; + +static struct paging npt_iommu_paging[NPT_IOMMU_PAGE_DIR_LEVELS]; + +/* bit cleared: direct access allowed */ +// TODO: convert to whitelist +static u8 __attribute__((aligned(PAGE_SIZE))) msrpm[][0x2000/4] = { + [ SVM_MSRPM_0000 ] = { + [ 0/4 ... 0x017/4 ] = 0, + [ 0x018/4 ... 0x01b/4 ] = 0x80, /* 0x01b (w) */ + [ 0x01c/4 ... 0x1ff/4 ] = 0, + [ 0x200/4 ... 0x273/4 ] = 0xaa, /* 0x200 - 0x273 (w) */ + [ 0x274/4 ... 0x277/4 ] = 0xea, /* 0x274 - 0x276 (w), 0x277 (rw) */ + [ 0x278/4 ... 0x2fb/4 ] = 0, + [ 0x2fc/4 ... 0x2ff/4 ] = 0x80, /* 0x2ff (w) */ + [ 0x300/4 ... 0x7ff/4 ] = 0, + /* x2APIC MSRs - emulated if not present */ + [ 0x800/4 ... 0x803/4 ] = 0x50, /* 0x802-0x803 (r) */ + [ 0x804/4 ... 0x807/4 ] = 0, + [ 0x808/4 ... 0x80b/4 ] = 0x93, /* 0x808 (rw), 0x80a (r), 0x80b (w) */ + [ 0x80c/4 ... 0x80f/4 ] = 0xc8, /* 0x80d (w), 0x80f (rw) */ + [ 0x810/4 ... 0x827/4 ] = 0x55, /* 0x810 - 0x827 (r) */ + [ 0x828/4 ... 0x82b/4 ] = 0x03, /* 0x828 (rw) */ + [ 0x82c/4 ... 0x82f/4 ] = 0xc0, /* 0x82f (rw) */ + [ 0x830/4 ... 0x833/4 ] = 0xf3, /* 0x830 (rw), 0x832 (rw), 0x833 (rw) */ + [ 0x834/4 ... 0x837/4 ] = 0xff, /* 0x834 - 0x837 (rw) */ + [ 0x838/4 ... 0x83b/4 ] = 0x07, /* 0x838 (rw), 0x839 (r) */ + [ 0x83c/4 ... 0x83f/4 ] = 0x70, /* 0x83e (rw), 0x83f (r) */ + [ 0x840/4 ... 0x1fff/4 ] = 0, + }, + [ SVM_MSRPM_C000 ] = { + [ 0/4 ... 0x07f/4 ] = 0, + [ 0x080/4 ... 0x083/4 ] = 0x02, /* 0x080 (w) */ + [ 0x084/4 ... 0x1fff/4 ] = 0 + }, + [ SVM_MSRPM_C001 ] = { + [ 0/4 ... 0x1fff/4 ] = 0, + }, + [ SVM_MSRPM_RESV ] = { + [ 0/4 ... 0x1fff/4 ] = 0, + } +}; + +static void *avic_page; + +static int svm_check_features(void) +{ + /* SVM is available */ + if (!(cpuid_ecx(0x80000001, 0) & X86_FEATURE_SVM)) + return trace_error(-ENODEV); + + /* Nested paging */ + if (!(cpuid_edx(0x8000000A, 0) & X86_FEATURE_NP)) + return trace_error(-EIO); + + /* Decode assists */ + if ((cpuid_edx(0x8000000A, 0) & X86_FEATURE_DECODE_ASSISTS)) + has_assists = true; + + /* AVIC support */ + /* FIXME: Jailhouse support is incomplete so far + if (cpuid_edx(0x8000000A, 0) & X86_FEATURE_AVIC) + has_avic = true; */ + + /* TLB Flush by ASID support */ + if (cpuid_edx(0x8000000A, 0) & X86_FEATURE_FLUSH_BY_ASID) + has_flush_by_asid = true; + + return 0; +} + +static void set_svm_segment_from_dtr(struct svm_segment *svm_segment, + const struct desc_table_reg *dtr) +{ + svm_segment->base = dtr->base; + svm_segment->limit = dtr->limit & 0xffff; +} + +static void set_svm_segment_from_segment(struct svm_segment *svm_segment, + const struct segment *segment) +{ + svm_segment->selector = segment->selector; + svm_segment->attributes = ((segment->access_rights & 0xf000) >> 4) | + (segment->access_rights & 0x00ff); + svm_segment->limit = segment->limit; + svm_segment->base = segment->base; +} + +static void svm_set_cell_config(struct cell *cell, struct vmcb *vmcb) +{ + vmcb->iopm_base_pa = paging_hvirt2phys(cell->arch.io_bitmap); + vmcb->n_cr3 = + paging_hvirt2phys(cell->arch.svm.npt_iommu_structs.root_table); +} + +static void vmcb_setup(struct per_cpu *cpu_data) +{ + struct vmcb *vmcb = &cpu_data->vmcb; + + memset(vmcb, 0, sizeof(struct vmcb)); + + vmcb->cr0 = cpu_data->linux_cr0 & SVM_CR0_ALLOWED_BITS; + vmcb->cr3 = cpu_data->linux_cr3; + vmcb->cr4 = cpu_data->linux_cr4; + + set_svm_segment_from_segment(&vmcb->cs, &cpu_data->linux_cs); + set_svm_segment_from_segment(&vmcb->ds, &cpu_data->linux_ds); + set_svm_segment_from_segment(&vmcb->es, &cpu_data->linux_es); + set_svm_segment_from_segment(&vmcb->fs, &cpu_data->linux_fs); + set_svm_segment_from_segment(&vmcb->gs, &cpu_data->linux_gs); + set_svm_segment_from_segment(&vmcb->ss, &invalid_seg); + set_svm_segment_from_segment(&vmcb->tr, &cpu_data->linux_tss); + set_svm_segment_from_segment(&vmcb->ldtr, &invalid_seg); + + set_svm_segment_from_dtr(&vmcb->gdtr, &cpu_data->linux_gdtr); + set_svm_segment_from_dtr(&vmcb->idtr, &cpu_data->linux_idtr); + + vmcb->cpl = 0; /* Linux runs in ring 0 before migration */ + + vmcb->rflags = 0x02; + /* Indicate success to the caller of arch_entry */ + vmcb->rax = 0; + vmcb->rsp = cpu_data->linux_sp + + (NUM_ENTRY_REGS + 1) * sizeof(unsigned long); + vmcb->rip = cpu_data->linux_ip; + + vmcb->sysenter_cs = read_msr(MSR_IA32_SYSENTER_CS); + vmcb->sysenter_eip = read_msr(MSR_IA32_SYSENTER_EIP); + vmcb->sysenter_esp = read_msr(MSR_IA32_SYSENTER_ESP); + vmcb->star = read_msr(MSR_STAR); + vmcb->lstar = read_msr(MSR_LSTAR); + vmcb->cstar = read_msr(MSR_CSTAR); + vmcb->sfmask = read_msr(MSR_SFMASK); + vmcb->kerngsbase = read_msr(MSR_KERNGS_BASE); + + vmcb->dr6 = 0x00000ff0; + vmcb->dr7 = 0x00000400; + + /* Make the hypervisor visible */ + vmcb->efer = (cpu_data->linux_efer | EFER_SVME); + + vmcb->g_pat = cpu_data->pat; + + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_NMI; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_CR0_SEL_WRITE; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_CPUID; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_IOIO_PROT; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_MSR_PROT; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_SHUTDOWN_EVT; + + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_VMRUN; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_VMMCALL; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_VMLOAD; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_VMSAVE; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_STGI; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_CLGI; + vmcb->general2_intercepts |= GENERAL2_INTERCEPT_SKINIT; + + /* + * We only intercept #DB and #AC to prevent that malicious guests can + * trigger infinite loops in microcode (see e.g. CVE-2015-5307 and + * CVE-2015-8104). + */ + vmcb->exception_intercepts |= (1 << DB_VECTOR) | (1 << AC_VECTOR); + + vmcb->msrpm_base_pa = paging_hvirt2phys(msrpm); + + vmcb->np_enable = 1; + /* No more than one guest owns the CPU */ + vmcb->guest_asid = 1; + + /* TODO: Setup AVIC */ + + /* Explicitly mark all of the state as new */ + vmcb->clean_bits = 0; + + svm_set_cell_config(cpu_data->public.cell, vmcb); +} + +unsigned long arch_paging_gphys2phys(unsigned long gphys, + unsigned long flags) +{ + return paging_virt2phys(&this_cell()->arch.svm.npt_iommu_structs, + gphys, flags); +} + +static void npt_iommu_set_next_pt_l4(pt_entry_t pte, unsigned long next_pt) +{ + /* + * Merge IOMMU and NPT flags. We need to mark the NTP entries as user + * accessible, see APMv2, Section 15.25.5. + */ + *pte = (next_pt & BIT_MASK(51, 12)) | AMD_IOMMU_PTE_PG_MODE(3) | + AMD_IOMMU_PTE_IR | AMD_IOMMU_PTE_IW | AMD_IOMMU_PTE_P | + PAGE_DEFAULT_FLAGS | PAGE_FLAG_US; +} + +static void npt_iommu_set_next_pt_l3(pt_entry_t pte, unsigned long next_pt) +{ + *pte = (next_pt & BIT_MASK(51, 12)) | AMD_IOMMU_PTE_PG_MODE(2) | + AMD_IOMMU_PTE_IR | AMD_IOMMU_PTE_IW | AMD_IOMMU_PTE_P | + PAGE_DEFAULT_FLAGS | PAGE_FLAG_US; +} + +static void npt_iommu_set_next_pt_l2(pt_entry_t pte, unsigned long next_pt) +{ + *pte = (next_pt & BIT_MASK(51, 12)) | AMD_IOMMU_PTE_PG_MODE(1) | + AMD_IOMMU_PTE_IR | AMD_IOMMU_PTE_IW | AMD_IOMMU_PTE_P | + PAGE_DEFAULT_FLAGS | PAGE_FLAG_US; +} + +static unsigned long npt_iommu_get_phys_l3(pt_entry_t pte, unsigned long virt) +{ + if (*pte & AMD_IOMMU_PTE_PG_MODE_MASK) + return INVALID_PHYS_ADDR; + return (*pte & BIT_MASK(51, 30)) | (virt & BIT_MASK(29, 0)); +} + +static unsigned long npt_iommu_get_phys_l2(pt_entry_t pte, unsigned long virt) +{ + if (*pte & AMD_IOMMU_PTE_PG_MODE_MASK) + return INVALID_PHYS_ADDR; + return (*pte & BIT_MASK(51, 21)) | (virt & BIT_MASK(20, 0)); +} + +int vcpu_vendor_early_init(void) +{ + unsigned long vm_cr; + int err; + + err = svm_check_features(); + if (err) + return err; + + vm_cr = read_msr(MSR_VM_CR); + if (vm_cr & VM_CR_SVMDIS) + /* SVM disabled in BIOS */ + return trace_error(-EPERM); + + /* + * Nested paging is almost the same as the native one. However, we + * need to override some handlers in order to reuse the page table for + * the IOMMU as well. + */ + memcpy(npt_iommu_paging, x86_64_paging, sizeof(npt_iommu_paging)); + npt_iommu_paging[0].set_next_pt = npt_iommu_set_next_pt_l4; + npt_iommu_paging[1].set_next_pt = npt_iommu_set_next_pt_l3; + npt_iommu_paging[2].set_next_pt = npt_iommu_set_next_pt_l2; + npt_iommu_paging[1].get_phys = npt_iommu_get_phys_l3; + npt_iommu_paging[2].get_phys = npt_iommu_get_phys_l2; + + parking_pt.root_paging = npt_iommu_paging; + + /* This is always false for AMD now (except in nested SVM); + see Sect. 16.3.1 in APMv2 */ + if (using_x2apic) { + /* allow direct x2APIC access except for ICR writes */ + memset(&msrpm[SVM_MSRPM_0000][MSR_X2APIC_BASE/4], 0, + (MSR_X2APIC_END - MSR_X2APIC_BASE + 1)/4); + msrpm[SVM_MSRPM_0000][MSR_X2APIC_ICR/4] = 0x02; + } else { + if (has_avic) { + avic_page = page_alloc(&remap_pool, 1); + if (!avic_page) + return trace_error(-ENOMEM); + } + } + + return vcpu_cell_init(&root_cell); +} + +int vcpu_vendor_cell_init(struct cell *cell) +{ + u64 flags; + + /* build root NPT of cell */ + cell->arch.svm.npt_iommu_structs.root_paging = npt_iommu_paging; + cell->arch.svm.npt_iommu_structs.root_table = + (page_table_t)cell->arch.root_table_page; + + if (!has_avic) { + /* + * Map xAPIC as is; reads are passed, writes are trapped. + */ + flags = PAGE_READONLY_FLAGS | PAGE_FLAG_US | PAGE_FLAG_DEVICE; + return paging_create(&cell->arch.svm.npt_iommu_structs, + XAPIC_BASE, PAGE_SIZE, XAPIC_BASE, flags, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + } else { + flags = PAGE_DEFAULT_FLAGS | PAGE_FLAG_DEVICE; + return paging_create(&cell->arch.svm.npt_iommu_structs, + paging_hvirt2phys(avic_page), + PAGE_SIZE, XAPIC_BASE, flags, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + } +} + +int vcpu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + u64 phys_start = mem->phys_start; + u64 access_flags = PAGE_FLAG_US; /* See APMv2, Section 15.25.5 */ + u64 paging_flags = PAGING_COHERENT | PAGING_HUGE; + + if (mem->flags & JAILHOUSE_MEM_READ) + access_flags |= PAGE_FLAG_PRESENT; + if (mem->flags & JAILHOUSE_MEM_WRITE) + access_flags |= PAGE_FLAG_RW; + if (!(mem->flags & JAILHOUSE_MEM_EXECUTE)) + access_flags |= PAGE_FLAG_NOEXECUTE; + if (mem->flags & JAILHOUSE_MEM_COMM_REGION) + phys_start = paging_hvirt2phys(&cell->comm_page); + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_HUGE; + + access_flags |= amd_iommu_get_memory_region_flags(mem); + + /* + * As we also manipulate the IOMMU page table, changes need to be + * coherent. + */ + return paging_create(&cell->arch.svm.npt_iommu_structs, phys_start, + mem->size, mem->virt_start, access_flags, + paging_flags); +} + +int vcpu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return paging_destroy(&cell->arch.svm.npt_iommu_structs, + mem->virt_start, mem->size, PAGING_COHERENT); +} + +void vcpu_vendor_cell_exit(struct cell *cell) +{ + paging_destroy(&cell->arch.svm.npt_iommu_structs, XAPIC_BASE, + PAGE_SIZE, PAGING_NON_COHERENT); +} + +int vcpu_init(struct per_cpu *cpu_data) +{ + unsigned long efer; + int err; + + err = svm_check_features(); + if (err) + return err; + + efer = read_msr(MSR_EFER); + if (efer & EFER_SVME) + return trace_error(-EBUSY); + + efer |= EFER_SVME; + write_msr(MSR_EFER, efer); + + cpu_data->svm_state = SVMON; + + vmcb_setup(cpu_data); + + /* + * APM Volume 2, 3.1.1: "When writing the CR0 register, software should + * set the values of reserved bits to the values found during the + * previous CR0 read." + * But we want to avoid surprises with new features unknown to us but + * set by Linux. So check if any assumed revered bit was set and bail + * out if so. + * Note that the APM defines all reserved CR4 bits as must-be-zero. + */ + if (cpu_data->linux_cr0 & X86_CR0_RESERVED) + return trace_error(-EIO); + + /* bring CR0 and CR4 into well-defined states */ + write_cr0(X86_CR0_HOST_STATE); + write_cr4(X86_CR4_HOST_STATE); + + write_msr(MSR_VM_HSAVE_PA, + paging_hvirt2phys(per_cpu(this_cpu_id())->host_state)); + + return 0; +} + +void vcpu_exit(struct per_cpu *cpu_data) +{ + unsigned long efer; + + if (cpu_data->svm_state == SVMOFF) + return; + + cpu_data->svm_state = SVMOFF; + + /* We are leaving - set the GIF */ + asm volatile ("stgi" : : : "memory"); + + efer = read_msr(MSR_EFER); + efer &= ~EFER_SVME; + write_msr(MSR_EFER, efer); + + write_msr(MSR_VM_HSAVE_PA, 0); +} + +void __attribute__((noreturn)) vcpu_activate_vmm(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + unsigned long vmcb_pa, host_stack; + + vmcb_pa = paging_hvirt2phys(&per_cpu(this_cpu_id())->vmcb); + host_stack = (unsigned long)cpu_data->stack + sizeof(cpu_data->stack); + + /* We enter Linux at the point arch_entry would return to as well. + * rax is cleared to signal success to the caller. */ + asm volatile( + "clgi\n\t" + "mov (%%rdi),%%r15\n\t" + "mov 0x8(%%rdi),%%r14\n\t" + "mov 0x10(%%rdi),%%r13\n\t" + "mov 0x18(%%rdi),%%r12\n\t" + "mov 0x20(%%rdi),%%rbx\n\t" + "mov 0x28(%%rdi),%%rbp\n\t" + "mov %2,%%rsp\n\t" + "vmload %%rax\n\t" + "jmp svm_vmentry" + : /* no output */ + : "D" (cpu_data->linux_reg), "a" (vmcb_pa), "m" (host_stack)); + __builtin_unreachable(); +} + +void __attribute__((noreturn)) vcpu_deactivate_vmm(void) +{ + /* use common per-cpu area - mandatory after arch_cpu_restore */ + struct per_cpu *cpu_data = per_cpu(this_cpu_id()); + struct vmcb *vmcb = &cpu_data->vmcb; + unsigned long *stack = (unsigned long *)vmcb->rsp; + unsigned long linux_ip = vmcb->rip; + + cpu_data->linux_cr0 = vmcb->cr0; + cpu_data->linux_cr3 = vmcb->cr3; + + cpu_data->linux_gdtr.base = vmcb->gdtr.base; + cpu_data->linux_gdtr.limit = vmcb->gdtr.limit; + cpu_data->linux_idtr.base = vmcb->idtr.base; + cpu_data->linux_idtr.limit = vmcb->idtr.limit; + + cpu_data->linux_cs.selector = vmcb->cs.selector; + + asm volatile("str %0" : "=m" (cpu_data->linux_tss.selector)); + + cpu_data->linux_efer = vmcb->efer & (~EFER_SVME); + cpu_data->linux_fs.base = read_msr(MSR_FS_BASE); + cpu_data->linux_gs.base = vmcb->gs.base; + + cpu_data->linux_ds.selector = vmcb->ds.selector; + cpu_data->linux_es.selector = vmcb->es.selector; + + asm volatile("mov %%fs,%0" : "=m" (cpu_data->linux_fs.selector)); + asm volatile("mov %%gs,%0" : "=m" (cpu_data->linux_gs.selector)); + + arch_cpu_restore(this_cpu_id(), 0); + + stack--; + *stack = linux_ip; + + asm volatile ( + "mov %%rbx,%%rsp\n\t" + "pop %%r15\n\t" + "pop %%r14\n\t" + "pop %%r13\n\t" + "pop %%r12\n\t" + "pop %%r11\n\t" + "pop %%r10\n\t" + "pop %%r9\n\t" + "pop %%r8\n\t" + "pop %%rdi\n\t" + "pop %%rsi\n\t" + "pop %%rbp\n\t" + "add $8,%%rsp\n\t" + "pop %%rbx\n\t" + "pop %%rdx\n\t" + "pop %%rcx\n\t" + "mov %%rax,%%rsp\n\t" + "xor %%rax,%%rax\n\t" + "ret" + : : "a" (stack), "b" (&cpu_data->guest_regs)); + __builtin_unreachable(); +} + +void vcpu_vendor_reset(unsigned int sipi_vector) +{ + static const struct svm_segment dataseg_reset_state = { + .selector = 0, + .base = 0, + .limit = 0xffff, + .attributes = 0x0093, + }; + static const struct svm_segment dtr_reset_state = { + .selector = 0, + .base = 0, + .limit = 0xffff, + .attributes = 0, + }; + struct per_cpu *cpu_data = this_cpu_data(); + struct vmcb *vmcb = &cpu_data->vmcb; + unsigned long vmcb_pa, reset_addr; + + vmcb->cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET; + vmcb->cr3 = 0; + vmcb->cr4 = 0; + + vmcb->rflags = 0x02; + vmcb->rsp = 0; + + if (sipi_vector == APIC_BSP_PSEUDO_SIPI) { + reset_addr = this_cell()->config->cpu_reset_address; + + vmcb->rip = reset_addr & 0xffff; + + vmcb->cs.selector = (reset_addr >> 4) & 0xf000; + vmcb->cs.base = reset_addr & ~0xffffL; + } else { + vmcb->rip = 0; + + vmcb->cs.selector = sipi_vector << 8; + vmcb->cs.base = sipi_vector << 12; + } + + vmcb->cs.limit = 0xffff; + vmcb->cs.attributes = 0x009b; + + vmcb->ds = dataseg_reset_state; + vmcb->es = dataseg_reset_state; + vmcb->fs = dataseg_reset_state; + vmcb->gs = dataseg_reset_state; + vmcb->ss = dataseg_reset_state; + + vmcb->tr.selector = 0; + vmcb->tr.base = 0; + vmcb->tr.limit = 0xffff; + vmcb->tr.attributes = 0x008b; + + vmcb->ldtr.selector = 0; + vmcb->ldtr.base = 0; + vmcb->ldtr.limit = 0xffff; + vmcb->ldtr.attributes = 0x0082; + + vmcb->gdtr = dtr_reset_state; + vmcb->idtr = dtr_reset_state; + + vmcb->efer = EFER_SVME; + + /* These MSRs are undefined on reset */ + vmcb->star = 0; + vmcb->lstar = 0; + vmcb->cstar = 0; + vmcb->sfmask = 0; + vmcb->sysenter_cs = 0; + vmcb->sysenter_eip = 0; + vmcb->sysenter_esp = 0; + vmcb->kerngsbase = 0; + + vmcb->dr7 = 0x00000400; + + vmcb->eventinj = 0; + + /* Almost all of the guest state changed */ + vmcb->clean_bits = 0; + + svm_set_cell_config(cpu_data->public.cell, vmcb); + + vmcb_pa = paging_hvirt2phys(&per_cpu(this_cpu_id())->vmcb); + asm volatile("vmload %%rax" : : "a" (vmcb_pa) : "memory"); + /* vmload overwrites GS_BASE - restore the host state */ + write_msr(MSR_GS_BASE, (unsigned long)cpu_data); +} + +void vcpu_skip_emulated_instruction(unsigned int inst_len) +{ + this_cpu_data()->vmcb.rip += inst_len; +} + +static void update_efer(struct vmcb *vmcb) +{ + unsigned long efer = vmcb->efer; + + if ((efer & (EFER_LME | EFER_LMA)) != EFER_LME) + return; + + efer |= EFER_LMA; + + /* Flush TLB on LMA/LME change: See APMv2, Sect. 15.16 */ + if ((vmcb->efer ^ efer) & EFER_LMA) + vcpu_tlb_flush(); + + vmcb->efer = efer; + vmcb->clean_bits &= ~CLEAN_BITS_CRX; +} + +void vcpu_get_guest_paging_structs(struct guest_paging_structures *pg_structs) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + + if (vmcb->efer & EFER_LMA) { + pg_structs->root_paging = x86_64_paging; + pg_structs->root_table_gphys = vmcb->cr3 & BIT_MASK(51, 12); + } else if (!(vmcb->cr0 & X86_CR0_PG)) { + pg_structs->root_paging = NULL; + } else if (vmcb->cr4 & X86_CR4_PAE) { + pg_structs->root_paging = pae_paging; + pg_structs->root_table_gphys = vmcb->cr3 & BIT_MASK(31, 5); + } else { + pg_structs->root_paging = i386_paging; + pg_structs->root_table_gphys = vmcb->cr3 & BIT_MASK(31, 12); + } +} + +void vcpu_vendor_set_guest_pat(unsigned long val) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + + vmcb->g_pat = val; + vmcb->clean_bits &= ~CLEAN_BITS_NP; +} + +struct parse_context { + unsigned int remaining; + unsigned int size; + unsigned long cs_base; + const u8 *inst; +}; + +static bool ctx_advance(struct parse_context *ctx, + unsigned long *pc, + struct guest_paging_structures *pg_structs) +{ + if (!ctx->size) { + ctx->size = ctx->remaining; + ctx->inst = vcpu_map_inst(pg_structs, ctx->cs_base + *pc, + &ctx->size); + if (!ctx->inst) + return false; + ctx->remaining -= ctx->size; + *pc += ctx->size; + } + return true; +} + +static bool svm_parse_mov_to_cr(struct vmcb *vmcb, unsigned long pc, + unsigned char reg, unsigned long *gpr) +{ + struct guest_paging_structures pg_structs; + struct parse_context ctx = {}; + /* No prefixes are supported yet */ + u8 opcodes[] = {0x0f, 0x22}, modrm; + unsigned int n; + + vcpu_get_guest_paging_structs(&pg_structs); + + ctx.remaining = ARRAY_SIZE(opcodes); + ctx.cs_base = (vmcb->efer & EFER_LMA) ? 0 : vmcb->cs.base; + + if (!ctx_advance(&ctx, &pc, &pg_structs)) + return false; + + for (n = 0; n < ARRAY_SIZE(opcodes); n++, ctx.inst++) + if (*(ctx.inst) != opcodes[n] || + !ctx_advance(&ctx, &pc, &pg_structs)) + return false; + + if (!ctx_advance(&ctx, &pc, &pg_structs)) + return false; + + modrm = *(ctx.inst); + + if (((modrm & 0x38) >> 3) != reg) + return false; + + if (gpr) + *gpr = (modrm & 0x7); + + return true; +} + +/* + * XXX: The only visible reason to have this function (vmx.c consistency + * aside) is to prevent cells from setting invalid CD+NW combinations that + * result in no more than VMEXIT_INVALID. Maybe we can get along without it + * altogether? + */ +static bool svm_handle_cr(struct per_cpu *cpu_data) +{ + struct vmcb *vmcb = &cpu_data->vmcb; + /* Workaround GCC 4.8 warning on uninitialized variable 'reg' */ + unsigned long reg = -1, val, bits; + + if (has_assists) { + if (!(vmcb->exitinfo1 & (1UL << 63))) { + panic_printk("FATAL: Unsupported CR access (LMSW or CLTS)\n"); + return false; + } + reg = vmcb->exitinfo1 & 0x07; + } else { + if (!svm_parse_mov_to_cr(vmcb, vmcb->rip, 0, ®)) { + panic_printk("FATAL: Unable to parse MOV-to-CR instruction\n"); + return false; + } + } + + if (reg == 4) + val = vmcb->rsp; + else + val = cpu_data->guest_regs.by_index[15 - reg]; + + vcpu_skip_emulated_instruction(X86_INST_LEN_MOV_TO_CR); + /* Flush TLB on PG/WP/CD/NW change: See APMv2, Sect. 15.16 */ + bits = (X86_CR0_PG | X86_CR0_WP | X86_CR0_CD | X86_CR0_NW); + if ((val ^ vmcb->cr0) & bits) + vcpu_tlb_flush(); + /* TODO: better check for #GP reasons */ + vmcb->cr0 = val & SVM_CR0_ALLOWED_BITS; + if (val & X86_CR0_PG) + update_efer(vmcb); + vmcb->clean_bits &= ~CLEAN_BITS_CRX; + + return true; +} + +static bool svm_handle_msr_write(struct per_cpu *cpu_data) +{ + struct vmcb *vmcb = &cpu_data->vmcb; + unsigned long efer; + + if (cpu_data->guest_regs.rcx == MSR_EFER) { + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + /* Never let a guest to disable SVME; see APMv2, Sect. 3.1.7 */ + efer = get_wrmsr_value(&cpu_data->guest_regs) | EFER_SVME; + /* Flush TLB on LME/NXE change: See APMv2, Sect. 15.16 */ + if ((efer ^ vmcb->efer) & (EFER_LME | EFER_NXE)) + vcpu_tlb_flush(); + vmcb->efer = efer; + vmcb->clean_bits &= ~CLEAN_BITS_CRX; + vcpu_skip_emulated_instruction(X86_INST_LEN_WRMSR); + return true; + } + + return vcpu_handle_msr_write(); +} + +/* + * TODO: This handles unaccelerated (non-AVIC) access. AVIC should + * be treated separately in svm_handle_avic_access(). + */ +static bool svm_handle_apic_access(struct vmcb *vmcb) +{ + struct guest_paging_structures pg_structs; + unsigned int inst_len, offset; + bool is_write; + + /* The caller is responsible for sanity checks */ + is_write = !!(vmcb->exitinfo1 & 0x2); + offset = vmcb->exitinfo2 - XAPIC_BASE; + + if (offset & 0x00f) + goto out_err; + + vcpu_get_guest_paging_structs(&pg_structs); + + inst_len = apic_mmio_access(&pg_structs, offset >> 4, is_write); + if (!inst_len) + goto out_err; + + vcpu_skip_emulated_instruction(inst_len); + return true; + +out_err: + panic_printk("FATAL: Unhandled APIC access, offset %d, is_write: %d\n", + offset, is_write); + return false; +} + +static void dump_guest_regs(union registers *guest_regs, struct vmcb *vmcb) +{ + panic_printk("RIP: 0x%016llx RSP: 0x%016llx FLAGS: %llx\n", vmcb->rip, + vmcb->rsp, vmcb->rflags); + panic_printk("RAX: 0x%016lx RBX: 0x%016lx RCX: 0x%016lx\n", + guest_regs->rax, guest_regs->rbx, guest_regs->rcx); + panic_printk("RDX: 0x%016lx RSI: 0x%016lx RDI: 0x%016lx\n", + guest_regs->rdx, guest_regs->rsi, guest_regs->rdi); + panic_printk("CS: %x BASE: 0x%016llx AR-BYTES: %x EFER.LMA %d\n", + vmcb->cs.selector, vmcb->cs.base, vmcb->cs.attributes, + !!(vmcb->efer & EFER_LMA)); + panic_printk("CR0: 0x%016llx CR3: 0x%016llx CR4: 0x%016llx\n", + vmcb->cr0, vmcb->cr3, vmcb->cr4); + panic_printk("EFER: 0x%016llx\n", vmcb->efer); +} + +void vcpu_vendor_get_io_intercept(struct vcpu_io_intercept *io) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + u64 exitinfo = vmcb->exitinfo1; + + /* parse exit info for I/O instructions (see APM, 15.10.2 ) */ + io->port = (exitinfo >> 16) & 0xFFFF; + io->size = (exitinfo >> 4) & 0x7; + io->in = !!(exitinfo & 0x1); + io->inst_len = vmcb->exitinfo2 - vmcb->rip; + io->rep_or_str = !!(exitinfo & 0x0c); +} + +void vcpu_vendor_get_mmio_intercept(struct vcpu_mmio_intercept *mmio) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + + mmio->phys_addr = vmcb->exitinfo2; + mmio->is_write = !!(vmcb->exitinfo1 & 0x2); +} + +unsigned long vcpu_vendor_get_guest_cr4(void) +{ + return this_cpu_data()->vmcb.cr4; +} + +void vcpu_handle_exit(struct per_cpu *cpu_data) +{ + struct public_per_cpu *cpu_public = &cpu_data->public; + struct vmcb *vmcb = &cpu_data->vmcb; + bool res = false; + + vmcb->gs.base = read_msr(MSR_GS_BASE); + + /* Restore GS value expected by per_cpu data accessors */ + write_msr(MSR_GS_BASE, (unsigned long)cpu_data); + + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL]++; + /* + * All guest state is marked unmodified; individual handlers must clear + * the bits as needed. + */ + vmcb->clean_bits = 0xffffffff; + + switch (vmcb->exitcode) { + case VMEXIT_INVALID: + panic_printk("FATAL: VM-Entry failure, error %lld\n", + vmcb->exitcode); + break; + case VMEXIT_NMI: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT]++; + /* Temporarily enable GIF to consume pending NMI */ + asm volatile("stgi; clgi" : : : "memory"); + x86_check_events(); + goto vmentry; + case VMEXIT_VMMCALL: + vcpu_handle_hypercall(); + goto vmentry; + case VMEXIT_CR0_SEL_WRITE: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_CR]++; + if (svm_handle_cr(cpu_data)) + goto vmentry; + break; + case VMEXIT_CPUID: + vcpu_handle_cpuid(); + goto vmentry; + case VMEXIT_MSR: + if (!vmcb->exitinfo1) + res = vcpu_handle_msr_read(); + else + res = svm_handle_msr_write(cpu_data); + if (res) + goto vmentry; + break; + case VMEXIT_NPF: + if ((vmcb->exitinfo1 & 0x7) == 0x7 && + vmcb->exitinfo2 >= XAPIC_BASE && + vmcb->exitinfo2 < XAPIC_BASE + PAGE_SIZE) { + /* APIC access in non-AVIC mode */ + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_XAPIC]++; + if (svm_handle_apic_access(vmcb)) + goto vmentry; + } else { + /* General MMIO (IOAPIC, PCI etc) */ + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++; + if (vcpu_handle_mmio_access()) + goto vmentry; + } + break; + case VMEXIT_IOIO: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_PIO]++; + if (vcpu_handle_io_access()) + goto vmentry; + break; + case VMEXIT_EXCEPTION_DB: + case VMEXIT_EXCEPTION_AC: + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_EXCEPTION]++; + /* Reinject exception, including error code if needed. */ + vmcb->eventinj = (vmcb->exitcode - VMEXIT_EXCEPTION_DE) | + SVM_EVENTINJ_EXCEPTION | SVM_EVENTINJ_VALID; + if (vmcb->exitcode == VMEXIT_EXCEPTION_AC) { + vmcb->eventinj |= SVM_EVENTINJ_ERR_VALID; + vmcb->eventinj_err = vmcb->exitinfo1; + } + x86_check_events(); + goto vmentry; + /* TODO: Handle VMEXIT_AVIC_NOACCEL and VMEXIT_AVIC_INCOMPLETE_IPI */ + default: + panic_printk("FATAL: Unexpected #VMEXIT, exitcode %llx, " + "exitinfo1 0x%016llx exitinfo2 0x%016llx\n", + vmcb->exitcode, vmcb->exitinfo1, vmcb->exitinfo2); + } + dump_guest_regs(&cpu_data->guest_regs, vmcb); + panic_park(); + +vmentry: + write_msr(MSR_GS_BASE, vmcb->gs.base); +} + +void vcpu_park(void) +{ +#ifdef CONFIG_CRASH_CELL_ON_PANIC + if (this_cpu_public()->failed) { + this_cpu_data()->vmcb.rip = 0; + return; + } +#endif + vcpu_vendor_reset(0); + /* No need to clear VMCB Clean bit: vcpu_vendor_reset() already does + * this. */ + this_cpu_data()->vmcb.n_cr3 = paging_hvirt2phys(parking_pt.root_table); + + vcpu_tlb_flush(); +} + +void vcpu_nmi_handler(void) +{ +} + +void vcpu_tlb_flush(void) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + + if (has_flush_by_asid) + vmcb->tlb_control = SVM_TLB_FLUSH_GUEST; + else + vmcb->tlb_control = SVM_TLB_FLUSH_ALL; +} + +const u8 *vcpu_get_inst_bytes(const struct guest_paging_structures *pg_structs, + unsigned long pc, unsigned int *size) +{ + struct vmcb *vmcb = &this_cpu_data()->vmcb; + unsigned long start; + + if (has_assists) { + if (!*size) + return NULL; + start = vmcb->rip - pc; + if (start < vmcb->bytes_fetched) { + *size = vmcb->bytes_fetched - start; + return &vmcb->guest_bytes[start]; + } else { + return NULL; + } + } else { + return vcpu_map_inst(pg_structs, pc, size); + } +} + +unsigned int vcpu_vendor_get_io_bitmap_pages(void) +{ + return IOPM_PAGES; +} + +#define VCPU_VENDOR_GET_REGISTER(__reg__) \ +u64 vcpu_vendor_get_##__reg__(void) \ +{ \ + return this_cpu_data()->vmcb.__reg__; \ +} + +VCPU_VENDOR_GET_REGISTER(efer); +VCPU_VENDOR_GET_REGISTER(rflags); +VCPU_VENDOR_GET_REGISTER(rip); + +u16 vcpu_vendor_get_cs_attr(void) +{ + /* + * Build the CS segment attributes from the L and D/B extracted from + * the segment attribute field and the CPL from its own field. The + * latter is suggested by the AMD spec (Vol 2, 15.5.1). Present the + * result in Intel format. + */ + u16 l_db = this_cpu_data()->vmcb.cs.attributes & BIT_MASK(10, 9); + + return (this_cpu_data()->vmcb.cpl << 5) | (l_db << 4); +} + +/* GIF must be set for interrupts to be delivered (APMv2, Sect. 15.17) */ +void enable_irq(void) +{ + asm volatile("stgi; sti" : : : "memory"); +} + +/* Jailhouse runs with GIF cleared, so we need to restore this state */ +void disable_irq(void) +{ + asm volatile("cli; clgi" : : : "memory"); +} diff --git a/hypervisor/arch/x86/test-device.c b/hypervisor/arch/x86/test-device.c new file mode 100644 index 0000000000000000000000000000000000000000..d9cee8342157fc7cbb87a2b69e3094f19e95775e --- /dev/null +++ b/hypervisor/arch/x86/test-device.c @@ -0,0 +1,105 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +static unsigned int testdev_mmio_count_regions(struct cell *cell) +{ + return cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE ? 1 : 0; +} + +static enum mmio_result testdev_handle_mmio_access(void *arg, + struct mmio_access *mmio) +{ + void *test_reg = &this_cell()->comm_page.padding[mmio->address]; + + if (mmio->address < 0xff8 || mmio->address > 0x1000 - mmio->size) + goto invalid_access; + + switch (mmio->size) { + case 1: + if (mmio->is_write) + *(u8 *)test_reg = mmio->value; + else + mmio->value = *(u8 *)test_reg; + break; + case 2: + if (mmio->is_write) + *(u16 *)test_reg = mmio->value; + else + mmio->value = *(u16 *)test_reg; + break; + case 4: + if (mmio->is_write) + *(u32 *)test_reg = mmio->value; + else + mmio->value = *(u32 *)test_reg; + break; + case 8: + if (mmio->is_write) + *(u64 *)test_reg = mmio->value; + else + mmio->value = *(u64 *)test_reg; + break; + } + return MMIO_HANDLED; + +invalid_access: + printk("testdev: invalid %s, register %lx, size %d\n", + mmio->is_write ? "write" : "read", mmio->address, mmio->size); + return MMIO_ERROR; +} + +static unsigned long testdev_get_mmio_base(struct cell *cell) +{ + const struct jailhouse_memory *mem; + unsigned int n; + + /* The mmio test page is one page after the COMM_REGION */ + for_each_mem_region(mem, cell->config, n) + if (mem->flags & JAILHOUSE_MEM_COMM_REGION) + return mem->virt_start + PAGE_SIZE; + + return INVALID_PHYS_ADDR; +} + +static int testdev_cell_init(struct cell *cell) +{ + unsigned long mmio_base; + + if (cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE) { + mmio_base = testdev_get_mmio_base(cell); + if (mmio_base == INVALID_PHYS_ADDR) + return trace_error(-EINVAL); + + mmio_region_register(cell, mmio_base, PAGE_SIZE, + testdev_handle_mmio_access, NULL); + } + return 0; +} + +static void testdev_cell_exit(struct cell *cell) +{ + if (cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE) + mmio_region_unregister(cell, testdev_get_mmio_base(cell)); +} + +static int testdev_init(void) +{ + return 0; +} + +DEFINE_UNIT_SHUTDOWN_STUB(testdev); +DEFINE_UNIT(testdev, "Test device"); diff --git a/hypervisor/arch/x86/vcpu.c b/hypervisor/arch/x86/vcpu.c new file mode 100644 index 0000000000000000000000000000000000000000..5dd23d499200f298624ecfed9b57667df652efe4 --- /dev/null +++ b/hypervisor/arch/x86/vcpu.c @@ -0,0 +1,436 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define for_each_pio_region(pio, config, counter) \ + for ((pio) = jailhouse_cell_pio(config), (counter) = 0; \ + (counter) < (config)->num_pio_regions; \ + (pio)++, (counter)++) + +static u8 __attribute__((aligned(PAGE_SIZE))) parking_code[PAGE_SIZE] = { + 0xfa, /* 1: cli */ + 0xf4, /* hlt */ + 0xeb, + 0xfc /* jmp 1b */ +}; + +int vcpu_early_init(void) +{ + int err; + + err = vcpu_vendor_early_init(); + if (err) + return err; + + /* Map guest parking code (shared between cells and CPUs) */ + return paging_create(&parking_pt, paging_hvirt2phys(parking_code), + PAGE_SIZE, 0, PAGE_READONLY_FLAGS | PAGE_FLAG_US, + PAGING_NON_COHERENT | PAGING_NO_HUGE); +} + +/* Can be overridden in vendor-specific code if needed */ +const u8 *vcpu_get_inst_bytes(const struct guest_paging_structures *pg_structs, + unsigned long pc, unsigned int *size) + __attribute__((weak, alias("vcpu_map_inst"))); + +const u8 *vcpu_map_inst(const struct guest_paging_structures *pg_structs, + unsigned long pc, unsigned int *size) +{ + unsigned short bytes_avail; + u8 *page = NULL; + + if (!*size) + goto out_err; + page = paging_get_guest_pages(pg_structs, pc, + 1, PAGE_READONLY_FLAGS); + if (!page) + goto out_err; + + /* Number of bytes available before page boundary */ + bytes_avail = PAGE_SIZE - (pc & PAGE_OFFS_MASK); + if (*size > bytes_avail) + *size = bytes_avail; + + return &page[pc & PAGE_OFFS_MASK]; + +out_err: + return NULL; +} + +static void pio_allow_access(u8 *bm, const struct jailhouse_pio *pio, + bool access) +{ + void (*access_method)(unsigned int, volatile unsigned long*) = + access ? clear_bit : set_bit; + unsigned int length, start_bit = pio->base; + + for (length = pio->length; length > 0; length--, start_bit++) + access_method(start_bit, (unsigned long*)bm); +} + +int vcpu_cell_init(struct cell *cell) +{ + const unsigned int io_bitmap_pages = vcpu_vendor_get_io_bitmap_pages(); + const struct jailhouse_pio *pio; + unsigned int n, pm_timer_addr; + int err; + + cell->arch.io_bitmap = page_alloc(&mem_pool, io_bitmap_pages); + if (!cell->arch.io_bitmap) + return -ENOMEM; + + err = vcpu_vendor_cell_init(cell); + if (err) { + page_free(&mem_pool, cell->arch.io_bitmap, io_bitmap_pages); + return err; + } + + /* initialize io bitmap to trap all accesses */ + memset(cell->arch.io_bitmap, -1, io_bitmap_pages * PAGE_SIZE); + + /* cells have no access to i8042, unless the port is whitelisted */ + cell->arch.pio_i8042_allowed = false; + + for_each_pio_region(pio, cell->config, n) { + pio_allow_access(cell->arch.io_bitmap, pio, true); + + /* moderate i8042 only if the config allows it */ + if (pio->base <= I8042_CMD_REG && + pio->base + pio->length > I8042_CMD_REG) + cell->arch.pio_i8042_allowed = true; + } + + /* but always intercept access to i8042 command register */ + cell->arch.io_bitmap[I8042_CMD_REG / 8] |= 1 << (I8042_CMD_REG % 8); + + if (cell != &root_cell) { + /* + * Shrink PIO access of root cell corresponding to new cell's + * access rights. + */ + for_each_pio_region(pio, cell->config, n) + pio_allow_access(root_cell.arch.io_bitmap, pio, false); + } + + /* permit access to the PM timer if there is any */ + pm_timer_addr = system_config->platform_info.x86.pm_timer_address; + if (pm_timer_addr) + for (n = 0; n < 4; n++, pm_timer_addr++) + cell->arch.io_bitmap[pm_timer_addr / 8] &= + ~(1 << (pm_timer_addr % 8)); + + return 0; +} + +void vcpu_cell_exit(struct cell *cell) +{ + const struct jailhouse_pio *cell_wl, *root_wl; + unsigned int interval_start, interval_end, m, n; + struct jailhouse_pio refund; + + /* Hand back ports to the root cell. But only hand back those ports + * that overlap with the root cell's config. This is done by pairwise + * comparison of the cell's and the root cell's whitelist entries. */ + for_each_pio_region(cell_wl, cell->config, m) + for_each_pio_region(root_wl, root_cell.config, n) { + interval_start = MAX(cell_wl->base, root_wl->base); + interval_end = MIN(cell_wl->base + cell_wl->length, + root_wl->base + root_wl->length); + if (interval_start < interval_end) { + refund.base = interval_start; + refund.length = interval_end - interval_start; + pio_allow_access(root_cell.arch.io_bitmap, + &refund, true); + } + } + + page_free(&mem_pool, cell->arch.io_bitmap, + vcpu_vendor_get_io_bitmap_pages()); + + vcpu_vendor_cell_exit(cell); +} + +void vcpu_handle_hypercall(void) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + u16 cs_attr = vcpu_vendor_get_cs_attr(); + bool long_mode = (vcpu_vendor_get_efer() & EFER_LMA) && + (cs_attr & VCPU_CS_L); + unsigned long arg_mask = long_mode ? (u64)-1 : (u32)-1; + unsigned long code = guest_regs->rax; + unsigned int cpu_id = this_cpu_id(); + + vcpu_skip_emulated_instruction(X86_INST_LEN_HYPERCALL); + + if ((!long_mode && (vcpu_vendor_get_rflags() & X86_RFLAGS_VM)) || + (cs_attr & VCPU_CS_DPL_MASK) != 0) { + guest_regs->rax = -EPERM; + return; + } + + guest_regs->rax = hypercall(code, guest_regs->rdi & arg_mask, + guest_regs->rsi & arg_mask); + if ((int)guest_regs->rax == -ENOSYS) + printk("CPU %d: Unknown hypercall %ld, RIP: 0x%016llx\n", + cpu_id, code, + vcpu_vendor_get_rip() - X86_INST_LEN_HYPERCALL); + + if (code == JAILHOUSE_HC_DISABLE && guest_regs->rax == 0) { + /* + * Restore full per_cpu region access so that we can switch + * back to the common stack mapping and to Linux page tables. + */ + paging_map_all_per_cpu(cpu_id, true); + + /* + * Switch the stack back to the common mapping. + * Preexisting pointers to the stack remain valid until we also + * switch the page tables in arch_cpu_restore. + */ + asm volatile( + "sub %0,%%rsp" + : : "g" (LOCAL_CPU_BASE - + (unsigned long)per_cpu(cpu_id))); + + vcpu_deactivate_vmm(); + } +} + +bool vcpu_handle_io_access(void) +{ + struct vcpu_io_intercept io; + int result = 0; + + vcpu_vendor_get_io_intercept(&io); + + /* string and REP-prefixed instructions are not supported */ + if (io.rep_or_str) + goto invalid_access; + + result = x86_pci_config_handler(io.port, io.in, io.size); + if (result == 0) + result = i8042_access_handler(io.port, io.in, io.size); + + /* Also ignore byte access to port 80, often used for delaying IO. */ + if (result == 1 || (io.port == 0x80 && io.size == 1)) { + vcpu_skip_emulated_instruction(io.inst_len); + return true; + } + +invalid_access: + /* report only unhandled access failures */ + if (result == 0) + panic_printk("FATAL: Invalid PIO %s, port: %x size: %d\n", + io.in ? "read" : "write", io.port, io.size); + return false; +} + +bool vcpu_handle_mmio_access(void) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + enum mmio_result result = MMIO_UNHANDLED; + struct guest_paging_structures pg_structs; + struct mmio_access mmio = {.size = 0}; + struct vcpu_mmio_intercept intercept; + struct mmio_instruction inst; + unsigned long *reg; + + vcpu_vendor_get_mmio_intercept(&intercept); + + vcpu_get_guest_paging_structs(&pg_structs); + + inst = x86_mmio_parse(&pg_structs, intercept.is_write); + if (!inst.inst_len) + goto invalid_access; + + mmio.is_write = intercept.is_write; + if (mmio.is_write) + mmio.value = inst.out_val; + + mmio.address = intercept.phys_addr; + mmio.size = inst.access_size; + + result = mmio_handle_access(&mmio); + if (result == MMIO_HANDLED) { + if (!mmio.is_write) { + reg= &guest_regs->by_index[inst.in_reg_num]; + *reg = (*reg & inst.reg_preserve_mask) | mmio.value; + } + vcpu_skip_emulated_instruction(inst.inst_len); + return true; + } + +invalid_access: + /* report only unhandled access failures */ + if (result == MMIO_UNHANDLED) + panic_printk("FATAL: Invalid MMIO/RAM %s, " + "addr: 0x%016llx size: %d\n", + intercept.is_write ? "write" : "read", + intercept.phys_addr, mmio.size); + return false; +} + +bool vcpu_handle_msr_read(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + + switch (cpu_data->guest_regs.rcx) { + case MSR_X2APIC_BASE ... MSR_X2APIC_END: + x2apic_handle_read(); + break; + case MSR_IA32_PAT: + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + set_rdmsr_value(&cpu_data->guest_regs, cpu_data->pat); + break; + case MSR_IA32_MTRR_DEF_TYPE: + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + set_rdmsr_value(&cpu_data->guest_regs, + cpu_data->mtrr_def_type); + break; + default: + panic_printk("FATAL: Unhandled MSR read: %lx\n", + cpu_data->guest_regs.rcx); + return false; + } + + vcpu_skip_emulated_instruction(X86_INST_LEN_WRMSR); + return true; +} + +bool vcpu_handle_msr_write(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + unsigned int bit_pos, pa; + unsigned long val; + + switch (cpu_data->guest_regs.rcx) { + case MSR_X2APIC_BASE ... MSR_X2APIC_END: + if (!x2apic_handle_write()) + return false; + break; + case MSR_IA32_PAT: + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + val = get_wrmsr_value(&cpu_data->guest_regs); + for (bit_pos = 0; bit_pos < 64; bit_pos += 8) { + pa = (val >> bit_pos) & 0xff; + /* filter out reserved memory types */ + if (pa == 2 || pa == 3 || pa > 7) { + printk("FATAL: Invalid PAT value: %lx\n", val); + return false; + } + } + cpu_data->pat = val; + if (cpu_data->mtrr_def_type & MTRR_ENABLE) + vcpu_vendor_set_guest_pat(val); + break; + case MSR_IA32_MTRR_DEF_TYPE: + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + /* + * This only emulates the difference between MTRRs enabled + * and disabled. When disabled, we turn off all caching by + * setting the guest PAT to 0. When enabled, guest PAT + + * host-controlled MTRRs define the guest's memory types. + */ + val = get_wrmsr_value(&cpu_data->guest_regs); + cpu_data->mtrr_def_type &= ~MTRR_ENABLE; + cpu_data->mtrr_def_type |= val & MTRR_ENABLE; + vcpu_vendor_set_guest_pat((val & MTRR_ENABLE) ? + cpu_data->pat : 0); + break; + default: + panic_printk("FATAL: Unhandled MSR write: %lx\n", + cpu_data->guest_regs.rcx); + return false; + } + + vcpu_skip_emulated_instruction(X86_INST_LEN_WRMSR); + return true; +} + +void vcpu_handle_cpuid(void) +{ + static const char signature[12] = "Jailhouse"; + union registers *guest_regs = &this_cpu_data()->guest_regs; + u32 function = guest_regs->rax; + + this_cpu_data()->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_CPUID]++; + + switch (function) { + case JAILHOUSE_CPUID_SIGNATURE: + guest_regs->rax = JAILHOUSE_CPUID_FEATURES; + guest_regs->rbx = *(u32 *)signature; + guest_regs->rcx = *(u32 *)(signature + 4); + guest_regs->rdx = *(u32 *)(signature + 8); + break; + case JAILHOUSE_CPUID_FEATURES: + guest_regs->rax = 0; + guest_regs->rbx = 0; + guest_regs->rcx = 0; + guest_regs->rdx = 0; + break; + default: + /* clear upper 32 bits of the involved registers */ + guest_regs->rax &= 0xffffffff; + guest_regs->rbx &= 0xffffffff; + guest_regs->rcx &= 0xffffffff; + guest_regs->rdx &= 0xffffffff; + + cpuid((u32 *)&guest_regs->rax, (u32 *)&guest_regs->rbx, + (u32 *)&guest_regs->rcx, (u32 *)&guest_regs->rdx); + if (function == 0x01) { + if (this_cell() != &root_cell) { + guest_regs->rcx &= ~X86_FEATURE_VMX; + guest_regs->rcx |= X86_FEATURE_HYPERVISOR; + } + + guest_regs->rcx &= ~X86_FEATURE_OSXSAVE; + if (vcpu_vendor_get_guest_cr4() & X86_CR4_OSXSAVE) + guest_regs->rcx |= X86_FEATURE_OSXSAVE; + } else if (function == 0x80000001) { + if (this_cell() != &root_cell) + guest_regs->rcx &= ~X86_FEATURE_SVM; + } + break; + } + + vcpu_skip_emulated_instruction(X86_INST_LEN_CPUID); +} + +void vcpu_reset(unsigned int sipi_vector) +{ + struct per_cpu *cpu_data = this_cpu_data(); + + vcpu_vendor_reset(sipi_vector); + + memset(&cpu_data->guest_regs, 0, sizeof(cpu_data->guest_regs)); + + if (sipi_vector == APIC_BSP_PSEUDO_SIPI) { + cpu_data->pat = PAT_RESET_VALUE; + cpu_data->mtrr_def_type &= ~MTRR_ENABLE; + vcpu_vendor_set_guest_pat(0); + } +} diff --git a/hypervisor/arch/x86/vmx-vmexit.S b/hypervisor/arch/x86/vmx-vmexit.S new file mode 100644 index 0000000000000000000000000000000000000000..2080497824c4b23d2c50078db8761d681df9e273 --- /dev/null +++ b/hypervisor/arch/x86/vmx-vmexit.S @@ -0,0 +1,58 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +/* VMX VM-exit handling */ + .globl vmx_vmexit +vmx_vmexit: + push %rax + push %rcx + push %rdx + push %rbx + sub $8,%rsp /* placeholder for rsp */ + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + mov $LOCAL_CPU_BASE_ASM,%rdi + call vcpu_handle_exit + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + add $8,%rsp + pop %rbx + pop %rdx + pop %rcx + pop %rax + + vmresume + + jmp vmx_entry_failure diff --git a/hypervisor/arch/x86/vmx.c b/hypervisor/arch/x86/vmx.c new file mode 100644 index 0000000000000000000000000000000000000000..f610e5078e9da54b0c89280a3090dc1f10cd2f9b --- /dev/null +++ b/hypervisor/arch/x86/vmx.c @@ -0,0 +1,1255 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CR0_IDX 0 +#define CR4_IDX 1 + +#define PIO_BITMAP_PAGES 2 + +static const struct segment invalid_seg = { + .access_rights = 0x10000 +}; + +/* bit cleared: direct access allowed */ +// TODO: convert to whitelist +static u8 __attribute__((aligned(PAGE_SIZE))) msr_bitmap[][0x2000/8] = { + [ VMX_MSR_BMP_0000_READ ] = { + [ 0/8 ... 0x26f/8 ] = 0, + [ 0x270/8 ... 0x277/8 ] = 0x80, /* 0x277 */ + [ 0x278/8 ... 0x2f7/8 ] = 0, + [ 0x2f8/8 ... 0x2ff/8 ] = 0x80, /* 0x2ff */ + [ 0x300/8 ... 0x7ff/8 ] = 0, + [ 0x800/8 ... 0x807/8 ] = 0x0c, /* 0x802, 0x803 */ + [ 0x808/8 ... 0x80f/8 ] = 0xa5, /* 0x808, 0x80a, 0x80d, 0x80f */ + [ 0x810/8 ... 0x817/8 ] = 0xff, /* 0x810 - 0x817 */ + [ 0x818/8 ... 0x81f/8 ] = 0xff, /* 0x818 - 0x81f */ + [ 0x820/8 ... 0x827/8 ] = 0xff, /* 0x820 - 0x827 */ + [ 0x828/8 ... 0x82f/8 ] = 0x81, /* 0x828, 0x82f */ + [ 0x830/8 ... 0x837/8 ] = 0xfd, /* 0x830, 0x832 - 0x837 */ + [ 0x838/8 ... 0x83f/8 ] = 0x43, /* 0x838, 0x839, 0x83e */ + [ 0x840/8 ... 0x1fff/8 ] = 0, + }, + [ VMX_MSR_BMP_C000_READ ] = { + [ 0/8 ... 0x1fff/8 ] = 0, + }, + [ VMX_MSR_BMP_0000_WRITE ] = { + [ 0/8 ... 0x17/8 ] = 0, + [ 0x18/8 ... 0x1f/8 ] = 0x08, /* 0x01b */ + [ 0x20/8 ... 0x1ff/8 ] = 0, + [ 0x200/8 ... 0x277/8 ] = 0xff, /* 0x200 - 0x277 */ + [ 0x278/8 ... 0x2f7/8 ] = 0, + [ 0x2f8/8 ... 0x2ff/8 ] = 0x80, /* 0x2ff */ + [ 0x300/8 ... 0x387/8 ] = 0, + [ 0x388/8 ... 0x38f/8 ] = 0x80, /* 0x38f */ + [ 0x390/8 ... 0x7ff/8 ] = 0, + [ 0x808/8 ... 0x80f/8 ] = 0x89, /* 0x808, 0x80b, 0x80f */ + [ 0x810/8 ... 0x827/8 ] = 0, + [ 0x828/8 ... 0x82f/8 ] = 0x81, /* 0x828, 0x82f */ + [ 0x830/8 ... 0x837/8 ] = 0xfd, /* 0x830, 0x832 - 0x837 */ + [ 0x838/8 ... 0x83f/8 ] = 0xc1, /* 0x838, 0x83e, 0x83f */ + [ 0x840/8 ... 0xd8f/8 ] = 0xff, /* esp. 0xc80 - 0xd8f */ + [ 0xd90/8 ... 0x1fff/8 ] = 0, + }, + [ VMX_MSR_BMP_C000_WRITE ] = { + [ 0/8 ... 0x1fff/8 ] = 0, + }, +}; + +/* Special access page to trap guest's attempts of accessing APIC in xAPIC mode */ +static u8 __attribute__((aligned(PAGE_SIZE))) apic_access_page[PAGE_SIZE]; +static struct paging ept_paging[EPT_PAGE_DIR_LEVELS]; +static u32 secondary_exec_addon; +static unsigned long cr_maybe1[2], cr_required1[2]; + +static bool vmxon(void) +{ + unsigned long vmxon_addr; + u8 ok; + + vmxon_addr = paging_hvirt2phys(&per_cpu(this_cpu_id())->vmxon_region); + asm volatile( + "vmxon (%1)\n\t" + "seta %0" + : "=rm" (ok) + : "r" (&vmxon_addr), "m" (vmxon_addr) + : "memory", "cc"); + return ok; +} + +static bool vmcs_clear(void) +{ + unsigned long vmcs_addr; + u8 ok; + + vmcs_addr = paging_hvirt2phys(&per_cpu(this_cpu_id())->vmcs); + asm volatile( + "vmclear (%1)\n\t" + "seta %0" + : "=qm" (ok) + : "r" (&vmcs_addr), "m" (vmcs_addr) + : "memory", "cc"); + return ok; +} + +static bool vmcs_load(void) +{ + unsigned long vmcs_addr; + u8 ok; + + vmcs_addr = paging_hvirt2phys(&per_cpu(this_cpu_id())->vmcs); + asm volatile( + "vmptrld (%1)\n\t" + "seta %0" + : "=qm" (ok) + : "r" (&vmcs_addr), "m" (vmcs_addr) + : "memory", "cc"); + return ok; +} + +static inline unsigned long vmcs_read64(unsigned long field) +{ + unsigned long value; + + asm volatile("vmread %1,%0" : "=r" (value) : "r" (field) : "cc"); + return value; +} + +static inline u16 vmcs_read16(unsigned long field) +{ + return vmcs_read64(field); +} + +static inline u32 vmcs_read32(unsigned long field) +{ + return vmcs_read64(field); +} + +static bool vmcs_write64(unsigned long field, unsigned long val) +{ + u8 ok; + + asm volatile( + "vmwrite %1,%2\n\t" + "setnz %0" + : "=qm" (ok) + : "r" (val), "r" (field) + : "cc"); + if (!ok) + printk("FATAL: vmwrite %08lx failed, error %d, caller %p\n", + field, vmcs_read32(VM_INSTRUCTION_ERROR), + __builtin_return_address(0)); + return ok; +} + +static bool vmcs_write16(unsigned long field, u16 value) +{ + return vmcs_write64(field, value); +} + +static bool vmcs_write32(unsigned long field, u32 value) +{ + return vmcs_write64(field, value); +} + +static bool vmx_define_cr_restrictions(unsigned int cr_idx, + unsigned long maybe1, + unsigned long required1) +{ + if (!cr_maybe1[cr_idx]) { + cr_maybe1[cr_idx] = maybe1; + cr_required1[cr_idx] = required1; + return true; + } + + return cr_maybe1[cr_idx] == maybe1 && + cr_required1[cr_idx] == required1; +} + +static int vmx_check_features(void) +{ + unsigned long vmx_proc_ctrl, vmx_proc_ctrl2, ept_cap; + unsigned long vmx_pin_ctrl, vmx_basic, maybe1, required1; + unsigned long vmx_entry_ctrl, vmx_exit_ctrl; + + if (!(cpuid_ecx(1, 0) & X86_FEATURE_VMX)) + return trace_error(-ENODEV); + + vmx_basic = read_msr(MSR_IA32_VMX_BASIC); + + /* require VMCS size <= PAGE_SIZE, + * VMCS memory access type == write back and + * availability of TRUE_*_CTLS */ + if (((vmx_basic >> 32) & 0x1fff) > PAGE_SIZE || + ((vmx_basic >> 50) & 0xf) != EPT_TYPE_WRITEBACK || + !(vmx_basic & (1UL << 55))) + return trace_error(-EIO); + + /* require NMI exiting and preemption timer support */ + vmx_pin_ctrl = read_msr(MSR_IA32_VMX_PINBASED_CTLS) >> 32; + if (!(vmx_pin_ctrl & PIN_BASED_NMI_EXITING) || + !(vmx_pin_ctrl & PIN_BASED_VMX_PREEMPTION_TIMER)) + return trace_error(-EIO); + + /* require I/O and MSR bitmap as well as secondary controls support */ + vmx_proc_ctrl = read_msr(MSR_IA32_VMX_PROCBASED_CTLS) >> 32; + if (!(vmx_proc_ctrl & CPU_BASED_USE_IO_BITMAPS) || + !(vmx_proc_ctrl & CPU_BASED_USE_MSR_BITMAPS) || + !(vmx_proc_ctrl & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) + return trace_error(-EIO); + + /* require disabling of CR3 access interception */ + vmx_proc_ctrl = read_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + if (vmx_proc_ctrl & + (CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING)) + return trace_error(-EIO); + + /* require APIC access, EPT and unrestricted guest mode support */ + vmx_proc_ctrl2 = read_msr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32; + ept_cap = read_msr(MSR_IA32_VMX_EPT_VPID_CAP); + if (!(vmx_proc_ctrl2 & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) || + !(vmx_proc_ctrl2 & SECONDARY_EXEC_ENABLE_EPT) || + (ept_cap & EPT_MANDATORY_FEATURES) != EPT_MANDATORY_FEATURES || + !(ept_cap & (EPT_INVEPT_SINGLE | EPT_INVEPT_GLOBAL)) || + !(vmx_proc_ctrl2 & SECONDARY_EXEC_UNRESTRICTED_GUEST)) + return trace_error(-EIO); + + /* require RDTSCP, INVPCID, XSAVES, TPAUSE/UMONITOR/UMWAIT if present + * in CPUID */ + if (cpuid_edx(0x80000001, 0) & X86_FEATURE_RDTSCP) + secondary_exec_addon |= SECONDARY_EXEC_RDTSCP; + if (cpuid_ebx(0x07, 0) & X86_FEATURE_INVPCID) + secondary_exec_addon |= SECONDARY_EXEC_INVPCID; + if (cpuid_eax(0x0d, 1) & X86_FEATURE_XSAVES) + secondary_exec_addon |= SECONDARY_EXEC_XSAVES; + if (cpuid_ecx(0x07, 0) & X86_FEATURE_WAITPKG) + secondary_exec_addon |= SECONDARY_EXEC_USR_WAIT_PAUSE; + if ((vmx_proc_ctrl2 & secondary_exec_addon) != secondary_exec_addon) + return trace_error(-EIO); + + /* require PAT and EFER save/restore */ + vmx_entry_ctrl = read_msr(MSR_IA32_VMX_ENTRY_CTLS) >> 32; + vmx_exit_ctrl = read_msr(MSR_IA32_VMX_EXIT_CTLS) >> 32; + if (!(vmx_entry_ctrl & VM_ENTRY_LOAD_IA32_PAT) || + !(vmx_entry_ctrl & VM_ENTRY_LOAD_IA32_EFER) || + !(vmx_exit_ctrl & VM_EXIT_SAVE_IA32_PAT) || + !(vmx_exit_ctrl & VM_EXIT_LOAD_IA32_PAT) || + !(vmx_exit_ctrl & VM_EXIT_SAVE_IA32_EFER) || + !(vmx_exit_ctrl & VM_EXIT_LOAD_IA32_EFER)) + return trace_error(-EIO); + + /* require activity state HLT */ + if (!(read_msr(MSR_IA32_VMX_MISC) & VMX_MISC_ACTIVITY_HLT)) + return trace_error(-EIO); + + /* + * Retrieve/validate restrictions on CR0 + * + * In addition to what the VMX MSRs tell us, make sure that + * - NW and CD are kept off as they are not updated on VM exit and we + * don't want them enabled for performance reasons while in root mode + * - PE and PG can be freely chosen (by the guest) because we demand + * unrestricted guest mode support anyway + * - ET is always on (architectural requirement) + */ + maybe1 = read_msr(MSR_IA32_VMX_CR0_FIXED1) & + ~(X86_CR0_NW | X86_CR0_CD); + required1 = (read_msr(MSR_IA32_VMX_CR0_FIXED0) & + ~(X86_CR0_PE | X86_CR0_PG)) | X86_CR0_ET; + if (!vmx_define_cr_restrictions(CR0_IDX, maybe1, required1)) + return trace_error(-EIO); + + /* Retrieve/validate restrictions on CR4 */ + maybe1 = read_msr(MSR_IA32_VMX_CR4_FIXED1); + required1 = read_msr(MSR_IA32_VMX_CR4_FIXED0); + if (!vmx_define_cr_restrictions(CR4_IDX, maybe1, required1)) + return trace_error(-EIO); + + return 0; +} + +static void ept_set_next_pt(pt_entry_t pte, unsigned long next_pt) +{ + *pte = (next_pt & BIT_MASK(51, 12)) | EPT_FLAG_READ | EPT_FLAG_WRITE | + EPT_FLAG_EXECUTE; +} + +int vcpu_vendor_early_init(void) +{ + unsigned int n; + int err; + + err = vmx_check_features(); + if (err) + return err; + + /* derive ept_paging from very similar x86_64_paging */ + memcpy(ept_paging, x86_64_paging, sizeof(ept_paging)); + for (n = 0; n < EPT_PAGE_DIR_LEVELS; n++) + ept_paging[n].set_next_pt = ept_set_next_pt; + if (!(read_msr(MSR_IA32_VMX_EPT_VPID_CAP) & EPT_1G_PAGES)) + ept_paging[1].page_size = 0; + if (!(read_msr(MSR_IA32_VMX_EPT_VPID_CAP) & EPT_2M_PAGES)) + ept_paging[2].page_size = 0; + + parking_pt.root_paging = ept_paging; + + if (using_x2apic) { + /* allow direct x2APIC access except for ICR writes */ + memset(&msr_bitmap[VMX_MSR_BMP_0000_READ][MSR_X2APIC_BASE/8], + 0, (MSR_X2APIC_END - MSR_X2APIC_BASE + 1)/8); + memset(&msr_bitmap[VMX_MSR_BMP_0000_WRITE][MSR_X2APIC_BASE/8], + 0, (MSR_X2APIC_END - MSR_X2APIC_BASE + 1)/8); + msr_bitmap[VMX_MSR_BMP_0000_WRITE][MSR_X2APIC_ICR/8] = 0x01; + } + + return vcpu_cell_init(&root_cell); +} + +unsigned long arch_paging_gphys2phys(unsigned long gphys, unsigned long flags) +{ + return paging_virt2phys(&this_cell()->arch.vmx.ept_structs, gphys, + flags); +} + +int vcpu_vendor_cell_init(struct cell *cell) +{ + /* build root EPT of cell */ + cell->arch.vmx.ept_structs.root_paging = ept_paging; + cell->arch.vmx.ept_structs.root_table = + (page_table_t)cell->arch.root_table_page; + + /* Map the special APIC access page into the guest's physical address + * space at the default address (XAPIC_BASE) */ + return paging_create(&cell->arch.vmx.ept_structs, + paging_hvirt2phys(apic_access_page), + PAGE_SIZE, XAPIC_BASE, + EPT_FLAG_READ | EPT_FLAG_WRITE | EPT_FLAG_WB_TYPE, + PAGING_NON_COHERENT | PAGING_NO_HUGE); +} + +int vcpu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + u64 phys_start = mem->phys_start; + unsigned long access_flags = EPT_FLAG_WB_TYPE; + unsigned long paging_flags = PAGING_NON_COHERENT | PAGING_HUGE; + + if (mem->flags & JAILHOUSE_MEM_READ) + access_flags |= EPT_FLAG_READ; + if (mem->flags & JAILHOUSE_MEM_WRITE) + access_flags |= EPT_FLAG_WRITE; + if (mem->flags & JAILHOUSE_MEM_EXECUTE) + access_flags |= EPT_FLAG_EXECUTE; + if (mem->flags & JAILHOUSE_MEM_COMM_REGION) + phys_start = paging_hvirt2phys(&cell->comm_page); + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_HUGE; + + return paging_create(&cell->arch.vmx.ept_structs, phys_start, mem->size, + mem->virt_start, access_flags, paging_flags); +} + +int vcpu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + return paging_destroy(&cell->arch.vmx.ept_structs, mem->virt_start, + mem->size, PAGING_NON_COHERENT); +} + +void vcpu_vendor_cell_exit(struct cell *cell) +{ + paging_destroy(&cell->arch.vmx.ept_structs, XAPIC_BASE, PAGE_SIZE, + PAGING_NON_COHERENT); +} + +void vcpu_tlb_flush(void) +{ + unsigned long ept_cap = read_msr(MSR_IA32_VMX_EPT_VPID_CAP); + struct { + u64 eptp; + u64 reserved; + } descriptor; + u64 type; + u8 ok; + + descriptor.reserved = 0; + if (ept_cap & EPT_INVEPT_SINGLE) { + type = VMX_INVEPT_SINGLE; + descriptor.eptp = vmcs_read64(EPT_POINTER); + } else { + type = VMX_INVEPT_GLOBAL; + descriptor.eptp = 0; + } + asm volatile( + "invept (%1),%2\n\t" + "seta %0\n\t" + : "=qm" (ok) + : "r" (&descriptor), "r" (type) + : "memory", "cc"); + + if (!ok) { + panic_printk("FATAL: invept failed, error %d\n", + vmcs_read32(VM_INSTRUCTION_ERROR)); + panic_stop(); + } +} + +static bool vmx_set_guest_cr(unsigned int cr_idx, unsigned long val) +{ + bool ok = true; + + if (cr_idx) + val |= X86_CR4_VMXE; /* keeps the hypervisor visible */ + + ok &= vmcs_write64(cr_idx ? GUEST_CR4 : GUEST_CR0, + (val & cr_maybe1[cr_idx]) | cr_required1[cr_idx]); + ok &= vmcs_write64(cr_idx ? CR4_READ_SHADOW : CR0_READ_SHADOW, val); + ok &= vmcs_write64(cr_idx ? CR4_GUEST_HOST_MASK : CR0_GUEST_HOST_MASK, + cr_required1[cr_idx] | ~cr_maybe1[cr_idx]); + + return ok; +} + +unsigned long vcpu_vendor_get_guest_cr4(void) +{ + unsigned long host_mask = cr_required1[CR4_IDX] | ~cr_maybe1[CR4_IDX]; + + return (vmcs_read64(CR4_READ_SHADOW) & host_mask) | + (vmcs_read64(GUEST_CR4) & ~host_mask); +} + +static bool vmx_set_cell_config(void) +{ + struct cell *cell = this_cell(); + u8 *io_bitmap; + bool ok = true; + + io_bitmap = cell->arch.io_bitmap; + ok &= vmcs_write64(IO_BITMAP_A, paging_hvirt2phys(io_bitmap)); + ok &= vmcs_write64(IO_BITMAP_B, + paging_hvirt2phys(io_bitmap + PAGE_SIZE)); + + ok &= vmcs_write64(EPT_POINTER, + paging_hvirt2phys(cell->arch.vmx.ept_structs.root_table) | + EPT_TYPE_WRITEBACK | EPT_PAGE_WALK_LEN); + + return ok; +} + +static bool vmx_set_guest_segment(const struct segment *seg, + unsigned long selector_field) +{ + bool ok = true; + + ok &= vmcs_write16(selector_field, seg->selector); + ok &= vmcs_write64(selector_field + GUEST_SEG_BASE, seg->base); + ok &= vmcs_write32(selector_field + GUEST_SEG_LIMIT, seg->limit); + ok &= vmcs_write32(selector_field + GUEST_SEG_AR_BYTES, + seg->access_rights); + return ok; +} + +static bool vmcs_setup(void) +{ + struct per_cpu *cpu_data = this_cpu_data(); + struct desc_table_reg dtr; + unsigned long val; + bool ok = true; + + ok &= vmcs_write64(HOST_CR0, read_cr0()); + ok &= vmcs_write64(HOST_CR3, read_cr3()); + ok &= vmcs_write64(HOST_CR4, read_cr4()); + + ok &= vmcs_write16(HOST_CS_SELECTOR, GDT_DESC_CODE * 8); + ok &= vmcs_write16(HOST_DS_SELECTOR, 0); + ok &= vmcs_write16(HOST_ES_SELECTOR, 0); + ok &= vmcs_write16(HOST_SS_SELECTOR, 0); + ok &= vmcs_write16(HOST_FS_SELECTOR, 0); + ok &= vmcs_write16(HOST_GS_SELECTOR, 0); + ok &= vmcs_write16(HOST_TR_SELECTOR, GDT_DESC_TSS * 8); + + ok &= vmcs_write64(HOST_FS_BASE, 0); + ok &= vmcs_write64(HOST_GS_BASE, read_msr(MSR_GS_BASE)); + ok &= vmcs_write64(HOST_TR_BASE, 0); + + read_gdtr(&dtr); + ok &= vmcs_write64(HOST_GDTR_BASE, dtr.base); + read_idtr(&dtr); + ok &= vmcs_write64(HOST_IDTR_BASE, dtr.base); + + ok &= vmcs_write64(HOST_IA32_PAT, read_msr(MSR_IA32_PAT)); + ok &= vmcs_write64(HOST_IA32_EFER, EFER_LMA | EFER_LME); + + ok &= vmcs_write32(HOST_IA32_SYSENTER_CS, 0); + ok &= vmcs_write64(HOST_IA32_SYSENTER_EIP, 0); + ok &= vmcs_write64(HOST_IA32_SYSENTER_ESP, 0); + + ok &= vmcs_write64(HOST_RSP, (unsigned long)cpu_data->stack + + sizeof(cpu_data->stack)); + + /* Set function executed when trapping to the hypervisor */ + ok &= vmcs_write64(HOST_RIP, (unsigned long)vmx_vmexit); + + ok &= vmx_set_guest_cr(CR0_IDX, cpu_data->linux_cr0); + ok &= vmx_set_guest_cr(CR4_IDX, cpu_data->linux_cr4); + + ok &= vmcs_write64(GUEST_CR3, cpu_data->linux_cr3); + + ok &= vmx_set_guest_segment(&cpu_data->linux_cs, GUEST_CS_SELECTOR); + ok &= vmx_set_guest_segment(&cpu_data->linux_ds, GUEST_DS_SELECTOR); + ok &= vmx_set_guest_segment(&cpu_data->linux_es, GUEST_ES_SELECTOR); + ok &= vmx_set_guest_segment(&cpu_data->linux_fs, GUEST_FS_SELECTOR); + ok &= vmx_set_guest_segment(&cpu_data->linux_gs, GUEST_GS_SELECTOR); + ok &= vmx_set_guest_segment(&invalid_seg, GUEST_SS_SELECTOR); + ok &= vmx_set_guest_segment(&cpu_data->linux_tss, GUEST_TR_SELECTOR); + ok &= vmx_set_guest_segment(&invalid_seg, GUEST_LDTR_SELECTOR); + + ok &= vmcs_write64(GUEST_GDTR_BASE, cpu_data->linux_gdtr.base); + ok &= vmcs_write32(GUEST_GDTR_LIMIT, cpu_data->linux_gdtr.limit); + ok &= vmcs_write64(GUEST_IDTR_BASE, cpu_data->linux_idtr.base); + ok &= vmcs_write32(GUEST_IDTR_LIMIT, cpu_data->linux_idtr.limit); + + ok &= vmcs_write64(GUEST_RFLAGS, 0x02); + ok &= vmcs_write64(GUEST_RSP, cpu_data->linux_sp + + (NUM_ENTRY_REGS + 1) * sizeof(unsigned long)); + ok &= vmcs_write64(GUEST_RIP, cpu_data->linux_ip); + + ok &= vmcs_write32(GUEST_SYSENTER_CS, + read_msr(MSR_IA32_SYSENTER_CS)); + ok &= vmcs_write64(GUEST_SYSENTER_EIP, + read_msr(MSR_IA32_SYSENTER_EIP)); + ok &= vmcs_write64(GUEST_SYSENTER_ESP, + read_msr(MSR_IA32_SYSENTER_ESP)); + + ok &= vmcs_write64(GUEST_DR7, 0x00000400); + ok &= vmcs_write64(GUEST_IA32_DEBUGCTL, 0); + + ok &= vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); + ok &= vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); + ok &= vmcs_write64(GUEST_PENDING_DBG_EXCEPTIONS, 0); + + ok &= vmcs_write64(GUEST_IA32_PAT, cpu_data->pat); + ok &= vmcs_write64(GUEST_IA32_EFER, cpu_data->linux_efer); + + ok &= vmcs_write64(VMCS_LINK_POINTER, -1UL); + ok &= vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); + + val = read_msr(MSR_IA32_VMX_PINBASED_CTLS); + val |= PIN_BASED_NMI_EXITING; + ok &= vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, val); + + ok &= vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, 0); + + val = read_msr(MSR_IA32_VMX_PROCBASED_CTLS); + val |= CPU_BASED_USE_IO_BITMAPS | CPU_BASED_USE_MSR_BITMAPS | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + val &= ~(CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING); + ok &= vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, val); + + ok &= vmcs_write64(MSR_BITMAP, paging_hvirt2phys(msr_bitmap)); + + val = read_msr(MSR_IA32_VMX_PROCBASED_CTLS2); + val |= SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | + SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_UNRESTRICTED_GUEST | + secondary_exec_addon; + ok &= vmcs_write32(SECONDARY_VM_EXEC_CONTROL, val); + + ok &= vmcs_write64(APIC_ACCESS_ADDR, + paging_hvirt2phys(apic_access_page)); + + ok &= vmx_set_cell_config(); + + /* see vmx_handle_exception_nmi for the interception reason */ + ok &= vmcs_write32(EXCEPTION_BITMAP, + (1 << DB_VECTOR) | (1 << AC_VECTOR)); + + val = read_msr(MSR_IA32_VMX_EXIT_CTLS); + val |= VM_EXIT_HOST_ADDR_SPACE_SIZE | + VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT | + VM_EXIT_SAVE_IA32_EFER | VM_EXIT_LOAD_IA32_EFER; + ok &= vmcs_write32(VM_EXIT_CONTROLS, val); + + ok &= vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); + ok &= vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); + ok &= vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); + + val = read_msr(MSR_IA32_VMX_ENTRY_CTLS); + val |= VM_ENTRY_IA32E_MODE | VM_ENTRY_LOAD_IA32_PAT | + VM_ENTRY_LOAD_IA32_EFER; + ok &= vmcs_write32(VM_ENTRY_CONTROLS, val); + + ok &= vmcs_write64(CR4_GUEST_HOST_MASK, 0); + + ok &= vmcs_write32(CR3_TARGET_COUNT, 0); + + return ok; +} + +int vcpu_init(struct per_cpu *cpu_data) +{ + unsigned long feature_ctrl, mask; + u32 revision_id; + int err; + + /* make sure all perf counters are off */ + if ((cpuid_eax(0x0a, 0) & 0xff) > 0) + write_msr(MSR_IA32_PERF_GLOBAL_CTRL, 0); + + if (cpu_data->linux_cr4 & X86_CR4_VMXE) + return trace_error(-EBUSY); + + err = vmx_check_features(); + if (err) + return err; + + revision_id = (u32)read_msr(MSR_IA32_VMX_BASIC); + cpu_data->vmxon_region.revision_id = revision_id; + cpu_data->vmxon_region.shadow_indicator = 0; + cpu_data->vmcs.revision_id = revision_id; + cpu_data->vmcs.shadow_indicator = 0; + + /* Note: We assume that TXT is off */ + feature_ctrl = read_msr(MSR_IA32_FEATURE_CONTROL); + mask = FEATURE_CONTROL_LOCKED | + FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; + + if ((feature_ctrl & mask) != mask) { + if (feature_ctrl & FEATURE_CONTROL_LOCKED) + return trace_error(-ENODEV); + + feature_ctrl |= mask; + write_msr(MSR_IA32_FEATURE_CONTROL, feature_ctrl); + } + + /* + * SDM Volume 3, 2.5: "When loading a control register, reserved bits + * should always be set to the values previously read." + * But we want to avoid surprises with new features unknown to us but + * set by Linux. So check if any assumed revered bit was set or should + * be set for VMX operation and bail out if so. + */ + if ((cpu_data->linux_cr0 | cr_required1[CR0_IDX]) & X86_CR0_RESERVED || + (cpu_data->linux_cr4 | cr_required1[CR4_IDX]) & X86_CR4_RESERVED) + return trace_error(-EIO); + /* + * Bring CR0 and CR4 into well-defined states. If they do not match + * with VMX requirements, vmxon will fail. + * X86_CR4_OSXSAVE is enabled if available so that xsetbv can be + * executed on behalf of a cell. + */ + write_cr0(X86_CR0_HOST_STATE); + write_cr4(X86_CR4_HOST_STATE | X86_CR4_VMXE | + ((cpuid_ecx(1, 0) & X86_FEATURE_XSAVE) ? + X86_CR4_OSXSAVE : 0)); + + if (!vmxon()) { + write_cr4(cpu_data->linux_cr4); + return trace_error(-EIO); + } + + cpu_data->vmx_state = VMXON; + + if (!vmcs_clear() || !vmcs_load() || !vmcs_setup()) + return trace_error(-EIO); + + cpu_data->vmx_state = VMCS_READY; + + return 0; +} + +void vcpu_exit(struct per_cpu *cpu_data) +{ + if (cpu_data->vmx_state == VMXOFF) + return; + + cpu_data->vmx_state = VMXOFF; + /* Write vmx_state to ensure that vcpu_nmi_handler stops accessing + * the VMCS (a compiler barrier would be sufficient, in fact). */ + memory_barrier(); + + vmcs_clear(); + asm volatile("vmxoff" : : : "cc"); + cpu_data->linux_cr4 &= ~X86_CR4_VMXE; +} + +void __attribute__((noreturn)) vcpu_activate_vmm(void) +{ + /* We enter Linux at the point arch_entry would return to as well. + * rax is cleared to signal success to the caller. */ + asm volatile( + "mov (%%rdi),%%r15\n\t" + "mov 0x8(%%rdi),%%r14\n\t" + "mov 0x10(%%rdi),%%r13\n\t" + "mov 0x18(%%rdi),%%r12\n\t" + "mov 0x20(%%rdi),%%rbx\n\t" + "mov 0x28(%%rdi),%%rbp\n\t" + "vmlaunch\n\t" + "pop %%rbp" + : /* no output */ + : "a" (0), "D" (this_cpu_data()->linux_reg) + : "memory", "r15", "r14", "r13", "r12", "rbx", "rbp", "cc"); + + panic_printk("FATAL: vmlaunch failed, error %d\n", + vmcs_read32(VM_INSTRUCTION_ERROR)); + panic_stop(); +} + +void __attribute__((noreturn)) vcpu_deactivate_vmm(void) +{ + /* use common per-cpu area - mandatory after arch_cpu_restore */ + struct per_cpu *cpu_data = per_cpu(this_cpu_id()); + unsigned long *stack = (unsigned long *)vmcs_read64(GUEST_RSP); + unsigned long linux_ip = vmcs_read64(GUEST_RIP); + + cpu_data->linux_cr0 = vmcs_read64(GUEST_CR0); + cpu_data->linux_cr3 = vmcs_read64(GUEST_CR3); + cpu_data->linux_cr4 = vmcs_read64(GUEST_CR4); + + cpu_data->linux_gdtr.base = vmcs_read64(GUEST_GDTR_BASE); + cpu_data->linux_gdtr.limit = vmcs_read64(GUEST_GDTR_LIMIT); + cpu_data->linux_idtr.base = vmcs_read64(GUEST_IDTR_BASE); + cpu_data->linux_idtr.limit = vmcs_read64(GUEST_IDTR_LIMIT); + + cpu_data->linux_cs.selector = vmcs_read32(GUEST_CS_SELECTOR); + + cpu_data->linux_tss.selector = vmcs_read32(GUEST_TR_SELECTOR); + + cpu_data->linux_efer = vmcs_read64(GUEST_IA32_EFER); + cpu_data->linux_fs.base = vmcs_read64(GUEST_FS_BASE); + cpu_data->linux_gs.base = vmcs_read64(GUEST_GS_BASE); + + write_msr(MSR_IA32_SYSENTER_CS, vmcs_read32(GUEST_SYSENTER_CS)); + write_msr(MSR_IA32_SYSENTER_EIP, vmcs_read64(GUEST_SYSENTER_EIP)); + write_msr(MSR_IA32_SYSENTER_ESP, vmcs_read64(GUEST_SYSENTER_ESP)); + + cpu_data->linux_ds.selector = vmcs_read16(GUEST_DS_SELECTOR); + cpu_data->linux_es.selector = vmcs_read16(GUEST_ES_SELECTOR); + cpu_data->linux_fs.selector = vmcs_read16(GUEST_FS_SELECTOR); + cpu_data->linux_gs.selector = vmcs_read16(GUEST_GS_SELECTOR); + + arch_cpu_restore(this_cpu_id(), 0); + + stack--; + *stack = linux_ip; + + asm volatile ( + "mov %%rbx,%%rsp\n\t" + "pop %%r15\n\t" + "pop %%r14\n\t" + "pop %%r13\n\t" + "pop %%r12\n\t" + "pop %%r11\n\t" + "pop %%r10\n\t" + "pop %%r9\n\t" + "pop %%r8\n\t" + "pop %%rdi\n\t" + "pop %%rsi\n\t" + "pop %%rbp\n\t" + "add $8,%%rsp\n\t" + "pop %%rbx\n\t" + "pop %%rdx\n\t" + "pop %%rcx\n\t" + "mov %%rax,%%rsp\n\t" + "xor %%rax,%%rax\n\t" + "ret" + : : "a" (stack), "b" (&cpu_data->guest_regs)); + __builtin_unreachable(); +} + +void vcpu_vendor_reset(unsigned int sipi_vector) +{ + unsigned long reset_addr, val; + bool ok = true; + + ok &= vmx_set_guest_cr(CR0_IDX, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET); + ok &= vmx_set_guest_cr(CR4_IDX, 0); + + ok &= vmcs_write64(GUEST_CR3, 0); + + ok &= vmcs_write64(GUEST_RFLAGS, 0x02); + ok &= vmcs_write64(GUEST_RSP, 0); + + if (sipi_vector == APIC_BSP_PSEUDO_SIPI) { + /* only cleared on hard reset */ + ok &= vmcs_write64(GUEST_IA32_DEBUGCTL, 0); + + reset_addr = this_cell()->config->cpu_reset_address; + + ok &= vmcs_write64(GUEST_RIP, reset_addr & 0xffff); + + ok &= vmcs_write16(GUEST_CS_SELECTOR, + (reset_addr >> 4) & 0xf000); + ok &= vmcs_write64(GUEST_CS_BASE, reset_addr & ~0xffffL); + } else { + ok &= vmcs_write64(GUEST_RIP, 0); + + ok &= vmcs_write16(GUEST_CS_SELECTOR, sipi_vector << 8); + ok &= vmcs_write64(GUEST_CS_BASE, sipi_vector << 12); + } + + ok &= vmcs_write32(GUEST_CS_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_CS_AR_BYTES, 0x0009b); + + ok &= vmcs_write16(GUEST_DS_SELECTOR, 0); + ok &= vmcs_write64(GUEST_DS_BASE, 0); + ok &= vmcs_write32(GUEST_DS_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_DS_AR_BYTES, 0x00093); + + ok &= vmcs_write16(GUEST_ES_SELECTOR, 0); + ok &= vmcs_write64(GUEST_ES_BASE, 0); + ok &= vmcs_write32(GUEST_ES_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_ES_AR_BYTES, 0x00093); + + ok &= vmcs_write16(GUEST_FS_SELECTOR, 0); + ok &= vmcs_write64(GUEST_FS_BASE, 0); + ok &= vmcs_write32(GUEST_FS_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_FS_AR_BYTES, 0x00093); + + ok &= vmcs_write16(GUEST_GS_SELECTOR, 0); + ok &= vmcs_write64(GUEST_GS_BASE, 0); + ok &= vmcs_write32(GUEST_GS_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_GS_AR_BYTES, 0x00093); + + ok &= vmcs_write16(GUEST_SS_SELECTOR, 0); + ok &= vmcs_write64(GUEST_SS_BASE, 0); + ok &= vmcs_write32(GUEST_SS_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_SS_AR_BYTES, 0x00093); + + ok &= vmcs_write16(GUEST_TR_SELECTOR, 0); + ok &= vmcs_write64(GUEST_TR_BASE, 0); + ok &= vmcs_write32(GUEST_TR_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_TR_AR_BYTES, 0x0008b); + + ok &= vmcs_write16(GUEST_LDTR_SELECTOR, 0); + ok &= vmcs_write64(GUEST_LDTR_BASE, 0); + ok &= vmcs_write32(GUEST_LDTR_LIMIT, 0xffff); + ok &= vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082); + + ok &= vmcs_write64(GUEST_GDTR_BASE, 0); + ok &= vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); + ok &= vmcs_write64(GUEST_IDTR_BASE, 0); + ok &= vmcs_write32(GUEST_IDTR_LIMIT, 0xffff); + + ok &= vmcs_write64(GUEST_IA32_EFER, 0); + + ok &= vmcs_write32(GUEST_SYSENTER_CS, 0); + ok &= vmcs_write64(GUEST_SYSENTER_EIP, 0); + ok &= vmcs_write64(GUEST_SYSENTER_ESP, 0); + + ok &= vmcs_write64(GUEST_DR7, 0x00000400); + + ok &= vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); + ok &= vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); + ok &= vmcs_write64(GUEST_PENDING_DBG_EXCEPTIONS, 0); + ok &= vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); + + val = vmcs_read32(VM_ENTRY_CONTROLS); + val &= ~VM_ENTRY_IA32E_MODE; + ok &= vmcs_write32(VM_ENTRY_CONTROLS, val); + + ok &= vmx_set_cell_config(); + + if (!ok) { + panic_printk("FATAL: CPU reset failed\n"); + panic_stop(); + } +} + +static void vmx_preemption_timer_set_enable(bool enable) +{ + u32 pin_based_ctrl = vmcs_read32(PIN_BASED_VM_EXEC_CONTROL); + + if (enable) + pin_based_ctrl |= PIN_BASED_VMX_PREEMPTION_TIMER; + else + pin_based_ctrl &= ~PIN_BASED_VMX_PREEMPTION_TIMER; + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, pin_based_ctrl); +} + +void vcpu_nmi_handler(void) +{ + if (this_cpu_data()->vmx_state == VMCS_READY) + vmx_preemption_timer_set_enable(true); +} + +void vcpu_park(void) +{ +#ifdef CONFIG_CRASH_CELL_ON_PANIC + if (this_cpu_public()->failed) { + vmcs_write64(GUEST_RIP, 0); + return; + } +#endif + vcpu_vendor_reset(0); + vmcs_write64(GUEST_IA32_DEBUGCTL, 0); + vmcs_write64(EPT_POINTER, paging_hvirt2phys(parking_pt.root_table) | + EPT_TYPE_WRITEBACK | EPT_PAGE_WALK_LEN); +} + +void vcpu_skip_emulated_instruction(unsigned int inst_len) +{ + vmcs_write64(GUEST_RIP, vmcs_read64(GUEST_RIP) + inst_len); +} + +static void vmx_check_events(void) +{ + vmx_preemption_timer_set_enable(false); + x86_check_events(); +} + +static void vmx_handle_exception_nmi(void) +{ + struct public_per_cpu *cpu_public = &this_cpu_data()->public; + u32 intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR) { + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT]++; + asm volatile("int %0" : : "i" (NMI_VECTOR)); + } else { + cpu_public->stats[JAILHOUSE_CPU_STAT_VMEXITS_EXCEPTION]++; + /* + * Reinject the event straight away. We only intercept #DB and + * #AC to prevent that malicious guests can trigger infinite + * loops in microcode (see e.g. CVE-2015-5307 and + * CVE-2015-8104). + */ + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + intr_info & INTR_TO_VECTORING_INFO_MASK); + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs_read32(VM_EXIT_INTR_ERROR_CODE)); + } + + /* + * Check for events even in the exception case in order to maintain + * control over the guest if it triggered #DB or #AC loops. + */ + vmx_check_events(); +} + +static void update_efer(void) +{ + unsigned long efer = vmcs_read64(GUEST_IA32_EFER); + + if ((efer & (EFER_LME | EFER_LMA)) != EFER_LME) + return; + + efer |= EFER_LMA; + vmcs_write64(GUEST_IA32_EFER, efer); + vmcs_write32(VM_ENTRY_CONTROLS, + vmcs_read32(VM_ENTRY_CONTROLS) | VM_ENTRY_IA32E_MODE); +} + +static bool vmx_handle_cr(void) +{ + u64 exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + unsigned long cr, reg, val; + + cr = exit_qualification & 0xf; + reg = (exit_qualification >> 8) & 0xf; + + switch ((exit_qualification >> 4) & 3) { + case 0: /* move to cr */ + if (reg == 4) + val = vmcs_read64(GUEST_RSP); + else + val = this_cpu_data()->guest_regs.by_index[15 - reg]; + + if (cr == 0 || cr == 4) { + vcpu_skip_emulated_instruction(X86_INST_LEN_MOV_TO_CR); + /* TODO: check for #GP reasons */ + vmx_set_guest_cr(cr ? CR4_IDX : CR0_IDX, val); + if (cr == 0 && val & X86_CR0_PG) + update_efer(); + return true; + } + break; + default: + break; + } + panic_printk("FATAL: Unhandled CR access, qualification %llx\n", + exit_qualification); + return false; +} + +void vcpu_get_guest_paging_structs(struct guest_paging_structures *pg_structs) +{ + struct per_cpu *cpu_data = this_cpu_data(); + unsigned int n; + + if (vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_IA32E_MODE) { + pg_structs->root_paging = x86_64_paging; + pg_structs->root_table_gphys = + vmcs_read64(GUEST_CR3) & BIT_MASK(51, 12); + } else if (!(vmcs_read64(GUEST_CR0) & X86_CR0_PG)) { + pg_structs->root_paging = NULL; + } else if (vmcs_read64(GUEST_CR4) & X86_CR4_PAE) { + pg_structs->root_paging = pae_paging; + /* + * Although we read the PDPTEs from the guest registers, we + * need to provide the root table here to please the generic + * page table walker. It will map the PDPT then, but we won't + * use it. + */ + pg_structs->root_table_gphys = + vmcs_read64(GUEST_CR3) & BIT_MASK(31, 5); + /* + * The CPU caches the PDPTEs in registers. We need to use them + * instead of reading the entries from guest memory. + */ + for (n = 0; n < 4; n++) + cpu_data->pdpte[n] = vmcs_read64(GUEST_PDPTR0 + n * 2); + } else { + pg_structs->root_paging = i386_paging; + pg_structs->root_table_gphys = + vmcs_read64(GUEST_CR3) & BIT_MASK(31, 12); + } +} + +pt_entry_t vcpu_pae_get_pdpte(page_table_t page_table, unsigned long virt) +{ + return &this_cpu_data()->pdpte[(virt >> 30) & 0x3]; +} + +void vcpu_vendor_set_guest_pat(unsigned long val) +{ + vmcs_write64(GUEST_IA32_PAT, val); +} + +static bool vmx_handle_apic_access(void) +{ + struct guest_paging_structures pg_structs; + unsigned int inst_len, offset; + u64 qualification; + bool is_write; + + qualification = vmcs_read64(EXIT_QUALIFICATION); + + switch (qualification & APIC_ACCESS_TYPE_MASK) { + case APIC_ACCESS_TYPE_LINEAR_READ: + case APIC_ACCESS_TYPE_LINEAR_WRITE: + is_write = !!(qualification & APIC_ACCESS_TYPE_LINEAR_WRITE); + offset = qualification & APIC_ACCESS_OFFSET_MASK; + if (offset & 0x00f) + break; + + vcpu_get_guest_paging_structs(&pg_structs); + + inst_len = apic_mmio_access(&pg_structs, offset >> 4, is_write); + if (!inst_len) + break; + + vcpu_skip_emulated_instruction(inst_len); + return true; + } + panic_printk("FATAL: Unhandled APIC access, " + "qualification %llx\n", qualification); + return false; +} + +static bool vmx_handle_xsetbv(void) +{ + union registers *guest_regs = &this_cpu_data()->guest_regs; + + if (vcpu_vendor_get_guest_cr4() & X86_CR4_OSXSAVE && + guest_regs->rax & X86_XCR0_FP && + (guest_regs->rax & ~cpuid_eax(0x0d, 0)) == 0 && + guest_regs->rcx == 0 && guest_regs->rdx == 0) { + vcpu_skip_emulated_instruction(X86_INST_LEN_XSETBV); + asm volatile( + "xsetbv" + : /* no output */ + : "a" (guest_regs->rax), "c" (0), "d" (0)); + return true; + } + panic_printk("FATAL: Invalid xsetbv parameters: " + "xcr[%ld] = %08lx:%08lx\n", + guest_regs->rcx, guest_regs->rdx, guest_regs->rax); + return false; +} + +static void dump_vm_exit_details(u32 reason) +{ + panic_printk("qualification %lx\n", vmcs_read64(EXIT_QUALIFICATION)); + panic_printk("vectoring info: %x interrupt info: %x\n", + vmcs_read32(IDT_VECTORING_INFO_FIELD), + vmcs_read32(VM_EXIT_INTR_INFO)); + if (reason == EXIT_REASON_EPT_VIOLATION || + reason == EXIT_REASON_EPT_MISCONFIG) + panic_printk("guest phys: 0x%016lx guest linear: 0x%016lx\n", + vmcs_read64(GUEST_PHYSICAL_ADDRESS), + vmcs_read64(GUEST_LINEAR_ADDRESS)); +} + +static void dump_guest_regs(union registers *guest_regs) +{ + panic_printk("RIP: 0x%016lx RSP: 0x%016lx FLAGS: %lx\n", + vmcs_read64(GUEST_RIP), vmcs_read64(GUEST_RSP), + vmcs_read64(GUEST_RFLAGS)); + panic_printk("RAX: 0x%016lx RBX: 0x%016lx RCX: 0x%016lx\n", + guest_regs->rax, guest_regs->rbx, guest_regs->rcx); + panic_printk("RDX: 0x%016lx RSI: 0x%016lx RDI: 0x%016lx\n", + guest_regs->rdx, guest_regs->rsi, guest_regs->rdi); + panic_printk("CS: %lx BASE: 0x%016lx AR-BYTES: %x EFER.LMA %d\n", + vmcs_read64(GUEST_CS_SELECTOR), + vmcs_read64(GUEST_CS_BASE), + vmcs_read32(GUEST_CS_AR_BYTES), + !!(vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_IA32E_MODE)); + panic_printk("CR0: 0x%016lx CR3: 0x%016lx CR4: 0x%016lx\n", + vmcs_read64(GUEST_CR0), vmcs_read64(GUEST_CR3), + vmcs_read64(GUEST_CR4)); + panic_printk("EFER: 0x%016lx\n", vmcs_read64(GUEST_IA32_EFER)); +} + +void vcpu_vendor_get_io_intercept(struct vcpu_io_intercept *io) +{ + u64 exitq = vmcs_read64(EXIT_QUALIFICATION); + + /* parse exit qualification for I/O instructions (see SDM, 27.2.1 ) */ + io->port = (exitq >> 16) & 0xFFFF; + io->size = (exitq & 0x3) + 1; + io->in = !!((exitq & 0x8) >> 3); + io->inst_len = vmcs_read64(VM_EXIT_INSTRUCTION_LEN); + io->rep_or_str = !!(exitq & 0x30); +} + +void vcpu_vendor_get_mmio_intercept(struct vcpu_mmio_intercept *mmio) +{ + u64 exitq = vmcs_read64(EXIT_QUALIFICATION); + + mmio->phys_addr = vmcs_read64(GUEST_PHYSICAL_ADDRESS); + /* We don't enable dirty/accessed bit updated in EPTP, + * so only read of write flags can be set, not both. */ + mmio->is_write = !!(exitq & 0x2); +} + +void vcpu_handle_exit(struct per_cpu *cpu_data) +{ + u32 reason = vmcs_read32(VM_EXIT_REASON); + u32 *stats = cpu_data->public.stats; + + stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL]++; + + switch (reason) { + case EXIT_REASON_EXCEPTION_NMI: + vmx_handle_exception_nmi(); + return; + case EXIT_REASON_PREEMPTION_TIMER: + stats[JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT]++; + vmx_check_events(); + return; + case EXIT_REASON_CPUID: + vcpu_handle_cpuid(); + return; + case EXIT_REASON_VMCALL: + vcpu_handle_hypercall(); + return; + case EXIT_REASON_CR_ACCESS: + stats[JAILHOUSE_CPU_STAT_VMEXITS_CR]++; + if (vmx_handle_cr()) + return; + break; + case EXIT_REASON_MSR_READ: + if (vcpu_handle_msr_read()) + return; + break; + case EXIT_REASON_MSR_WRITE: + if (cpu_data->guest_regs.rcx == MSR_IA32_PERF_GLOBAL_CTRL) { + /* ignore writes */ + stats[JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER]++; + vcpu_skip_emulated_instruction(X86_INST_LEN_WRMSR); + return; + } else if (vcpu_handle_msr_write()) + return; + break; + case EXIT_REASON_APIC_ACCESS: + stats[JAILHOUSE_CPU_STAT_VMEXITS_XAPIC]++; + if (vmx_handle_apic_access()) + return; + break; + case EXIT_REASON_XSETBV: + stats[JAILHOUSE_CPU_STAT_VMEXITS_XSETBV]++; + if (vmx_handle_xsetbv()) + return; + break; + case EXIT_REASON_IO_INSTRUCTION: + stats[JAILHOUSE_CPU_STAT_VMEXITS_PIO]++; + if (vcpu_handle_io_access()) + return; + break; + case EXIT_REASON_EPT_VIOLATION: + stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++; + if (vcpu_handle_mmio_access()) + return; + break; + default: + panic_printk("FATAL: %s, reason %d\n", + (reason & EXIT_REASONS_FAILED_VMENTRY) ? + "VM-Entry failure" : "Unhandled VM-Exit", + (u16)reason); + dump_vm_exit_details(reason); + break; + } + dump_guest_regs(&cpu_data->guest_regs); + panic_park(); +} + +void vmx_entry_failure(void) +{ + panic_printk("FATAL: vmresume failed, error %d\n", + vmcs_read32(VM_INSTRUCTION_ERROR)); + panic_stop(); +} + +unsigned int vcpu_vendor_get_io_bitmap_pages(void) +{ + return PIO_BITMAP_PAGES; +} + +#define VCPU_VENDOR_GET_REGISTER(__reg__, __field__) \ +u64 vcpu_vendor_get_##__reg__(void) \ +{ \ + return vmcs_read64(__field__); \ +} + +VCPU_VENDOR_GET_REGISTER(efer, GUEST_IA32_EFER); +VCPU_VENDOR_GET_REGISTER(rflags, GUEST_RFLAGS); +VCPU_VENDOR_GET_REGISTER(rip, GUEST_RIP); + +u16 vcpu_vendor_get_cs_attr(void) +{ + return vmcs_read32(GUEST_CS_AR_BYTES); +} + +void enable_irq(void) +{ + asm volatile("sti" : : : "memory"); +} + +void disable_irq(void) +{ + asm volatile("cli" : : : "memory"); +} diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c new file mode 100644 index 0000000000000000000000000000000000000000..ccd0bdde134e658d0c7b8fec00c24668163334ce --- /dev/null +++ b/hypervisor/arch/x86/vtd.c @@ -0,0 +1,1117 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Jan Kiszka + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VTD_INTERRUPT_LIMIT() \ + system_config->platform_info.x86.vtd_interrupt_limit + +#define VTD_ROOT_PRESENT 0x00000001 + +#define VTD_CTX_PRESENT 0x00000001 +#define VTD_CTX_TTYPE_MLP_UNTRANS 0x00000000 + +#define VTD_CTX_AGAW_39 0x00000001 +#define VTD_CTX_AGAW_48 0x00000002 +#define VTD_CTX_DID_SHIFT 8 + +struct vtd_entry { + u64 lo_word; + u64 hi_word; +}; + +#define VTD_PAGE_READ 0x00000001 +#define VTD_PAGE_WRITE 0x00000002 + +#define VTD_MAX_PAGE_TABLE_LEVELS 4 + +#define VTD_VER_REG 0x00 +# define VTD_VER_MASK BIT_MASK(7, 0) +# define VTD_VER_MIN 0x10 +#define VTD_CAP_REG 0x08 +# define VTD_CAP_NUM_DID_MASK BIT_MASK(2, 0) +# define VTD_CAP_SAGAW39 (1UL << 9) +# define VTD_CAP_SAGAW48 (1UL << 10) +# define VTD_CAP_SLLPS2M (1UL << 34) +# define VTD_CAP_SLLPS1G (1UL << 35) +# define VTD_CAP_FRO_MASK BIT_MASK(33, 24) +# define VTD_CAP_NFR_MASK BIT_MASK(47, 40) +#define VTD_ECAP_REG 0x10 +# define VTD_ECAP_QI (1UL << 1) +# define VTD_ECAP_IR (1UL << 3) +# define VTD_ECAP_EIM (1UL << 4) +#define VTD_GCMD_REG 0x18 +# define VTD_GCMD_SIRTP (1UL << 24) +# define VTD_GCMD_IRE (1UL << 25) +# define VTD_GCMD_QIE (1UL << 26) +# define VTD_GCMD_SRTP (1UL << 30) +# define VTD_GCMD_TE (1UL << 31) +#define VTD_GSTS_REG 0x1c +# define VTD_GSTS_IRES (1UL << 25) +# define VTD_GSTS_QIES (1UL << 26) +# define VTD_GSTS_TES (1UL << 31) +# define VTD_GSTS_USED_CTRLS \ + (VTD_GSTS_IRES | VTD_GSTS_QIES | VTD_GSTS_TES) +#define VTD_RTADDR_REG 0x20 +#define VTD_FSTS_REG 0x34 +# define VTD_FSTS_PFO (1UL << 0) +# define VTD_FSTS_PFO_CLEAR 1 +# define VTD_FSTS_PPF (1UL << 1) +# define VTD_FSTS_FRI_MASK BIT_MASK(15, 8) +#define VTD_FECTL_REG 0x38 +#define VTD_FECTL_IM (1UL << 31) +#define VTD_FEDATA_REG 0x3c +#define VTD_FEADDR_REG 0x40 +#define VTD_FEUADDR_REG 0x44 +#define VTD_IQH_REG 0x80 +# define VTD_IQH_QH_SHIFT 4 +#define VTD_IQT_REG 0x88 +# define VTD_IQT_QT_MASK BIT_MASK(18, 4) +#define VTD_IQA_REG 0x90 +# define VTD_IQA_ADDR_MASK BIT_MASK(63, 12) +#define VTD_IRTA_REG 0xb8 +# define VTD_IRTA_SIZE_MASK BIT_MASK(3, 0) +# define VTD_IRTA_EIME (1UL << 11) +# define VTD_IRTA_ADDR_MASK BIT_MASK(63, 12) + +#define VTD_REQ_INV_MASK BIT_MASK(3, 0) + +#define VTD_REQ_INV_CONTEXT 0x01 +# define VTD_INV_CONTEXT_GLOBAL (1UL << 4) +# define VTD_INV_CONTEXT_DOMAIN (2UL << 4) +# define VTD_INV_CONTEXT_DOMAIN_SHIFT 16 + +#define VTD_REQ_INV_IOTLB 0x02 +# define VTD_INV_IOTLB_GLOBAL (1UL << 4) +# define VTD_INV_IOTLB_DOMAIN (2UL << 4) +# define VTD_INV_IOTLB_DW (1UL << 6) +# define VTD_INV_IOTLB_DR (1UL << 7) +# define VTD_INV_IOTLB_DOMAIN_SHIFT 16 + +#define VTD_REQ_INV_INT 0x04 +# define VTD_INV_INT_GLOBAL (0UL << 4) +# define VTD_INV_INT_INDEX (1UL << 4) +# define VTD_INV_INT_IM_MASK BIT_MASK(31, 27) +# define VTD_INV_INT_IM_SHIFT 27 +# define VTD_INV_INT_IIDX_MASK BIT_MASK(47, 32) +# define VTD_INV_INT_IIDX_SHIFT 32 + +#define VTD_REQ_INV_WAIT 0x05 +#define VTD_INV_WAIT_IF (1UL << 4) +#define VTD_INV_WAIT_SW (1UL << 5) +#define VTD_INV_WAIT_FN (1UL << 6) +#define VTD_INV_WAIT_SDATA_SHIFT 32 + +#define VTD_FRCD_LO_REG 0x0 +#define VTD_FRCD_LO_FI_MASK BIT_MASK(63, 12) +#define VTD_FRCD_HI_REG 0x8 +#define VTD_FRCD_HI_SID_MASK BIT_MASK(79-64, 64-64) +#define VTD_FRCD_HI_FR_MASK BIT_MASK(103-64, 96-64) +#define VTD_FRCD_HI_TYPE (1L << (126-64)) +#define VTD_FRCD_HI_F (1L << (127-64)) +#define VTD_FRCD_HI_F_CLEAR 1 + +union vtd_irte { + struct { + u8 p:1; + u8 fpd:1; + u8 dest_logical:1; + u8 redir_hint:1; + u8 level_triggered:1; + u8 delivery_mode:3; + u8 assigned:1; + u8 reserved:7; + u8 vector; + u8 reserved2; + u32 destination; + u16 sid; + u16 sq:2; + u16 svt:2; + u16 reserved3:12; + u32 reserved4; + } __attribute__((packed)) field; + u64 raw[2]; +} __attribute__((packed)); + +#define VTD_IRTE_SQ_VERIFY_FULL_SID 0x0 +#define VTD_IRTE_SVT_VERIFY_SID_SQ 0x1 + +/* A unit can occupy up to 3 pages for registers, we reserve 4. */ +#define DMAR_MMIO_SIZE (PAGE_SIZE * 4) + +struct vtd_irte_usage { + u16 device_id; + u16 vector:10, + used:1; +} __attribute__((packed)); + +struct vtd_emulation { + u64 irta; + unsigned int irt_entries; + struct vtd_irte_usage *irte_map; + + u64 iqa; + u16 iqh; + + u32 fault_event_regs[4]; +}; + +static const struct vtd_entry inv_global_context = { + .lo_word = VTD_REQ_INV_CONTEXT | VTD_INV_CONTEXT_GLOBAL, +}; +static const struct vtd_entry inv_global_iotlb = { + .lo_word = VTD_REQ_INV_IOTLB | VTD_INV_IOTLB_GLOBAL | + VTD_INV_IOTLB_DW | VTD_INV_IOTLB_DR, +}; +static const struct vtd_entry inv_global_int = { + .lo_word = VTD_REQ_INV_INT | VTD_INV_INT_GLOBAL, +}; + +/* TODO: Support multiple segments */ +static struct vtd_entry __attribute__((aligned(PAGE_SIZE))) + root_entry_table[256]; +static union vtd_irte *int_remap_table; +static unsigned int int_remap_table_size_log2; +static struct paging vtd_paging[VTD_MAX_PAGE_TABLE_LEVELS]; +static void *dmar_reg_base; +static void *unit_inv_queue; +static unsigned int dmar_units; +static unsigned int dmar_pt_levels; +static unsigned int dmar_num_did = ~0U; +static spinlock_t inv_queue_lock; +static struct vtd_emulation root_cell_units[JAILHOUSE_MAX_IOMMU_UNITS]; +static bool dmar_units_initialized; + +static unsigned int vtd_mmio_count_regions(struct cell *cell) +{ + return cell == &root_cell ? iommu_count_units() : 0; +} + +static unsigned int inv_queue_write(void *inv_queue, unsigned int index, + struct vtd_entry content) +{ + struct vtd_entry *entry = inv_queue; + + entry[index] = content; + arch_paging_flush_cpu_caches(&entry[index], sizeof(*entry)); + + return (index + 1) % (PAGE_SIZE / sizeof(*entry)); +} + +static void vtd_submit_iq_request(void *reg_base, void *inv_queue, + const struct vtd_entry *inv_request) +{ + struct vtd_entry inv_wait = { + .lo_word = VTD_REQ_INV_WAIT | VTD_INV_WAIT_SW | + VTD_INV_WAIT_FN | (1UL << VTD_INV_WAIT_SDATA_SHIFT), + .hi_word = paging_hvirt2phys( + &per_cpu(this_cpu_id())->vtd_iq_completed), + }; + unsigned int index; + + this_cpu_data()->vtd_iq_completed = 0; + + spin_lock(&inv_queue_lock); + + index = mmio_read64_field(reg_base + VTD_IQT_REG, VTD_IQT_QT_MASK); + + if (inv_request) + index = inv_queue_write(inv_queue, index, *inv_request); + index = inv_queue_write(inv_queue, index, inv_wait); + + mmio_write64_field(reg_base + VTD_IQT_REG, VTD_IQT_QT_MASK, index); + + while (!this_cpu_data()->vtd_iq_completed) + cpu_relax(); + + spin_unlock(&inv_queue_lock); +} + +static void vtd_flush_domain_caches(unsigned int did) +{ + const struct vtd_entry inv_context = { + .lo_word = VTD_REQ_INV_CONTEXT | VTD_INV_CONTEXT_DOMAIN | + (did << VTD_INV_CONTEXT_DOMAIN_SHIFT), + }; + const struct vtd_entry inv_iotlb = { + .lo_word = VTD_REQ_INV_IOTLB | VTD_INV_IOTLB_DOMAIN | + VTD_INV_IOTLB_DW | VTD_INV_IOTLB_DR | + (did << VTD_INV_IOTLB_DOMAIN_SHIFT), + }; + void *inv_queue = unit_inv_queue; + void *reg_base = dmar_reg_base; + unsigned int n; + + for (n = 0; n < dmar_units; n++) { + vtd_submit_iq_request(reg_base, inv_queue, &inv_context); + vtd_submit_iq_request(reg_base, inv_queue, &inv_iotlb); + reg_base += DMAR_MMIO_SIZE; + inv_queue += PAGE_SIZE; + } +} + +static void vtd_update_gcmd_reg(void *reg_base, u32 mask, unsigned int set) +{ + u32 val = mmio_read32(reg_base + VTD_GSTS_REG) & VTD_GSTS_USED_CTRLS; + + if (set) + val |= mask; + else + val &= ~mask; + mmio_write32(reg_base + VTD_GCMD_REG, val); + + /* Note: This test is built on the fact related bits are at the same + * position in VTD_GCMD_REG and VTD_GSTS_REG. */ + while ((mmio_read32(reg_base + VTD_GSTS_REG) & mask) != (val & mask)) + cpu_relax(); +} + +static void vtd_set_next_pt(pt_entry_t pte, unsigned long next_pt) +{ + *pte = (next_pt & BIT_MASK(51, 12)) | VTD_PAGE_READ | VTD_PAGE_WRITE; +} + +static void vtd_init_fault_nmi(void) +{ + union x86_msi_vector msi = { .native.address = MSI_ADDRESS_VALUE }; + struct public_per_cpu *target_data; + void *reg_base = dmar_reg_base; + unsigned int n; + + /* Pick a suitable root cell CPU to report faults. */ + target_data = iommu_select_fault_reporting_cpu(); + + /* We only support 8-bit APIC IDs. */ + msi.native.destination = (u8)target_data->apic_id; + + for (n = 0; n < dmar_units; n++, reg_base += DMAR_MMIO_SIZE) { + /* Mask events */ + mmio_write32_field(reg_base + VTD_FECTL_REG, VTD_FECTL_IM, 1); + + /* + * VT-d spec rev. 2.3 section 7.4 suggests that only reading + * back FSTS or FECTL ensures no interrupt messages are still + * in-flight when we change their destination below. + */ + mmio_read32(reg_base + VTD_FECTL_REG); + + /* Program MSI message to send NMIs to the target CPU */ + mmio_write32(reg_base + VTD_FEDATA_REG, MSI_DM_NMI); + mmio_write32(reg_base + VTD_FEADDR_REG, (u32)msi.raw.address); + mmio_write32(reg_base + VTD_FEUADDR_REG, 0); + + /* Unmask events */ + mmio_write32_field(reg_base + VTD_FECTL_REG, VTD_FECTL_IM, 0); + } + + /* + * There is a race window between setting the new reporting CPU ID and + * updating the target programming in the register. If a fault hits us + * in this window and no other NMIs arrive after that, the event will + * not be reported. Address this by triggering an NMI on the new + * reporting CPU. + */ + apic_send_nmi_ipi(target_data); +} + +static void *vtd_get_fault_rec_reg_addr(void *reg_base) +{ + return reg_base + 16 * + mmio_read64_field(reg_base + VTD_CAP_REG, VTD_CAP_FRO_MASK); +} + +static void vtd_print_fault_record_reg_status(unsigned int unit_no, + void *reg_base) +{ + unsigned int sid = mmio_read64_field(reg_base + VTD_FRCD_HI_REG, + VTD_FRCD_HI_SID_MASK); + unsigned int fr = mmio_read64_field(reg_base + VTD_FRCD_HI_REG, + VTD_FRCD_HI_FR_MASK); + unsigned long fi = mmio_read64_field(reg_base + VTD_FRCD_LO_REG, + VTD_FRCD_LO_FI_MASK); + unsigned int type = mmio_read64_field(reg_base + VTD_FRCD_HI_REG, + VTD_FRCD_HI_TYPE); + + printk("VT-d fault event reported by IOMMU %d:\n", unit_no); + printk(" Source Identifier (bus:dev.func): %02x:%02x.%x\n", + PCI_BDF_PARAMS(sid)); + printk(" Fault Reason: 0x%x Fault Info: %lx Type %d\n", fr, fi, type); +} + +void iommu_check_pending_faults(void) +{ + unsigned int fr_index; + void *reg_base = dmar_reg_base; + unsigned int n; + void *fault_reg_addr, *rec_reg_addr; + + if (this_cpu_id() != fault_reporting_cpu_id) + return; + + for (n = 0; n < dmar_units; n++, reg_base += DMAR_MMIO_SIZE) + if (mmio_read32_field(reg_base + VTD_FSTS_REG, VTD_FSTS_PPF)) { + fr_index = mmio_read32_field(reg_base + VTD_FSTS_REG, + VTD_FSTS_FRI_MASK); + fault_reg_addr = vtd_get_fault_rec_reg_addr(reg_base); + rec_reg_addr = fault_reg_addr + 16 * fr_index; + vtd_print_fault_record_reg_status(n, rec_reg_addr); + + /* Clear faults in record registers */ + mmio_write64_field(rec_reg_addr + VTD_FRCD_HI_REG, + VTD_FRCD_HI_F, VTD_FRCD_HI_F_CLEAR); + } +} + +static int vtd_emulate_inv_int(unsigned int unit_no, unsigned int index) +{ + struct vtd_irte_usage *irte_usage; + struct apic_irq_message irq_msg; + struct pci_device *device; + + if (index >= root_cell_units[unit_no].irt_entries) + return 0; + irte_usage = &root_cell_units[unit_no].irte_map[index]; + if (!irte_usage->used) + return 0; + + device = pci_get_assigned_device(&root_cell, irte_usage->device_id); + /* On x86, ivshmem devices only support MSI-X. */ + if (device && device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return ivshmem_update_msix_vector(device, irte_usage->vector); + + irq_msg = iommu_get_remapped_root_int(unit_no, irte_usage->device_id, + irte_usage->vector, index); + return iommu_map_interrupt(&root_cell, irte_usage->device_id, + irte_usage->vector, irq_msg); +} + +static int vtd_emulate_qi_request(unsigned int unit_no, + struct vtd_entry inv_desc) +{ + unsigned int start, count, n; + void *status_addr; + int result; + + switch (inv_desc.lo_word & VTD_REQ_INV_MASK) { + case VTD_REQ_INV_INT: + if (inv_desc.lo_word & VTD_INV_INT_INDEX) { + start = (inv_desc.lo_word & VTD_INV_INT_IIDX_MASK) >> + VTD_INV_INT_IIDX_SHIFT; + count = + 1 << ((inv_desc.lo_word & VTD_INV_INT_IM_MASK) >> + VTD_INV_INT_IM_SHIFT); + } else { + start = 0; + count = root_cell_units[unit_no].irt_entries; + } + for (n = start; n < start + count; n++) { + result = vtd_emulate_inv_int(unit_no, n); + if (result < 0) + return result; + } + return 0; + case VTD_REQ_INV_WAIT: + if (inv_desc.lo_word & VTD_INV_WAIT_IF || + !(inv_desc.lo_word & VTD_INV_WAIT_SW)) + return -EINVAL; + + status_addr = paging_get_guest_pages(NULL, inv_desc.hi_word, 1, + PAGE_DEFAULT_FLAGS); + if (!status_addr) + return -EINVAL; + + status_addr += inv_desc.hi_word & PAGE_OFFS_MASK & ~3; + *(u32 *)status_addr = + inv_desc.lo_word >> VTD_INV_WAIT_SDATA_SHIFT; + + return 0; + } + return -EINVAL; +} + +static enum mmio_result vtd_unit_access_handler(void *arg, + struct mmio_access *mmio) +{ + struct vtd_emulation *unit = arg; + unsigned int unit_no = unit - root_cell_units; + struct vtd_entry inv_desc; + void *inv_desc_page; + unsigned int reg; + + if (mmio->address == VTD_FSTS_REG && !mmio->is_write) { + /* + * Nothing to report this way, vtd_check_pending_faults takes + * care for the whole system. + */ + mmio->value = 0; + return MMIO_HANDLED; + } + if (mmio->address >= VTD_FECTL_REG && + mmio->address <= VTD_FEUADDR_REG) { + /* + * Direct the access to the shadow registers - we handle the + * real fault events now. + */ + reg = (mmio->address - VTD_FECTL_REG) / 4; + if (mmio->is_write) + unit->fault_event_regs[reg] = mmio->value; + else + mmio->value = unit->fault_event_regs[reg]; + return MMIO_HANDLED; + } + if (mmio->address == VTD_IQT_REG && mmio->is_write) { + while (unit->iqh != + (mmio->value & VTD_IQT_QT_MASK & PAGE_OFFS_MASK)) { + inv_desc_page = + paging_get_guest_pages(NULL, unit->iqa, 1, + PAGE_READONLY_FLAGS); + if (!inv_desc_page) + goto invalid_iq_entry; + + inv_desc = + *(struct vtd_entry *)(inv_desc_page + unit->iqh); + + if (vtd_emulate_qi_request(unit_no, inv_desc) != 0) + goto invalid_iq_entry; + + unit->iqh += 1 << VTD_IQH_QH_SHIFT; + unit->iqh &= PAGE_OFFS_MASK; + } + return MMIO_HANDLED; + } + panic_printk("FATAL: Unhandled DMAR unit %s access, register %02lx\n", + mmio->is_write ? "write" : "read", mmio->address); + return MMIO_ERROR; + +invalid_iq_entry: + panic_printk("FATAL: Invalid/unsupported invalidation queue entry\n"); + return MMIO_ERROR; +} + +static void vtd_init_unit(void *reg_base, void *inv_queue) +{ + void *fault_reg_base; + unsigned int nfr, n; + + /* Disabled QI and IR in case it was already on */ + vtd_update_gcmd_reg(reg_base, VTD_GCMD_QIE, 0); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_IRE, 0); + + nfr = mmio_read64_field(reg_base + VTD_CAP_REG, VTD_CAP_NFR_MASK); + fault_reg_base = vtd_get_fault_rec_reg_addr(reg_base); + + for (n = 0; n < nfr; n++) + /* Clear fault recording register status */ + mmio_write64_field(fault_reg_base + 16 * n + VTD_FRCD_HI_REG, + VTD_FRCD_HI_F, VTD_FRCD_HI_F_CLEAR); + + /* Clear fault overflow status */ + mmio_write32_field(reg_base + VTD_FSTS_REG, VTD_FSTS_PFO, + VTD_FSTS_PFO_CLEAR); + + /* Set root entry table pointer */ + mmio_write64(reg_base + VTD_RTADDR_REG, + paging_hvirt2phys(root_entry_table)); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_SRTP, 1); + + /* Set interrupt remapping table pointer */ + mmio_write64(reg_base + VTD_IRTA_REG, + paging_hvirt2phys(int_remap_table) | + (using_x2apic ? VTD_IRTA_EIME : 0) | + (int_remap_table_size_log2 - 1)); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_SIRTP, 1); + + /* Setup and activate invalidation queue */ + mmio_write64(reg_base + VTD_IQT_REG, 0); + mmio_write64(reg_base + VTD_IQA_REG, paging_hvirt2phys(inv_queue)); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_QIE, 1); + + vtd_submit_iq_request(reg_base, inv_queue, &inv_global_context); + vtd_submit_iq_request(reg_base, inv_queue, &inv_global_iotlb); + vtd_submit_iq_request(reg_base, inv_queue, &inv_global_int); + + vtd_update_gcmd_reg(reg_base, VTD_GCMD_TE, 1); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_IRE, 1); +} + +static void vtd_update_irte(unsigned int index, union vtd_irte content) +{ + const struct vtd_entry inv_int = { + .lo_word = VTD_REQ_INV_INT | VTD_INV_INT_INDEX | + ((u64)index << VTD_INV_INT_IIDX_SHIFT), + }; + union vtd_irte *irte = &int_remap_table[index]; + void *inv_queue = unit_inv_queue; + void *reg_base = dmar_reg_base; + unsigned int n; + + if (content.field.p) { + /* + * Write upper half first to preserve non-presence. + * If the entry was present before, we are only modifying the + * lower half's content (destination etc.), so writing the + * upper half becomes a nop and is safely done first. + */ + irte->raw[1] = content.raw[1]; + memory_barrier(); + irte->raw[0] = content.raw[0]; + } else { + /* + * Write only lower half - we are clearing presence and + * assignment. + */ + irte->raw[0] = content.raw[0]; + } + arch_paging_flush_cpu_caches(irte, sizeof(*irte)); + + for (n = 0; n < dmar_units; n++) { + vtd_submit_iq_request(reg_base, inv_queue, &inv_int); + reg_base += DMAR_MMIO_SIZE; + inv_queue += PAGE_SIZE; + } +} + +static int vtd_find_int_remap_region(u16 device_id) +{ + unsigned int n; + + /* VTD_INTERRUPT_LIMIT() is < 2^16, see vtd_init */ + for (n = 0; n < VTD_INTERRUPT_LIMIT(); n++) + if (int_remap_table[n].field.assigned && + int_remap_table[n].field.sid == device_id) + return n; + + return -ENOENT; +} + +static int vtd_reserve_int_remap_region(u16 device_id, unsigned int length) +{ + int start = -E2BIG; + unsigned int n; + + if (length == 0 || vtd_find_int_remap_region(device_id) >= 0) + return 0; + + for (n = 0; n < VTD_INTERRUPT_LIMIT(); n++) { + if (int_remap_table[n].field.assigned) { + start = -E2BIG; + continue; + } + if (start < 0) + start = n; + if (n + 1 == start + length) { + printk("Reserving %u interrupt(s) for device " + "%02x:%02x.%x at index %d\n", length, + PCI_BDF_PARAMS(device_id), start); + for (n = start; n < start + length; n++) { + int_remap_table[n].field.assigned = 1; + int_remap_table[n].field.sid = device_id; + } + return start; + } + } + return trace_error(-E2BIG); +} + +static void vtd_free_int_remap_region(u16 device_id, unsigned int length) +{ + union vtd_irte free_irte = { .field.p = 0, .field.assigned = 0 }; + int pos = vtd_find_int_remap_region(device_id); + + if (pos >= 0) { + printk("Freeing %u interrupt(s) for device %02x:%02x.%x at " + "index %d\n", length, PCI_BDF_PARAMS(device_id), pos); + while (length-- > 0) + vtd_update_irte(pos++, free_irte); + } +} + +int iommu_add_pci_device(struct cell *cell, struct pci_device *device) +{ + unsigned int max_vectors = MAX(device->info->num_msi_vectors, + device->info->num_msix_vectors); + u16 bdf = device->info->bdf; + u64 *root_entry_lo = &root_entry_table[PCI_BUS(bdf)].lo_word; + struct vtd_entry *context_entry_table, *context_entry; + int result; + + result = vtd_reserve_int_remap_region(bdf, max_vectors); + if (result < 0) + return result; + + if (*root_entry_lo & VTD_ROOT_PRESENT) { + context_entry_table = + paging_phys2hvirt(*root_entry_lo & PAGE_MASK); + } else { + context_entry_table = page_alloc(&mem_pool, 1); + if (!context_entry_table) + goto error_nomem; + *root_entry_lo = VTD_ROOT_PRESENT | + paging_hvirt2phys(context_entry_table); + arch_paging_flush_cpu_caches(root_entry_lo, sizeof(u64)); + } + + context_entry = &context_entry_table[PCI_DEVFN(bdf)]; + context_entry->lo_word = VTD_CTX_PRESENT | VTD_CTX_TTYPE_MLP_UNTRANS | + paging_hvirt2phys(cell->arch.vtd.pg_structs.root_table); + context_entry->hi_word = + (dmar_pt_levels == 3 ? VTD_CTX_AGAW_39 : VTD_CTX_AGAW_48) | + (cell->config->id << VTD_CTX_DID_SHIFT); + arch_paging_flush_cpu_caches(context_entry, sizeof(*context_entry)); + + return 0; + +error_nomem: + vtd_free_int_remap_region(bdf, max_vectors); + return -ENOMEM; +} + +void iommu_remove_pci_device(struct pci_device *device) +{ + u16 bdf = device->info->bdf; + u64 *root_entry_lo = &root_entry_table[PCI_BUS(bdf)].lo_word; + struct vtd_entry *context_entry_table; + struct vtd_entry *context_entry; + unsigned int n; + + vtd_free_int_remap_region(bdf, MAX(device->info->num_msi_vectors, + device->info->num_msix_vectors)); + + context_entry_table = paging_phys2hvirt(*root_entry_lo & PAGE_MASK); + context_entry = &context_entry_table[PCI_DEVFN(bdf)]; + + context_entry->lo_word &= ~VTD_CTX_PRESENT; + arch_paging_flush_cpu_caches(&context_entry->lo_word, sizeof(u64)); + + for (n = 0; n < 256; n++) + if (context_entry_table[n].lo_word & VTD_CTX_PRESENT) + return; + + *root_entry_lo &= ~VTD_ROOT_PRESENT; + arch_paging_flush_cpu_caches(root_entry_lo, sizeof(u64)); + page_free(&mem_pool, context_entry_table, 1); +} + +static void vtd_cell_exit(struct cell *cell); + +static int vtd_cell_init(struct cell *cell) +{ + const struct jailhouse_irqchip *irqchip = + jailhouse_cell_irqchips(cell->config); + struct phys_ioapic *ioapic; + unsigned int n; + int result; + + if (cell->config->id >= dmar_num_did) + return trace_error(-ERANGE); + + cell->arch.vtd.pg_structs.root_paging = vtd_paging; + cell->arch.vtd.pg_structs.root_table = page_alloc(&mem_pool, 1); + if (!cell->arch.vtd.pg_structs.root_table) + return -ENOMEM; + + /* reserve regions for IRQ chips (if not done already) */ + for (n = 0; n < cell->config->num_irqchips; n++, irqchip++) { + result = ioapic_get_or_add_phys(irqchip, &ioapic); + if (result == 0) + result = vtd_reserve_int_remap_region(irqchip->id, + ioapic->pins); + if (result < 0) { + vtd_cell_exit(cell); + return result; + } + } + + return 0; +} + +int iommu_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + unsigned long access_flags = 0; + unsigned long paging_flags = PAGING_COHERENT | PAGING_HUGE; + + if (!(mem->flags & JAILHOUSE_MEM_DMA)) + return 0; + + if (mem->virt_start & BIT_MASK(63, 12 + 9 * dmar_pt_levels)) + return trace_error(-E2BIG); + + if (mem->flags & JAILHOUSE_MEM_READ) + access_flags |= VTD_PAGE_READ; + if (mem->flags & JAILHOUSE_MEM_WRITE) + access_flags |= VTD_PAGE_WRITE; + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_HUGE; + + return paging_create(&cell->arch.vtd.pg_structs, mem->phys_start, + mem->size, mem->virt_start, access_flags, + paging_flags); +} + +int iommu_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem) +{ + if (!(mem->flags & JAILHOUSE_MEM_DMA)) + return 0; + + return paging_destroy(&cell->arch.vtd.pg_structs, mem->virt_start, + mem->size, PAGING_COHERENT); +} + +struct apic_irq_message +iommu_get_remapped_root_int(unsigned int iommu, u16 device_id, + unsigned int vector, unsigned int remap_index) +{ + struct vtd_emulation *unit = &root_cell_units[iommu]; + struct apic_irq_message irq_msg = { .valid = 0 }; + union vtd_irte root_irte; + unsigned long irte_addr; + void *irte_page; + + if (remap_index >= unit->irt_entries) + return irq_msg; + unit->irte_map[remap_index].used = 0; + + irte_addr = (unit->irta & VTD_IRTA_ADDR_MASK) + + remap_index * sizeof(union vtd_irte); + irte_page = paging_get_guest_pages(NULL, irte_addr, 1, + PAGE_READONLY_FLAGS); + if (!irte_page) + return irq_msg; + + root_irte = *(union vtd_irte *)(irte_page + + (irte_addr & PAGE_OFFS_MASK)); + + irq_msg.valid = root_irte.field.p; + irq_msg.vector = root_irte.field.vector; + irq_msg.delivery_mode = root_irte.field.delivery_mode; + irq_msg.dest_logical = root_irte.field.dest_logical; + irq_msg.level_triggered = root_irte.field.level_triggered; + irq_msg.redir_hint = root_irte.field.redir_hint; + irq_msg.destination = root_irte.field.destination; + if (!using_x2apic) + /* xAPIC in flat mode: APIC ID in 47:40 (of 63:32) */ + irq_msg.destination >>= 8; + + unit->irte_map[remap_index].device_id = device_id; + unit->irte_map[remap_index].vector = vector; + unit->irte_map[remap_index].used = 1; + + return irq_msg; +} + +int iommu_map_interrupt(struct cell *cell, u16 device_id, unsigned int vector, + struct apic_irq_message irq_msg) +{ + union vtd_irte irte; + int base_index; + + base_index = vtd_find_int_remap_region(device_id); + if (base_index < 0) + return base_index; + + if ((vector >= VTD_INTERRUPT_LIMIT()) || + ((u32)base_index >= VTD_INTERRUPT_LIMIT() - vector)) + return -ERANGE; + + irte = int_remap_table[base_index + vector]; + if (!irte.field.assigned || irte.field.sid != device_id) + return -ERANGE; + + irte.field.p = irq_msg.valid; + if (!irte.field.p) + /* + * Do not validate non-present entries, they may contain + * invalid data and cause false-positives. + */ + goto update_irte; + + /* Validate delivery mode and destination(s). */ + if (irq_msg.delivery_mode != APIC_MSG_DLVR_FIXED && + irq_msg.delivery_mode != APIC_MSG_DLVR_LOWPRI) + return -EINVAL; + if (!apic_filter_irq_dest(cell, &irq_msg)) + return -EPERM; + + irte.field.dest_logical = irq_msg.dest_logical; + irte.field.redir_hint = irq_msg.redir_hint; + irte.field.level_triggered = irq_msg.level_triggered; + irte.field.delivery_mode = irq_msg.delivery_mode; + irte.field.vector = irq_msg.vector; + irte.field.destination = irq_msg.destination; + if (!using_x2apic) + /* xAPIC in flat mode: APIC ID in 47:40 (of 63:32) */ + irte.field.destination <<= 8; + irte.field.sq = VTD_IRTE_SQ_VERIFY_FULL_SID; + irte.field.svt = VTD_IRTE_SVT_VERIFY_SID_SQ; + +update_irte: + vtd_update_irte(base_index + vector, irte); + + return base_index + vector; +} + +static void vtd_cell_exit(struct cell *cell) +{ + page_free(&mem_pool, cell->arch.vtd.pg_structs.root_table, 1); + + /* + * Note that reservation regions of IOAPICs won't be released because + * they might be shared with other cells + */ +} + +void iommu_config_commit(struct cell *cell_added_removed) +{ + void *inv_queue = unit_inv_queue; + void *reg_base = dmar_reg_base; + unsigned int n; + + if (cell_added_removed) + vtd_init_fault_nmi(); + + if (cell_added_removed == &root_cell) { + for (n = 0; n < dmar_units; n++) { + vtd_init_unit(reg_base, inv_queue); + reg_base += DMAR_MMIO_SIZE; + inv_queue += PAGE_SIZE; + } + dmar_units_initialized = true; + } else { + if (cell_added_removed) + vtd_flush_domain_caches(cell_added_removed->config->id); + vtd_flush_domain_caches(root_cell.config->id); + } +} + +static void vtd_restore_ir(unsigned int unit_no, void *reg_base) +{ + struct vtd_emulation *unit = &root_cell_units[unit_no]; + void *inv_queue = unit_inv_queue + unit_no * PAGE_SIZE; + void *root_inv_queue; + u64 iqh; + int n; + + mmio_write64(reg_base + VTD_IRTA_REG, unit->irta); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_SIRTP, 1); + vtd_submit_iq_request(reg_base, inv_queue, &inv_global_int); + + vtd_update_gcmd_reg(reg_base, VTD_GCMD_QIE, 0); + mmio_write64(reg_base + VTD_IQT_REG, 0); + mmio_write64(reg_base + VTD_IQA_REG, unit->iqa); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_QIE, 1); + + /* + * Restore invalidation queue head pointer by issuing dummy requests + * until the hardware is in sync with the Linux state again. + */ + iqh =unit->iqh; + root_inv_queue = paging_get_guest_pages(NULL, unit->iqa, 1, + PAGE_DEFAULT_FLAGS); + if (root_inv_queue) + while (mmio_read64(reg_base + VTD_IQH_REG) != iqh) + vtd_submit_iq_request(reg_base, root_inv_queue, NULL); + else + printk("WARNING: Failed to restore invalidation queue head\n"); + + vtd_update_gcmd_reg(reg_base, VTD_GCMD_IRE, 1); + + /* Mask events */ + mmio_write32_field(reg_base + VTD_FECTL_REG, VTD_FECTL_IM, 1); + + /* Restore, unmasking with the last write. */ + for (n = ARRAY_SIZE(unit->fault_event_regs) - 1; n >= 0; n--) + mmio_write32(reg_base + VTD_FECTL_REG + n * 4, + unit->fault_event_regs[n]); +} + +static int vtd_init_ir_emulation(unsigned int unit_no, void *reg_base) +{ + struct vtd_emulation *unit = &root_cell_units[unit_no]; + unsigned long base, size; + unsigned int n; + u64 iqt; + + root_cell.arch.vtd.ir_emulation = true; + + base = system_config->platform_info.iommu_units[unit_no].base; + mmio_region_register(&root_cell, base, PAGE_SIZE, + vtd_unit_access_handler, unit); + + unit->irta = mmio_read64(reg_base + VTD_IRTA_REG); + unit->irt_entries = 2 << (unit->irta & VTD_IRTA_SIZE_MASK); + + size = PAGE_ALIGN(sizeof(struct vtd_irte_usage) * unit->irt_entries); + unit->irte_map = page_alloc(&mem_pool, size / PAGE_SIZE); + if (!unit->irte_map) + return -ENOMEM; + + iqt = mmio_read64(reg_base + VTD_IQT_REG); + while (mmio_read64(reg_base + VTD_IQH_REG) != iqt) + cpu_relax(); + unit->iqh = iqt; + + unit->iqa = mmio_read64(reg_base + VTD_IQA_REG); + if (unit->iqa & ~VTD_IQA_ADDR_MASK) + return trace_error(-EIO); + + for (n = 0; n < ARRAY_SIZE(unit->fault_event_regs); n++) + unit->fault_event_regs[n] = + mmio_read32(reg_base + VTD_FECTL_REG + n * 4); + + return 0; +} + +static int vtd_init(void) +{ + unsigned long version, caps, ecaps, ctrls, sllps_caps = ~0UL; + unsigned int units, pt_levels, num_did, n; + struct jailhouse_iommu *unit; + void *reg_base; + int err; + + /* n = roundup(log2(VTD_INTERRUPT_LIMIT())) */ + for (n = 0; (1UL << n) < VTD_INTERRUPT_LIMIT(); n++) + ; /* empty loop */ + if (n >= 16) + return trace_error(-EINVAL); + + int_remap_table = + page_alloc(&mem_pool, PAGES(sizeof(union vtd_irte) << n)); + if (!int_remap_table) + return -ENOMEM; + + int_remap_table_size_log2 = n; + + units = iommu_count_units(); + if (units == 0) + return trace_error(-EINVAL); + + dmar_reg_base = page_alloc(&remap_pool, units * PAGES(DMAR_MMIO_SIZE)); + if (!dmar_reg_base) + return trace_error(-ENOMEM); + + unit_inv_queue = page_alloc(&mem_pool, units); + if (!unit_inv_queue) + return -ENOMEM; + + for (n = 0; n < units; n++) { + unit = &system_config->platform_info.iommu_units[n]; + if (unit->type != JAILHOUSE_IOMMU_INTEL) + return trace_error(-EINVAL); + + reg_base = dmar_reg_base + n * DMAR_MMIO_SIZE; + + err = paging_create(&hv_paging_structs, unit->base, unit->size, + (unsigned long)reg_base, + PAGE_DEFAULT_FLAGS | PAGE_FLAG_DEVICE, + PAGING_NON_COHERENT | PAGING_HUGE); + if (err) + return err; + + version = mmio_read64(reg_base + VTD_VER_REG) & VTD_VER_MASK; + if (version < VTD_VER_MIN || version == 0xff) + return trace_error(-EIO); + + printk("DMAR unit @0x%llx/0x%x\n", unit->base, unit->size); + + caps = mmio_read64(reg_base + VTD_CAP_REG); + if (caps & VTD_CAP_SAGAW39) + pt_levels = 3; + else if (caps & VTD_CAP_SAGAW48) + pt_levels = 4; + else + return trace_error(-EIO); + sllps_caps &= caps; + + if (dmar_pt_levels > 0 && dmar_pt_levels != pt_levels) + return trace_error(-EIO); + dmar_pt_levels = pt_levels; + + ecaps = mmio_read64(reg_base + VTD_ECAP_REG); + if (!(ecaps & VTD_ECAP_QI) || !(ecaps & VTD_ECAP_IR) || + (using_x2apic && !(ecaps & VTD_ECAP_EIM))) + return trace_error(-EIO); + + ctrls = mmio_read32(reg_base + VTD_GSTS_REG) & + VTD_GSTS_USED_CTRLS; + if (ctrls != 0) { + if (ctrls != (VTD_GSTS_IRES | VTD_GSTS_QIES)) + return trace_error(-EBUSY); + err = vtd_init_ir_emulation(n, reg_base); + if (err) + return err; + } else if (root_cell.arch.vtd.ir_emulation) { + /* IR+QI must be either on or off in all units */ + return trace_error(-EIO); + } + + num_did = 1 << (4 + (caps & VTD_CAP_NUM_DID_MASK) * 2); + if (num_did < dmar_num_did) + dmar_num_did = num_did; + } + + dmar_units = units; + + /* + * Derive vdt_paging from very similar x86_64_paging, + * replicating 0..3 for 4 levels and 1..3 for 3 levels. + */ + memcpy(vtd_paging, &x86_64_paging[4 - dmar_pt_levels], + sizeof(struct paging) * dmar_pt_levels); + for (n = 0; n < dmar_pt_levels; n++) + vtd_paging[n].set_next_pt = vtd_set_next_pt; + if (!(sllps_caps & VTD_CAP_SLLPS1G)) + vtd_paging[dmar_pt_levels - 3].page_size = 0; + if (!(sllps_caps & VTD_CAP_SLLPS2M)) + vtd_paging[dmar_pt_levels - 2].page_size = 0; + + return vtd_cell_init(&root_cell); +} + +void iommu_prepare_shutdown(void) +{ + void *reg_base = dmar_reg_base; + unsigned int n; + + if (dmar_units_initialized) + for (n = 0; n < dmar_units; n++, reg_base += DMAR_MMIO_SIZE) { + vtd_update_gcmd_reg(reg_base, VTD_GCMD_TE, 0); + vtd_update_gcmd_reg(reg_base, VTD_GCMD_IRE, 0); + if (root_cell.arch.vtd.ir_emulation) + vtd_restore_ir(n, reg_base); + else + vtd_update_gcmd_reg(reg_base, VTD_GCMD_QIE, 0); + } +} + +bool iommu_cell_emulates_ir(struct cell *cell) +{ + return cell->arch.vtd.ir_emulation; +} + +DEFINE_UNIT_SHUTDOWN_STUB(vtd); +DEFINE_UNIT(vtd, "VT-d"); diff --git a/hypervisor/control.c b/hypervisor/control.c new file mode 100644 index 0000000000000000000000000000000000000000..2214406fe0acfa79e7f5f0a4f573fdae7eede739 --- /dev/null +++ b/hypervisor/control.c @@ -0,0 +1,1027 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum msg_type {MSG_REQUEST, MSG_INFORMATION}; +enum failure_mode {ABORT_ON_ERROR, WARN_ON_ERROR}; +enum management_task {CELL_START, CELL_SET_LOADABLE, CELL_DESTROY}; + +/** System configuration as used while activating the hypervisor. */ +struct jailhouse_system *system_config; +/** State structure of the root cell. @ingroup Control */ +struct cell root_cell; + +static spinlock_t shutdown_lock; +static unsigned int num_cells = 1; + +volatile unsigned long panic_in_progress; +unsigned long panic_cpu = -1; + +/** + * CPU set iterator. + * @param cpu Previous CPU ID. + * @param cpu_set CPU set to iterate over. + * @param exception CPU ID to skip if it is contained. + * + * @return Next CPU ID in the set. + * + * @note For internal use only. Use for_each_cpu() or for_each_cpu_except() + * instead. + */ +unsigned int next_cpu(unsigned int cpu, struct cpu_set *cpu_set, + unsigned int exception) +{ + do + cpu++; + while (cpu <= cpu_set->max_cpu_id && + (cpu == exception || !test_bit(cpu, cpu_set->bitmap))); + return cpu; +} + +/** + * Check if a CPU ID is contained in the system's CPU set, i.e. the initial CPU + * set of the root cell. + * @param cpu_id CPU ID to check. + * + * @return True if CPU ID is valid. + */ +bool cpu_id_valid(unsigned long cpu_id) +{ + const unsigned long *system_cpu_set = + jailhouse_cell_cpu_set(&system_config->root_cell); + + return (cpu_id < system_config->root_cell.cpu_set_size * 8 && + test_bit(cpu_id, system_cpu_set)); +} + +/** + * Suspend a remote CPU. + * @param cpu_id ID of the target CPU. + * + * Suspension means that the target CPU is no longer executing cell code or + * arbitrary hypervisor code. It may actively busy-wait in the hypervisor + * context, so the suspension time should be kept short. + * + * The function waits for the target CPU to enter suspended state. + * + * This service can be used to synchronize with other CPUs before performing + * management tasks. + * + * @note This function must not be invoked for the caller's CPU. + * + * @see resume_cpu + * @see arch_reset_cpu + * @see arch_park_cpu + */ +static void suspend_cpu(unsigned int cpu_id) +{ + struct public_per_cpu *target_data = public_per_cpu(cpu_id); + bool target_suspended; + + spin_lock(&target_data->control_lock); + + target_data->suspend_cpu = true; + target_suspended = target_data->cpu_suspended; + + /* + * Acts as memory barrier on certain architectures to make suspend_cpu + * visible. Otherwise, arch_send_event() will take care of that. + */ + spin_unlock(&target_data->control_lock); + + if (!target_suspended) { + /* + * Send a maintenance signal to the target CPU. + * Then, wait for the target CPU to enter the suspended state. + * The target CPU, in turn, will leave the guest and handle the + * request in the event loop. + */ + arch_send_event(target_data); + + while (!target_data->cpu_suspended) + cpu_relax(); + } +} + +void resume_cpu(unsigned int cpu_id) +{ + struct public_per_cpu *target_data = public_per_cpu(cpu_id); + + /* take lock to avoid theoretical race with a pending suspension */ + spin_lock(&target_data->control_lock); + + target_data->suspend_cpu = false; + + spin_unlock(&target_data->control_lock); +} + +/* + * Suspend all CPUs assigned to the cell except the one executing + * the function (if it is in the cell's CPU set) to prevent races. + */ +static void cell_suspend(struct cell *cell) +{ + unsigned int cpu; + + for_each_cpu_except(cpu, cell->cpu_set, this_cpu_id()) + suspend_cpu(cpu); +} + +static void cell_resume(struct cell *cell) +{ + unsigned int cpu; + + for_each_cpu_except(cpu, cell->cpu_set, this_cpu_id()) + resume_cpu(cpu); +} + +/** + * Deliver a message to cell and wait for the reply. + * @param cell Target cell. + * @param message Message code to be sent (JAILHOUSE_MSG_*). + * @param type Message type, defines the valid replies. + * + * @return True if a request message was approved or reception of an + * informational message was acknowledged by the target cell. It also + * returns true if the target cell does not support an active + * communication region, is shut down or in failed state. + * In case of timeout (if enabled) it also stops the cell and put it + * in failed state. + * Returns false on request denial or invalid replies. + */ +static bool cell_exchange_message(struct cell *cell, u32 message, + enum msg_type type) +{ + u64 timeout = cell->config->msg_reply_timeout; + + if (cell->config->flags & JAILHOUSE_CELL_PASSIVE_COMMREG) + return true; + + jailhouse_send_msg_to_cell(&cell->comm_page.comm_region, message); + + while (1) { + u32 reply = cell->comm_page.comm_region.reply_from_cell; + u32 cell_state = cell->comm_page.comm_region.cell_state; + + if (cell_state == JAILHOUSE_CELL_SHUT_DOWN || + cell_state == JAILHOUSE_CELL_FAILED) + return true; + + if ((type == MSG_REQUEST && + reply == JAILHOUSE_MSG_REQUEST_APPROVED) || + (type == MSG_INFORMATION && + reply == JAILHOUSE_MSG_RECEIVED)) + return true; + + if (reply != JAILHOUSE_MSG_NONE) + return false; + + if (cell->config->msg_reply_timeout > 0 && --timeout == 0) { + printk("Timeout expired while waiting for reply from " + "target cell\n"); + cell_suspend(cell); + cell->comm_page.comm_region.cell_state = + JAILHOUSE_CELL_FAILED; + return true; + } + + cpu_relax(); + } +} + +static bool cell_reconfig_ok(struct cell *excluded_cell) +{ + struct cell *cell; + + for_each_non_root_cell(cell) + if (cell != excluded_cell && + cell->comm_page.comm_region.cell_state == + JAILHOUSE_CELL_RUNNING_LOCKED) + return false; + return true; +} + +static void cell_reconfig_completed(void) +{ + struct cell *cell; + + for_each_non_root_cell(cell) + cell_exchange_message(cell, JAILHOUSE_MSG_RECONFIG_COMPLETED, + MSG_INFORMATION); +} + +/** + * Initialize a new cell. + * @param cell Cell to be initialized. + * + * @return 0 on success, negative error code otherwise. + * + * @note Uninitialized fields of the cell data structure must be zeroed. + */ +int cell_init(struct cell *cell) +{ + const unsigned long *config_cpu_set = + jailhouse_cell_cpu_set(cell->config); + unsigned long cpu_set_size = cell->config->cpu_set_size; + struct cpu_set *cpu_set; + int err; + + if (cpu_set_size > PAGE_SIZE) + return trace_error(-EINVAL); + if (cpu_set_size > sizeof(cell->small_cpu_set.bitmap)) { + cpu_set = page_alloc(&mem_pool, 1); + if (!cpu_set) + return -ENOMEM; + } else { + cpu_set = &cell->small_cpu_set; + } + cpu_set->max_cpu_id = cpu_set_size * 8 - 1; + memcpy(cpu_set->bitmap, config_cpu_set, cpu_set_size); + + cell->cpu_set = cpu_set; + + err = mmio_cell_init(cell); + if (err && cell->cpu_set != &cell->small_cpu_set) + page_free(&mem_pool, cell->cpu_set, 1); + + return err; +} + +static void cell_exit(struct cell *cell) +{ + mmio_cell_exit(cell); + + if (cell->cpu_set != &cell->small_cpu_set) + page_free(&mem_pool, cell->cpu_set, 1); +} + +/** + * Apply system configuration changes. + * @param cell_added_removed Cell that was added or removed to/from the + * system or NULL. + * + * @see arch_config_commit + * @see pci_config_commit + */ +void config_commit(struct cell *cell_added_removed) +{ + arch_flush_cell_vcpu_caches(&root_cell); + if (cell_added_removed && cell_added_removed != &root_cell) + arch_flush_cell_vcpu_caches(cell_added_removed); + + arch_config_commit(cell_added_removed); + pci_config_commit(cell_added_removed); +} + +static bool address_in_region(unsigned long addr, + const struct jailhouse_memory *region) +{ + return addr >= region->phys_start && + addr < (region->phys_start + region->size); +} + +static int unmap_from_root_cell(const struct jailhouse_memory *mem) +{ + /* + * arch_unmap_memory_region and mmio_subpage_unregister use the + * virtual address of the memory region for their job. As only the root + * cell has a guaranteed 1:1 mapping, make a copy where we ensure this. + */ + struct jailhouse_memory tmp = *mem; + + tmp.virt_start = tmp.phys_start; + + if (JAILHOUSE_MEMORY_IS_SUBPAGE(&tmp)) { + mmio_subpage_unregister(&root_cell, &tmp); + return 0; + } + + return arch_unmap_memory_region(&root_cell, &tmp); +} + +static int remap_to_root_cell(const struct jailhouse_memory *mem, + enum failure_mode mode) +{ + const struct jailhouse_memory *root_mem; + struct jailhouse_memory overlap; + unsigned int n; + int err = 0; + + for_each_mem_region(root_mem, root_cell.config, n) { + if (address_in_region(mem->phys_start, root_mem)) { + overlap.phys_start = mem->phys_start; + overlap.size = root_mem->size - + (overlap.phys_start - root_mem->phys_start); + if (overlap.size > mem->size) + overlap.size = mem->size; + } else if (address_in_region(root_mem->phys_start, mem)) { + overlap.phys_start = root_mem->phys_start; + overlap.size = mem->size - + (overlap.phys_start - mem->phys_start); + if (overlap.size > root_mem->size) + overlap.size = root_mem->size; + } else + continue; + + overlap.virt_start = root_mem->virt_start + + overlap.phys_start - root_mem->phys_start; + overlap.flags = root_mem->flags; + + if (JAILHOUSE_MEMORY_IS_SUBPAGE(&overlap)) + err = mmio_subpage_register(&root_cell, &overlap); + else + err = arch_map_memory_region(&root_cell, &overlap); + if (err) { + if (mode == ABORT_ON_ERROR) + break; + printk("WARNING: Failed to re-assign memory region " + "to root cell\n"); + } + } + return err; +} + +static void cell_destroy_internal(struct cell *cell) +{ + const struct jailhouse_memory *mem; + unsigned int cpu, n; + struct unit *unit; + + cell->comm_page.comm_region.cell_state = JAILHOUSE_CELL_SHUT_DOWN; + + for_each_cpu(cpu, cell->cpu_set) { + arch_park_cpu(cpu); + + set_bit(cpu, root_cell.cpu_set->bitmap); + public_per_cpu(cpu)->cell = &root_cell; + public_per_cpu(cpu)->failed = false; + memset(public_per_cpu(cpu)->stats, 0, + sizeof(public_per_cpu(cpu)->stats)); + } + + for_each_mem_region(mem, cell->config, n) { + if (!JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) + /* + * This cannot fail. The region was mapped as a whole + * before, thus no hugepages need to be broken up to + * unmap it. + */ + arch_unmap_memory_region(cell, mem); + + if (!(mem->flags & (JAILHOUSE_MEM_COMM_REGION | + JAILHOUSE_MEM_ROOTSHARED))) + remap_to_root_cell(mem, WARN_ON_ERROR); + } + + for_each_unit_reverse(unit) + unit->cell_exit(cell); + arch_cell_destroy(cell); + + config_commit(cell); + + cell_exit(cell); +} + +static int cell_create(struct per_cpu *cpu_data, unsigned long config_address) +{ + unsigned long cfg_page_offs = config_address & PAGE_OFFS_MASK; + unsigned int cfg_pages, cell_pages, cpu, n; + const struct jailhouse_memory *mem; + struct jailhouse_cell_desc *cfg; + unsigned long cfg_total_size; + struct cell *cell, *last; + struct unit *unit; + void *cfg_mapping; + int err; + + /* We do not support creation over non-root cells. */ + if (cpu_data->public.cell != &root_cell) + return -EPERM; + + cell_suspend(&root_cell); + + if (!cell_reconfig_ok(NULL)) { + err = -EPERM; + goto err_resume; + } + + cfg_pages = PAGES(cfg_page_offs + sizeof(struct jailhouse_cell_desc)); + cfg_mapping = paging_get_guest_pages(NULL, config_address, cfg_pages, + PAGE_READONLY_FLAGS); + if (!cfg_mapping) { + err = -ENOMEM; + goto err_resume; + } + + cfg = (struct jailhouse_cell_desc *)(cfg_mapping + cfg_page_offs); + + for_each_cell(cell) + /* + * No bound checking needed, thus strcmp is safe here because + * sizeof(cell->config->name) == sizeof(cfg->name) and + * cell->config->name is guaranteed to be null-terminated. + */ + if (strcmp(cell->config->name, cfg->name) == 0 || + cell->config->id == cfg->id) { + err = -EEXIST; + goto err_resume; + } + + cfg_total_size = jailhouse_cell_config_size(cfg); + cfg_pages = PAGES(cfg_page_offs + cfg_total_size); + if (cfg_pages > NUM_TEMPORARY_PAGES) { + err = trace_error(-E2BIG); + goto err_resume; + } + + if (!paging_get_guest_pages(NULL, config_address, cfg_pages, + PAGE_READONLY_FLAGS)) { + err = -ENOMEM; + goto err_resume; + } + + cell_pages = PAGES(sizeof(*cell) + cfg_total_size); + cell = page_alloc(&mem_pool, cell_pages); + if (!cell) { + err = -ENOMEM; + goto err_resume; + } + + cell->data_pages = cell_pages; + cell->config = ((void *)cell) + sizeof(*cell); + memcpy(cell->config, cfg, cfg_total_size); + + err = cell_init(cell); + if (err) + goto err_free_cell; + + /* don't assign the CPU we are currently running on */ + if (cell_owns_cpu(cell, cpu_data->public.cpu_id)) { + err = trace_error(-EBUSY); + goto err_cell_exit; + } + + /* the root cell's cpu set must be super-set of new cell's set */ + for_each_cpu(cpu, cell->cpu_set) + if (!cell_owns_cpu(&root_cell, cpu)) { + err = trace_error(-EBUSY); + goto err_cell_exit; + } + + err = arch_cell_create(cell); + if (err) + goto err_cell_exit; + + for_each_unit(unit) { + err = unit->cell_init(cell); + if (err) { + for_each_unit_before_reverse(unit, unit) + unit->cell_exit(cell); + goto err_arch_destroy; + } + } + + /* + * Shrinking: the new cell's CPUs are parked, then removed from the root + * cell, assigned to the new cell and get their stats cleared. + */ + for_each_cpu(cpu, cell->cpu_set) { + arch_park_cpu(cpu); + + clear_bit(cpu, root_cell.cpu_set->bitmap); + public_per_cpu(cpu)->cell = cell; + memset(public_per_cpu(cpu)->stats, 0, + sizeof(public_per_cpu(cpu)->stats)); + } + + /* + * Unmap the cell's memory regions from the root cell and map them to + * the new cell instead. + */ + for_each_mem_region(mem, cell->config, n) { + /* + * Unmap exceptions: + * - the communication region is not backed by root memory + * - regions that may be shared with the root cell + */ + if (!(mem->flags & (JAILHOUSE_MEM_COMM_REGION | + JAILHOUSE_MEM_ROOTSHARED))) { + err = unmap_from_root_cell(mem); + if (err) + goto err_destroy_cell; + } + + if (JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) + err = mmio_subpage_register(cell, mem); + else + err = arch_map_memory_region(cell, mem); + if (err) + goto err_destroy_cell; + } + + config_commit(cell); + + cell->comm_page.comm_region.cell_state = JAILHOUSE_CELL_SHUT_DOWN; + + last = &root_cell; + while (last->next) + last = last->next; + last->next = cell; + num_cells++; + + cell_reconfig_completed(); + + printk("Created cell \"%s\"\n", cell->config->name); + + paging_dump_stats("after cell creation"); + + cell_resume(&root_cell); + + return 0; + +err_destroy_cell: + cell_destroy_internal(cell); + /* cell_destroy_internal already calls arch_cell_destroy & cell_exit */ + goto err_free_cell; +err_arch_destroy: + arch_cell_destroy(cell); +err_cell_exit: + cell_exit(cell); +err_free_cell: + page_free(&mem_pool, cell, cell_pages); +err_resume: + cell_resume(&root_cell); + + return err; +} + +static bool cell_shutdown_ok(struct cell *cell) +{ + return cell_exchange_message(cell, JAILHOUSE_MSG_SHUTDOWN_REQUEST, + MSG_REQUEST); +} + +static int cell_management_prologue(enum management_task task, + struct per_cpu *cpu_data, unsigned long id, + struct cell **cell_ptr) +{ + /* We do not support management commands over non-root cells. */ + if (cpu_data->public.cell != &root_cell) + return -EPERM; + + cell_suspend(&root_cell); + + for_each_cell(*cell_ptr) + if ((*cell_ptr)->config->id == id) + break; + + if (!*cell_ptr) { + cell_resume(&root_cell); + return -ENOENT; + } + + /* root cell cannot be managed */ + if (*cell_ptr == &root_cell) { + cell_resume(&root_cell); + return -EINVAL; + } + + if ((task == CELL_DESTROY && !cell_reconfig_ok(*cell_ptr)) || + !cell_shutdown_ok(*cell_ptr)) { + cell_resume(&root_cell); + return -EPERM; + } + + cell_suspend(*cell_ptr); + + return 0; +} + +static int cell_start(struct per_cpu *cpu_data, unsigned long id) +{ + struct jailhouse_comm_region *comm_region; + const struct jailhouse_memory *mem; + unsigned int cpu, n; + struct cell *cell; + int err; + + err = cell_management_prologue(CELL_START, cpu_data, id, &cell); + if (err) + return err; + + if (cell->loadable) { + /* unmap all loadable memory regions from the root cell */ + for_each_mem_region(mem, cell->config, n) + if (mem->flags & JAILHOUSE_MEM_LOADABLE) { + err = unmap_from_root_cell(mem); + if (err) + goto out_resume; + } + + config_commit(NULL); + + cell->loadable = false; + } + + /* + * Present a consistent Communication Region state to the cell. Zero the + * whole region as it might be dirty. This implies: + * - cell_state = JAILHOUSE_CELL_RUNNING (0) + * - msg_to_cell = JAILHOUSE_MSG_NONE (0) + */ + comm_region = &cell->comm_page.comm_region; + memset(&cell->comm_page, 0, sizeof(cell->comm_page)); + + comm_region->revision = COMM_REGION_ABI_REVISION; + memcpy(comm_region->signature, COMM_REGION_MAGIC, + sizeof(comm_region->signature)); + + if (CELL_FLAGS_VIRTUAL_CONSOLE_PERMITTED(cell->config->flags)) + comm_region->flags |= JAILHOUSE_COMM_FLAG_DBG_PUTC_PERMITTED; + if (CELL_FLAGS_VIRTUAL_CONSOLE_ACTIVE(cell->config->flags)) + comm_region->flags |= JAILHOUSE_COMM_FLAG_DBG_PUTC_ACTIVE; + comm_region->console = cell->config->console; + comm_region->pci_mmconfig_base = + system_config->platform_info.pci_mmconfig_base; + + pci_cell_reset(cell); + arch_cell_reset(cell); + + for_each_cpu(cpu, cell->cpu_set) { + public_per_cpu(cpu)->failed = false; + arch_reset_cpu(cpu); + } + + printk("Started cell \"%s\"\n", cell->config->name); + +out_resume: + cell_resume(&root_cell); + + return err; +} + +static int cell_set_loadable(struct per_cpu *cpu_data, unsigned long id) +{ + const struct jailhouse_memory *mem; + unsigned int cpu, n; + struct cell *cell; + int err; + + err = cell_management_prologue(CELL_SET_LOADABLE, cpu_data, id, &cell); + if (err) + return err; + + /* + * Unconditionally park so that the target cell's CPUs don't stay in + * suspension mode. + */ + for_each_cpu(cpu, cell->cpu_set) { + public_per_cpu(cpu)->failed = false; + arch_park_cpu(cpu); + } + + if (cell->loadable) + goto out_resume; + + cell->comm_page.comm_region.cell_state = JAILHOUSE_CELL_SHUT_DOWN; + cell->loadable = true; + + pci_cell_reset(cell); + + /* map all loadable memory regions into the root cell */ + for_each_mem_region(mem, cell->config, n) + if (mem->flags & JAILHOUSE_MEM_LOADABLE) { + err = remap_to_root_cell(mem, ABORT_ON_ERROR); + if (err) + goto out_resume; + } + + config_commit(NULL); + + printk("Cell \"%s\" can be loaded\n", cell->config->name); + +out_resume: + cell_resume(&root_cell); + + return err; +} + +static int cell_destroy(struct per_cpu *cpu_data, unsigned long id) +{ + struct cell *cell, *previous; + int err; + + err = cell_management_prologue(CELL_DESTROY, cpu_data, id, &cell); + if (err) + return err; + + printk("Closing cell \"%s\"\n", cell->config->name); + + cell_destroy_internal(cell); + + previous = &root_cell; + while (previous->next != cell) + previous = previous->next; + previous->next = cell->next; + num_cells--; + + page_free(&mem_pool, cell, cell->data_pages); + paging_dump_stats("after cell destruction"); + + cell_reconfig_completed(); + + cell_resume(&root_cell); + + return 0; +} + +static int cell_get_state(struct per_cpu *cpu_data, unsigned long id) +{ + struct cell *cell; + + if (cpu_data->public.cell != &root_cell) + return -EPERM; + + /* + * We do not need explicit synchronization with cell_create/destroy + * because their cell_suspend(root_cell) will not return before we left + * this hypercall. + */ + for_each_cell(cell) + if (cell->config->id == id) { + u32 state = cell->comm_page.comm_region.cell_state; + + switch (state) { + case JAILHOUSE_CELL_RUNNING: + case JAILHOUSE_CELL_RUNNING_LOCKED: + case JAILHOUSE_CELL_SHUT_DOWN: + case JAILHOUSE_CELL_FAILED: + case JAILHOUSE_CELL_FAILED_COMM_REV: + return state; + default: + return -EINVAL; + } + } + return -ENOENT; +} + +/** + * Perform all CPU-unrelated hypervisor shutdown steps. + */ +void shutdown(void) +{ + struct unit *unit; + + pci_prepare_handover(); + arch_prepare_shutdown(); + + for_each_unit_reverse(unit) + unit->shutdown(); +} + +static int hypervisor_disable(struct per_cpu *cpu_data) +{ + static volatile unsigned int waiting_cpus; + static bool do_common_shutdown; + unsigned int this_cpu = cpu_data->public.cpu_id; + unsigned int cpu; + int state, ret; + + /* We do not support shutdown over non-root cells. */ + if (cpu_data->public.cell != &root_cell) + return -EPERM; + + /* + * This may race against another root cell CPU invoking a different + * management hypercall (cell create, set loadable, start, destroy). + * Those suspend the root cell to protect against concurrent requests. + * We can't do this here because all root cell CPUs will invoke this + * function, and cell_suspend doesn't support such a scenario. We are + * safe nevertheless because we only need to see a consistent num_cells + * that is not increasing anymore once the shutdown was started: + * + * If another CPU in a management hypercall already called cell_suspend, + * it is now waiting for this CPU to react. In this case, we see + * num_cells prior to any change, can start the shutdown if it is 1, and + * will prevent the other CPU from changing it anymore. This is because + * we are taking one CPU away from the hypervisor when leaving shutdown. + * This will lock up the root cell (which is violating the hypercall + * protocol), but only if it was the last cell. + * + * If the other CPU already returned from cell_suspend, we cannot be + * running in parallel before that CPU releases the root cell again via + * cell_resume. In that case, we will see the result of the change. + * + * shutdown_lock is here to protect shutdown_state, waiting_cpus and + * do_common_shutdown. + */ + spin_lock(&shutdown_lock); + + if (cpu_data->public.shutdown_state == SHUTDOWN_NONE) { + state = num_cells == 1 ? SHUTDOWN_STARTED : -EBUSY; + for_each_cpu(cpu, root_cell.cpu_set) + public_per_cpu(cpu)->shutdown_state = state; + } + + if (cpu_data->public.shutdown_state == SHUTDOWN_STARTED) { + do_common_shutdown = true; + waiting_cpus++; + ret = 0; + } else { + ret = cpu_data->public.shutdown_state; + cpu_data->public.shutdown_state = SHUTDOWN_NONE; + } + + spin_unlock(&shutdown_lock); + + if (ret < 0) + return ret; + + /* + * The shutdown will change hardware behavior, and we have to avoid + * that one CPU already turns it to native mode while another makes use + * of it or runs into a hypervisor trap. This barrier prevents such + * scenarios. + */ + while (waiting_cpus < hypervisor_header.online_cpus) + cpu_relax(); + + spin_lock(&shutdown_lock); + + if (do_common_shutdown) { + /* + * The first CPU to get here changes common settings to native. + */ + printk("Shutting down hypervisor\n"); + shutdown(); + do_common_shutdown = false; + } + printk(" Releasing CPU %d\n", this_cpu); + + spin_unlock(&shutdown_lock); + + return 0; +} + +static long hypervisor_get_info(struct per_cpu *cpu_data, unsigned long type) +{ + switch (type) { + case JAILHOUSE_INFO_MEM_POOL_SIZE: + return mem_pool.pages; + case JAILHOUSE_INFO_MEM_POOL_USED: + return mem_pool.used_pages; + case JAILHOUSE_INFO_REMAP_POOL_SIZE: + return remap_pool.pages; + case JAILHOUSE_INFO_REMAP_POOL_USED: + return remap_pool.used_pages; + case JAILHOUSE_INFO_NUM_CELLS: + return num_cells; + default: + return -EINVAL; + } +} + +static int cpu_get_info(struct per_cpu *cpu_data, unsigned long cpu_id, + unsigned long type) +{ + if (!cpu_id_valid(cpu_id)) + return -EINVAL; + + /* + * We do not need explicit synchronization with cell_destroy because + * its cell_suspend(root_cell + this_cell) will not return before we + * left this hypercall. + */ + if (cpu_data->public.cell != &root_cell && + !cell_owns_cpu(cpu_data->public.cell, cpu_id)) + return -EPERM; + + if (type == JAILHOUSE_CPU_INFO_STATE) { + return public_per_cpu(cpu_id)->failed ? JAILHOUSE_CPU_FAILED : + JAILHOUSE_CPU_RUNNING; + } else if (type >= JAILHOUSE_CPU_INFO_STAT_BASE && + type - JAILHOUSE_CPU_INFO_STAT_BASE < JAILHOUSE_NUM_CPU_STATS) { + type -= JAILHOUSE_CPU_INFO_STAT_BASE; + return public_per_cpu(cpu_id)->stats[type] & BIT_MASK(30, 0); + } else + return -EINVAL; +} + +/** + * Handle hypercall invoked by a cell. + * @param code Hypercall code. + * @param arg1 First hypercall argument. + * @param arg2 Seconds hypercall argument. + * + * @return Value that shall be passed to the caller of the hypercall on return. + * + * @note If @c arg1 and @c arg2 are valid depends on the hypercall code. + */ +long hypercall(unsigned long code, unsigned long arg1, unsigned long arg2) +{ + struct per_cpu *cpu_data = this_cpu_data(); + + cpu_data->public.stats[JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL]++; + + switch (code) { + case JAILHOUSE_HC_DISABLE: + return hypervisor_disable(cpu_data); + case JAILHOUSE_HC_CELL_CREATE: + return cell_create(cpu_data, arg1); + case JAILHOUSE_HC_CELL_START: + return cell_start(cpu_data, arg1); + case JAILHOUSE_HC_CELL_SET_LOADABLE: + return cell_set_loadable(cpu_data, arg1); + case JAILHOUSE_HC_CELL_DESTROY: + return cell_destroy(cpu_data, arg1); + case JAILHOUSE_HC_HYPERVISOR_GET_INFO: + return hypervisor_get_info(cpu_data, arg1); + case JAILHOUSE_HC_CELL_GET_STATE: + return cell_get_state(cpu_data, arg1); + case JAILHOUSE_HC_CPU_GET_INFO: + return cpu_get_info(cpu_data, arg1, arg2); + case JAILHOUSE_HC_DEBUG_CONSOLE_PUTC: + if (!CELL_FLAGS_VIRTUAL_CONSOLE_PERMITTED( + cpu_data->public.cell->config->flags)) + return trace_error(-EPERM); + printk("%c", (char)arg1); + return 0; + default: + return -ENOSYS; + } +} + +/** + * Stops the current CPU on panic and prevents any execution on it until the + * system is rebooted. + * + * @note This service should be used when facing an unrecoverable error of the + * hypervisor. + * + * @see panic_park + */ +void __attribute__((noreturn)) panic_stop(void) +{ + struct cell *cell = this_cell(); + + panic_printk("Stopping CPU %d (Cell: \"%s\")\n", this_cpu_id(), + cell && cell->config ? cell->config->name : ""); + + if (phys_processor_id() == panic_cpu) + panic_in_progress = 0; + + arch_panic_stop(); +} + +/** + * Parks the current CPU on panic, allowing to restart it by resetting the + * cell's CPU state. + * + * @note This service should be used when facing an error of a cell CPU, e.g. a + * cell boundary violation. + * + * @see panic_stop + */ +void panic_park(void) +{ + struct cell *cell = this_cell(); + bool cell_failed = true; + unsigned int cpu; + + panic_printk("Parking CPU %d (Cell: \"%s\")\n", this_cpu_id(), + cell->config->name); + + this_cpu_public()->failed = true; + for_each_cpu(cpu, cell->cpu_set) + if (!public_per_cpu(cpu)->failed) { + cell_failed = false; + break; + } + if (cell_failed) + cell->comm_page.comm_region.cell_state = JAILHOUSE_CELL_FAILED; + + arch_panic_park(); + + if (phys_processor_id() == panic_cpu) + panic_in_progress = 0; +} diff --git a/hypervisor/gcov.c b/hypervisor/gcov.c new file mode 100644 index 0000000000000000000000000000000000000000..ec3a0d9e1747705ef9c14b9112b6ab97513f724b --- /dev/null +++ b/hypervisor/gcov.c @@ -0,0 +1,55 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include +#include + +extern unsigned long __init_array_start[], __init_array_end[]; + +/* the actual data structure is bigger but we just need to know the version + * independent beginning to link the elements to a list */ +struct gcov_min_info { + unsigned int version; + struct gcov_min_info *next; +}; + +void gcov_init(void) { + unsigned long *iarray = __init_array_start; + unsigned long *iarray_end = __init_array_end; + void (*__init_func)(void); + + while (iarray < iarray_end) { + __init_func = (void(*)(void))iarray[0]; + iarray++; + __init_func(); + } +} + +void __gcov_init(struct gcov_min_info *info); +void __gcov_merge_add(void *counters, unsigned int n_counters); +void __gcov_exit(void); + +/* just link them all together and leave the head in the header + * where a processing tool can find it */ +void __gcov_init(struct gcov_min_info *info) +{ + info->next = (struct gcov_min_info *)hypervisor_header.gcov_info_head; + hypervisor_header.gcov_info_head = info; +} + +/* Satisfy the linker, never called */ +void __gcov_merge_add(void *counters, unsigned int n_counters) +{ +} + +void __gcov_exit(void) +{ +} diff --git a/hypervisor/hypervisor.lds.S b/hypervisor/hypervisor.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..ca06ab20bc687ef98b15db781e90c2bf3fd537b8 --- /dev/null +++ b/hypervisor/hypervisor.lds.S @@ -0,0 +1,65 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#include +#include + +SECTIONS +{ + . = JAILHOUSE_BASE; + .header : { *(.header) } + + . = ALIGN(16); + .text : { + __text_start = .; + *(.text) + } + + . = ALIGN(16); + .rodata : { *(.rodata) } + + . = ALIGN(16); + .data : { *(.data) } + + . = ALIGN(8); + .init_array : { + __init_array_start = .; + *(SORT(.init_array.*)) *(.init_array) + __init_array_end = .; + } + + .units : { + __unit_array_start = .; + *(.units); + __unit_array_end = .; + } + + ARCH_SECTIONS + + /* The console section shall only contain the hypervisor console. This + * section and the next section must be aligned to PAGE_SIZE, as we + * will map the console section, and only that section, as a whole page + * to the root cell. */ + + . = ALIGN(PAGE_SIZE); + .console : { *(.console) } + + . = ALIGN(PAGE_SIZE); + .bss : { *(.bss) } + + . = ALIGN(PAGE_SIZE); + __page_pool = .; + + .eh_frame : { *(.eh_frame*) } +} diff --git a/hypervisor/include/jailhouse/bitops.h b/hypervisor/include/jailhouse/bitops.h new file mode 100644 index 0000000000000000000000000000000000000000..e98381d04d2f6e2e57ed048aa4ca801b1e006139 --- /dev/null +++ b/hypervisor/include/jailhouse/bitops.h @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_BITOPS_H +#define _JAILHOUSE_BITOPS_H + +#include +#include + +static inline __attribute__((always_inline)) void +clear_bit(unsigned int nr, volatile unsigned long *addr) +{ + addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG)); +} + +static inline __attribute__((always_inline)) void +set_bit(unsigned int nr, volatile unsigned long *addr) +{ + addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); +} + +#endif /* !_JAILHOUSE_BITOPS_H */ diff --git a/hypervisor/include/jailhouse/cell.h b/hypervisor/include/jailhouse/cell.h new file mode 100644 index 0000000000000000000000000000000000000000..c804a5df00eadcf4f0a6ab7fc8e9607f7ed3d6f8 --- /dev/null +++ b/hypervisor/include/jailhouse/cell.h @@ -0,0 +1,76 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_CELL_H +#define _JAILHOUSE_CELL_H + +#include +#include +#include +#include +#include + +#include +#include + +/** Cell-related states. */ +struct cell { + union { + /** Communication region. */ + struct jailhouse_comm_region comm_region; + /** Padding to full page size. */ + u8 padding[PAGE_SIZE]; + } __attribute__((aligned(PAGE_SIZE))) comm_page; + /**< Page containing the communication region (shared with cell). */ + + /** Architecture-specific fields. */ + struct arch_cell arch; + + /** Number of pages used for storing cell-specific states and + * configuration data. */ + unsigned int data_pages; + /** Pointer to static cell description. */ + struct jailhouse_cell_desc *config; + + /** Pointer to cell's CPU set. */ + struct cpu_set *cpu_set; + /** Stores the cell's CPU set if small enough. */ + struct cpu_set small_cpu_set; + + /** True while the cell can be loaded by the root cell. */ + bool loadable; + + /** Pointer to next cell in the system. */ + struct cell *next; + + /** List of PCI devices assigned to this cell. */ + struct pci_device *pci_devices; + + /** Lock protecting changes to mmio_locations, mmio_handlers, and + * num_mmio_regions. */ + spinlock_t mmio_region_lock; + /** Generation counter of mmio_locations, mmio_handlers, and + * num_mmio_regions. */ + volatile unsigned long mmio_generation; + /** MMIO region description table. */ + struct mmio_region_location *mmio_locations; + /** MMIO region handler table. */ + struct mmio_region_handler *mmio_handlers; + /** Number of MMIO regions in use. */ + unsigned int num_mmio_regions; + /** Maximum number of MMIO regions. */ + unsigned int max_mmio_regions; +}; + +extern struct cell root_cell; + +#endif /* !_JAILHOUSE_CELL_H */ diff --git a/hypervisor/include/jailhouse/control.h b/hypervisor/include/jailhouse/control.h new file mode 100644 index 0000000000000000000000000000000000000000..f2b07c0d4fa882a6e0145267e5bab92206969f8d --- /dev/null +++ b/hypervisor/include/jailhouse/control.h @@ -0,0 +1,293 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +#define SHUTDOWN_NONE 0 +#define SHUTDOWN_STARTED 1 + +#define INVALID_CPU_ID ~(0U) + +extern volatile unsigned long panic_in_progress; +extern unsigned long panic_cpu; + +/** + * @defgroup Control Control Subsystem + * + * The control subsystem provides services for managing cells and the + * hypervisor during runtime. It implements the hypercall interface and + * performs the required access control and parameter validation for it. + * + * @{ + */ + +extern struct jailhouse_system *system_config; + +unsigned int next_cpu(unsigned int cpu, struct cpu_set *cpu_set, + unsigned int exception); + +/** + * Get the first CPU in a given set. + * @param set CPU set. + * + * @return First CPU in set, or max_cpu_id + 1 if the set is empty. + */ +#define first_cpu(set) next_cpu(INVALID_CPU_ID, (set), INVALID_CPU_ID) + +/** + * Loop-generating macro for iterating over all CPUs in a set. + * @param cpu Iteration variable holding the current CPU ID + * (unsigned int). + * @param set CPU set to iterate over (struct cpu_set). + * + * @see for_each_cpu_except + */ +#define for_each_cpu(cpu, set) for_each_cpu_except(cpu, set, -1) + +/** + * Loop-generating macro for iterating over all CPUs in a set, except the + * specified one. + * @param cpu Iteration variable holding the current CPU ID + * (unsigned int). + * @param set CPU set to iterate over (struct cpu_set). + * @param exception CPU to skip if it is part of the set. + * + * @see for_each_cpu + */ +#define for_each_cpu_except(cpu, set, exception) \ + for ((cpu) = -1; \ + (cpu) = next_cpu((cpu), (set), (exception)), \ + (cpu) <= (set)->max_cpu_id; \ + ) + +/** + * Loop-generating macro for iterating over all registered cells. + * @param cell Iteration variable holding the reference to the current + * cell (struct cell *). + * + * @see for_each_non_root_cell + */ +#define for_each_cell(cell) \ + for ((cell) = &root_cell; (cell); (cell) = (cell)->next) + +/** + * Loop-generating macro for iterating over all registered cells, expect the + * root cell. + * @param cell Iteration variable holding the reference to the current + * cell (struct cell *). + * + * @see for_each_cell + */ +#define for_each_non_root_cell(cell) \ + for ((cell) = root_cell.next; (cell); (cell) = (cell)->next) + +/** + * Loop-generating macro for iterating over all memory regions of a + * configuration. + * @param mem Iteration variable holding the reference to the current + * memory region (const struct jailhouse_memory *). + * @param config Cell or system configuration containing the regions. + * @param counter Helper variable (unsigned int). + */ +#define for_each_mem_region(mem, config, counter) \ + for ((mem) = jailhouse_cell_mem_regions(config), (counter) = 0; \ + (counter) < (config)->num_memory_regions; \ + (mem)++, (counter)++) + +/** + * Check if the CPU is assigned to the specified cell. + * @param cell Cell the CPU may belong to. + * @param cpu_id ID of the CPU. + * + * @return True if the CPU is assigned to the cell. + */ +static inline bool cell_owns_cpu(struct cell *cell, unsigned int cpu_id) +{ + return (cpu_id <= cell->cpu_set->max_cpu_id && + test_bit(cpu_id, cell->cpu_set->bitmap)); +} + +bool cpu_id_valid(unsigned long cpu_id); + +int cell_init(struct cell *cell); + +void config_commit(struct cell *cell_added_removed); + +long hypercall(unsigned long code, unsigned long arg1, unsigned long arg2); + +void shutdown(void); + +void __attribute__((noreturn)) panic_stop(void); +void panic_park(void); + +/** + * Resume a suspended remote CPU. + * @param cpu_id ID of the target CPU. + * + * @note This function must not be invoked for the caller's CPU. + * + * @see suspend_cpu + */ +void resume_cpu(unsigned int cpu_id); + +/** + * Reset a suspended remote CPU and resumes its execution. + * @param cpu_id ID of the target CPU. + * + * Sets the target CPU into the architecture-specific reset set and resumes its + * execution. + * + * @note This function must not be invoked for the caller's CPU or if the + * target CPU is not in suspend state. + * + * @see suspend_cpu + */ +void arch_reset_cpu(unsigned int cpu_id); + +/** + * Park a suspended remote CPU. + * @param cpu_id ID of the target CPU. + * + * Parking means that the target CPU does not execute cell code but can handle + * asynchronous events again. Parking is not implemented as busy-waiting and + * may set the CPU into an appropriate power-saving mode. The CPU can therefore + * be left in this state for an undefined time. + * + * Parking may destroy the cell-visible CPU state and cannot be used to resume + * cell execution in the previous state without additional measures. + * + * @note This function must not be invoked for the caller's CPU or if the + * target CPU is not in suspend state. + * + * @see suspend_cpu + */ +void arch_park_cpu(unsigned int cpu_id); + +/** + * Send internal event to remote CPU. + * @param cpu_id ID of the target CPU. + * + * When the state of the target CPU was updated and action is required on the + * remote side, this function can be called. Processing of the state change is + * architecture specific. + * + * The caller of this function is required to have performed the state changes + * under a spinlock and called spin_unlock prior to this. The implementation of + * arch_send_event() has to account for the case when spin_unlock does not + * imply a memory barrier and issue this explicitly. + */ +void arch_send_event(struct public_per_cpu *target_data); + +/** + * Performs the architecture-specific steps for mapping a memory region into a + * cell's address space. + * @param cell Cell for which the mapping shall be done. + * @param mem Memory region to map. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_unmap_memory_region + */ +int arch_map_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); + +/** + * Performs the architecture-specific steps for unmapping a memory region from + * a cell's address space. + * @param cell Cell for which the unmapping shall be done. + * @param mem Memory region to unmap. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_map_memory_region + */ +int arch_unmap_memory_region(struct cell *cell, + const struct jailhouse_memory *mem); + +/** + * Performs the architecture-specific steps for invalidating memory caches + * after memory regions have been unmapped from a cell. + * This function should be called after memory got unmapped or memory access + * got restricted, and the cell should keep running. + * @param cell Cell for which the caches should get flushed + * + * @see public_per_cpu::flush_vcpu_caches + */ +void arch_flush_cell_vcpu_caches(struct cell *cell); + +/** + * Performs the architecture-specific steps for creating a new cell. + * @param cell Data structure of the new cell. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_cell_destroy + */ +int arch_cell_create(struct cell *cell); + +/** + * Performs the architecture-specific steps for destroying a cell. + * @param cell Cell to be destroyed. + * + * @see arch_cell_create + */ +void arch_cell_destroy(struct cell *cell); + +/** + * Performs the architecture-specific steps for resetting a cell. + * @param cell Cell to be reset. + * + * @note This function shall not reset individual cell CPUs. Instead, this is + * triggered by the core via arch_reset_cpu(). + * + * @see arch_reset_cpu + */ +void arch_cell_reset(struct cell *cell); + +/** + * Performs the architecture-specific steps for applying configuration changes. + * @param cell_added_removed Cell that was added or removed to/from the + * system or NULL. + * + * @see config_commit + * @see pci_config_commit + */ +void arch_config_commit(struct cell *cell_added_removed); + +/** + * Architecture-specific preparations before shutting down the hypervisor. + */ +void arch_prepare_shutdown(void); + +/** + * Performs the architecture-specifc steps to stop the current CPU on panic. + * + * @note This function never returns. + * + * @see panic_stop + */ +void __attribute__((noreturn)) arch_panic_stop(void); + +/** + * Performs the architecture-specific steps to park the current CPU on panic. + * + * @note This function only marks the CPU as parked and then returns to the + * caller. + * + * @see panic_park + */ +void arch_panic_park(void); + +/** @} */ diff --git a/hypervisor/include/jailhouse/entry.h b/hypervisor/include/jailhouse/entry.h new file mode 100644 index 0000000000000000000000000000000000000000..26360a6e7094b14062e632c812a1478669053e1b --- /dev/null +++ b/hypervisor/include/jailhouse/entry.h @@ -0,0 +1,117 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_ENTRY_H +#define _JAILHOUSE_ENTRY_H + +#include +#include + +#include + +#define EPERM 1 +#define ENOENT 2 +#define EIO 5 +#define E2BIG 7 +#define ENOMEM 12 +#define EBUSY 16 +#define EEXIST 17 +#define ENODEV 19 +#define EINVAL 22 +#define ERANGE 34 +#define ENOSYS 38 + +struct per_cpu; +struct cell; + +/** + * @defgroup Setup Setup Subsystem + * + * This subsystem coordinates the handover from Linux to the hypervisor. + * + * @{ + */ + +extern struct jailhouse_header hypervisor_header; + +/** + * Architecture-specific entry point for enabling the hypervisor. + * @param cpu_id Logical ID of the calling CPU. + * + * @return 0 on success, negative error code otherwise. + * + * The functions always returns the same value on each CPU it is invoked on. + * + * @note This function has to be called for every configured CPU or the setup + * will fail. + * + * @see entry + * @see jailhouse_entry + */ +int arch_entry(unsigned int cpu_id); + +/** + * Entry point for enabling the hypervisor. + * @param cpu_id Logical ID of the calling CPU. + * @param cpu_data Data structure of the calling CPU. + * + * @return 0 on success, negative error code otherwise. + * + * The functions is called by arch_entry(). It always returns the same value on + * each CPU it is invoked on. + * + * @note This function has to be called for every configured CPU or the setup + * will fail. + * + * @see arch_entry + */ +int entry(unsigned int cpu_id, struct per_cpu *cpu_data); + +/** + * Perform architecture-specific early setup steps. + * + * @return 0 on success, negative error code otherwise. + * + * @note This is called over the master CPU that performs CPU-unrelated setup + * steps. + */ +int arch_init_early(void); + +/** + * Perform architecture-specific CPU setup steps. + * @param cpu_data Data structure of the calling CPU. + * + * @return 0 on success, negative error code otherwise. + */ +int arch_cpu_init(struct per_cpu *cpu_data); + +/** + * Perform architecture-specific activation of the hypervisor mode. + * + * @note This function does not return to the caller but rather resumes Linux + * in guest mode at the point arch_entry() would return to. + */ +void __attribute__((noreturn)) arch_cpu_activate_vmm(void); + +/** + * Perform architecture-specific restoration of the CPU state on setup + * failures or after disabling the hypervisor. + * @param cpu_id ID of the calling CPU. + * @param return_code Return value to pass to Linux. + * + * @note Depending on the architectural implementation, this function may not + * return to the caller but rather jump to the target Linux context. + */ +void arch_cpu_restore(unsigned int cpu_id, int return_code); + +/** @} */ +#endif /* !_JAILHOUSE_ENTRY_H */ diff --git a/hypervisor/include/jailhouse/gcov.h b/hypervisor/include/jailhouse/gcov.h new file mode 100644 index 0000000000000000000000000000000000000000..b0a13e2b7ef818d4fea697c435d6fd2c866074be --- /dev/null +++ b/hypervisor/include/jailhouse/gcov.h @@ -0,0 +1,17 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifdef CONFIG_JAILHOUSE_GCOV +void gcov_init(void); +#else +static inline void gcov_init(void) {} +#endif diff --git a/hypervisor/include/jailhouse/gen-defines.h b/hypervisor/include/jailhouse/gen-defines.h new file mode 100644 index 0000000000000000000000000000000000000000..d42fe255fe6d2e8f01ea44644e8bef9c1c2780dd --- /dev/null +++ b/hypervisor/include/jailhouse/gen-defines.h @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Derived from linux/include/linux/kbuild.h: + * + * Copyright (c) Linux kernel developers, 2014 + */ + +#ifndef _JAILHOUSE_GEN_DEFINES_H +#define _JAILHOUSE_GEN_DEFINES_H + +#define DEFINE(sym, val) \ + asm volatile("\n=>" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n=>" : : ) + +#define OFFSET(sym, str, mem) \ + DEFINE(sym, __builtin_offsetof(struct str, mem)) + +#define COMMENT(x) \ + asm volatile("\n=>#" x) + +#endif diff --git a/hypervisor/include/jailhouse/header.h b/hypervisor/include/jailhouse/header.h new file mode 100644 index 0000000000000000000000000000000000000000..518bc5cb61789ed27fb8b185127d1d7ee7c1afb1 --- /dev/null +++ b/hypervisor/include/jailhouse/header.h @@ -0,0 +1,96 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define JAILHOUSE_SIGNATURE "JAILHOUS" + +#define HYP_STUB_ABI_LEGACY 0 +#define HYP_STUB_ABI_OPCODE 1 + + +#ifdef __ASSEMBLY__ + +#define __JH_CONST_UL(x) x + +#else /* !__ASSEMBLY__ */ + +#define __JH_CONST_UL(x) x ## UL + +/** + * @ingroup Setup + * @{ + */ + +/** + * Hypervisor entry point. + * + * @see arch_entry + */ +typedef int (*jailhouse_entry)(unsigned int); + +struct jailhouse_virt_console { + unsigned int busy; + unsigned int tail; + /* current implementation requires the size of the content to be a + * power of two */ + char content[2048]; +}; + +/** + * Hypervisor description. + * Located at the beginning of the hypervisor binary image and loaded by + * the driver (which also initializes some fields). + */ +struct jailhouse_header { + /** Signature "JAILHOUS" used for basic validity check of the + * hypervisor image. + * @note Filled at build time. */ + char signature[8]; + /** Size of hypervisor core. + * It starts with the hypervisor's header and ends after its bss + * section. Rounded up to page boundary. + * @note Filled at build time. */ + unsigned long core_size; + /** Size of the per-CPU data structure. + * @note Filled at build time. */ + unsigned long percpu_size; + /** Entry point (arch_entry()). + * @note Filled at build time. */ + int (*entry)(unsigned int); + /** Offset of the console page inside the hypervisor memory + * @note Filled at build time. */ + unsigned long console_page; + /** Pointer to the first struct gcov_info + * @note Filled at build time */ + void *gcov_info_head; + + /** Configured maximum logical CPU ID + 1. + * @note Filled by Linux loader driver before entry. */ + unsigned int max_cpus; + /** Number of online CPUs that will call the entry function. + * @note Filled by Linux loader driver before entry. */ + unsigned int online_cpus; + /** Virtual base address of the debug console device (if used). + * @note Filled by Linux loader driver on ARM and x86 before entry. + * Filled by arch_entry on ARM64. */ + void *debug_console_base; + + /** Physical address of Linux's hyp-stubs. + * @note Filled by Linux loader driver before entry. */ + unsigned long long arm_linux_hyp_vectors; + /** Denotes hyp-stub ABI for arm and arm64: + * @note Filled by Linux loader driver before entry. */ + unsigned int arm_linux_hyp_abi; +}; + +#endif /* !__ASSEMBLY__ */ diff --git a/hypervisor/include/jailhouse/ivshmem.h b/hypervisor/include/jailhouse/ivshmem.h new file mode 100644 index 0000000000000000000000000000000000000000..9153d4a18d687cbd4b6555d05729a49324df3468 --- /dev/null +++ b/hypervisor/include/jailhouse/ivshmem.h @@ -0,0 +1,86 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2019 + * + * Authors: + * Henning Schild + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_IVSHMEM_H +#define _JAILHOUSE_IVSHMEM_H + +#include +#include + +#define IVSHMEM_MSIX_VECTORS PCI_EMBEDDED_MSIX_VECTS + +#include + +#define IVSHMEM_CFG_SIZE 0x80 + +#define IVSHMEM_INT_ENABLE 0x1 + +/** + * @defgroup IVSHMEM ivshmem + * @{ + */ + +struct ivshmem_link; + +struct ivshmem_endpoint { + u32 cspace[IVSHMEM_CFG_SIZE / sizeof(u32)]; + /** Lock protecting accesses to irq_cache and int_ctrl_reg, also + * synchronizing interrupt submissions with device shutdown. */ + spinlock_t irq_lock; + u32 int_ctrl_reg; + struct arch_ivshmem_irq_cache irq_cache; + struct pci_device *device; + struct ivshmem_link *link; + const struct jailhouse_memory *shmem; + u32 ioregion[2]; + u32 state; +}; + +int ivshmem_init(struct cell *cell, struct pci_device *device); +void ivshmem_reset(struct pci_device *device); +void ivshmem_exit(struct pci_device *device); +int ivshmem_update_msix_vector(struct pci_device *device, unsigned int vector); +int ivshmem_update_msix(struct pci_device *device); +enum pci_access ivshmem_pci_cfg_write(struct pci_device *device, + unsigned int row, u32 mask, u32 value); +enum pci_access ivshmem_pci_cfg_read(struct pci_device *device, u16 address, + u32 *value); + +/** + * Trigger interrupt on ivshmem endpoint. + * @param ive Ivshmem endpoint the interrupt should be raised at. + * @param vector Interrupt vector to trigger. + */ +void arch_ivshmem_trigger_interrupt(struct ivshmem_endpoint *ive, + unsigned int vector); + +/** + * Update cached MSI-X state (if any) of the given ivshmem device and vector. + * @param ive Ivshmem endpoint to be updated. + * @param vector Interrupt vector to update. + * @param enabled True if MSI-X is enabled and unmasked. + * + * @return 0 on success, negative error code otherwise. + */ +int arch_ivshmem_update_msix(struct ivshmem_endpoint *ive, unsigned int vector, + bool enabled); + +/** + * Update cached INTx state (if any) of the given ivshmem device. + * @param ive Ivshmem endpoint to be updated. + * @param enabled True if INTx is enabled and unmasked. + */ +void arch_ivshmem_update_intx(struct ivshmem_endpoint *ive, bool enabled); + +/** @} IVSHMEM */ +#endif /* !_JAILHOUSE_IVSHMEM_H */ diff --git a/hypervisor/include/jailhouse/mmio.h b/hypervisor/include/jailhouse/mmio.h new file mode 100644 index 0000000000000000000000000000000000000000..aa85a089b0dc014a91ca921ba401f50cee3c3cfd --- /dev/null +++ b/hypervisor/include/jailhouse/mmio.h @@ -0,0 +1,196 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_MMIO_H +#define _JAILHOUSE_MMIO_H + +#include +#include +#include + +struct cell; + +/** + * @defgroup IO I/O Access Subsystem + * + * This subsystem provides accessors to I/O and supports the interpretation and + * handling of intercepted I/O accesses performed by cells. + * + * @{ + */ + +/** + * Define MMIO read accessor. + * @param size Access size. + */ +#define DEFINE_MMIO_READ(size) \ +static inline u##size mmio_read##size(void *address) \ +{ \ + return *(volatile u##size *)address; \ +} + +/** + * Read 8, 16, 32 or 64-bit value from a memory-mapped I/O register. + * @param address Virtual address of the register. + * + * @return Read value. + * @{ + */ +DEFINE_MMIO_READ(8) +DEFINE_MMIO_READ(16) +DEFINE_MMIO_READ(32) +DEFINE_MMIO_READ(64) +/** @} */ + +/** + * Define MMIO write accessor. + * @param size Access size. + */ +#define DEFINE_MMIO_WRITE(size) \ +static inline void mmio_write##size(void *address, u##size value) \ +{ \ + *(volatile u##size *)address = value; \ +} + +/** + * Write 8, 16, 32 or 64-bit value to a memory-mapped I/O register. + * @param address Virtual address of the register. + * @param value Value to write. + * @{ + */ +DEFINE_MMIO_WRITE(8) +DEFINE_MMIO_WRITE(16) +DEFINE_MMIO_WRITE(32) +DEFINE_MMIO_WRITE(64) +/** @} */ + +/** + * Write a 64-bit value to a memory-mapper I/O register. Perform two 32-bit + * write operations instead of one 64-bit write operation. + * + * @param address Virtual address of the register. + * @param value Value to write. + * @{ + */ +static inline void mmio_write64_split(void *address, u64 value) +{ + mmio_write32(address + 4, (u32)(value >> 32)); + mmio_write32(address, (u32)value); +} +/** @} */ + +/** + * Read value from 32 or 64-bit MMIO register field. + * @param address Virtual address of the register. + * @param mask Bitmask to defining the field. Only successive bits + * must be set. + * + * @return Field value of register, shifted so that the first non-zero bit in + * @c mask becomes bit 0. + * @{ + */ +static inline u32 mmio_read32_field(void *address, u32 mask) +{ + return (mmio_read32(address) & mask) >> (__builtin_ffs(mask) - 1); +} + +static inline u64 mmio_read64_field(void *address, u64 mask) +{ + return (mmio_read64(address) & mask) >> (__builtin_ffsl(mask) - 1); +} +/** @} */ + +/** + * Write value to 32 or 64-bit MMIO register field. + * @param address Virtual address of the register. + * @param mask Bitmask to defining the field. Only successive bits + * must be set. + * @param value Register field value. + * + * This updates only the field value of the register, leaving all other + * register bits unmodified. Thus, it performs a read-modify-write cycle. + * @{ + */ +static inline void mmio_write32_field(void *address, u32 mask, u32 value) +{ + mmio_write32(address, (mmio_read32(address) & ~mask) | + ((value << (__builtin_ffs(mask) - 1)) & mask)); +} + +static inline void mmio_write64_field(void *address, u64 mask, u64 value) +{ + mmio_write64(address, (mmio_read64(address) & ~mask) | + ((value << (__builtin_ffsl(mask) - 1)) & mask)); +} +/** @} */ + +/** MMIO access result. */ +enum mmio_result {MMIO_ERROR = -1, MMIO_UNHANDLED, MMIO_HANDLED}; + +/** MMIO access description. */ +struct mmio_access { + /** Address to access, depending on the context, an absolute address or + * relative offset to region start. */ + unsigned long address; + /** Size of the access. */ + unsigned int size; + /** True if write access. */ + bool is_write; + /** The value to be written or the read value to return. */ + unsigned long value; +}; + +/** MMIO handler. + * @param arg Opaque argument defined via mmio_region_register(). + * @param mmio MMIO access description. @a mmio->address will be + * provided as offset to the region start. + * + * @return MMIO_HANDLED on success, MMIO_ERROR otherwise. + */ +typedef enum mmio_result (*mmio_handler)(void *arg, struct mmio_access *mmio); + +/** MMIO region coordinates. */ +struct mmio_region_location { + /** Start address of the region. */ + unsigned long start; + /** Region size. */ + unsigned long size; +}; + +/** MMIO region access handler description. */ +struct mmio_region_handler { + /** Access handling function. */ + mmio_handler function; + /** Argument to pass to the function. */ + void *arg; +}; + +int mmio_cell_init(struct cell *cell); + +void mmio_region_register(struct cell *cell, unsigned long start, + unsigned long size, mmio_handler handler, + void *handler_arg); +void mmio_region_unregister(struct cell *cell, unsigned long start); + +enum mmio_result mmio_handle_access(struct mmio_access *mmio); + +void mmio_cell_exit(struct cell *cell); + +void mmio_perform_access(void *base, struct mmio_access *mmio); + +int mmio_subpage_register(struct cell *cell, + const struct jailhouse_memory *mem); +void mmio_subpage_unregister(struct cell *cell, + const struct jailhouse_memory *mem); + +/** @} */ +#endif /* !_JAILHOUSE_MMIO_H */ diff --git a/hypervisor/include/jailhouse/paging.h b/hypervisor/include/jailhouse/paging.h new file mode 100644 index 0000000000000000000000000000000000000000..d592abad63c4ed9c7626ddae001ccbedc930f21b --- /dev/null +++ b/hypervisor/include/jailhouse/paging.h @@ -0,0 +1,378 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_PAGING_H +#define _JAILHOUSE_PAGING_H + +/** + * @defgroup Paging Page Management Subsystem + * + * The page management subsystem provides services for allocating physical + * pages for the hypervisor and reserving remapping pages in the remapping + * area. It further offers functions to map pages for the hypervisor or cells, + * walk existing mappings or destroy them again. + * + * @{ + */ + +/** Size of smallest page. */ +#define PAGE_SIZE (1 << PAGE_SHIFT) +/** Mask of bits selecting a page. */ +#define PAGE_MASK ~(PAGE_SIZE - 1) +/** Mask of bits selecting an offset in a page. */ +#define PAGE_OFFS_MASK (PAGE_SIZE - 1) + +/** Align address to page boundary (round up). */ +#define PAGE_ALIGN(s) (((s) + PAGE_SIZE-1) & PAGE_MASK) +/** Count number of pages for given size (round up). */ +#define PAGES(s) (((s) + PAGE_SIZE-1) / PAGE_SIZE) + +/** Location of per-CPU data structure in hypervisor address space. */ +#define LOCAL_CPU_BASE (TEMPORARY_MAPPING_BASE + \ + NUM_TEMPORARY_PAGES * PAGE_SIZE) +/** @} */ + +#include + +#ifndef __ASSEMBLY__ + +#include +#include + +/** + * @ingroup Paging + * @{ + */ + +/** Global page pool */ +extern u8 __page_pool[]; + +/** Page pool state. */ +struct page_pool { + /** Base address of the pool. */ + void *base_address; + /** Number of managed pages. */ + unsigned long pages; + /** Number of currently used pages. */ + unsigned long used_pages; + /** Base address for bitmap of used pages. */ + unsigned long *used_bitmap; + /** Set @c PAGE_SCRUB_ON_FREE to zero-out pages on release. */ + unsigned long flags; +}; + +/** + * @defgroup PAGING_FLAGS Paging creation/destruction flags + * @{ + */ + +/** Do not force changes into RAM, i.e. avoid costly cache flushes. */ +#define PAGING_NON_COHERENT 0 +/** Make changes visible to non-snooping readers, i.e. commit them to RAM. */ +#define PAGING_COHERENT 0x1 + +/** Do not use huge pages for creating a mapping. */ +#define PAGING_NO_HUGE 0 +/** When possible, use huge pages for creating a mapping. */ +#define PAGING_HUGE 0x2 +/** @} */ + +/** Page table reference. */ +typedef pt_entry_t page_table_t; + +/** + * Parameters and callbacks for creating and parsing paging structures of a + * specific level. + */ +struct paging { + /** Page size of terminal entries in this level or 0 if none are + * supported. */ + unsigned int page_size; + + /** + * Get entry in given table corresponding to virt address. + * @param page_table Reference to page table. + * @param virt Virtual address to look up. + * + * @return Page table entry. + */ + pt_entry_t (*get_entry)(page_table_t page_table, unsigned long virt); + + /** + * Returns true if entry is a valid and supports the provided access + * flags (terminal and non-terminal entries). + * @param pte Reference to page table entry. + * @param flags Access flags to validate, see @ref PAGE_ACCESS_FLAGS. + * + * @return True if entry is valid. + */ + bool (*entry_valid)(pt_entry_t pte, unsigned long flags); + + /** + * Set terminal entry to physical address and access flags. + * @param pte Reference to page table entry. + * @param phys Target physical address. + * @param flags Flags of permitted access, see @ref PAGE_ACCESS_FLAGS. + */ + void (*set_terminal)(pt_entry_t pte, unsigned long phys, + unsigned long flags); + /** + * Extract physical address from given entry. + * @param pte Reference to page table entry. + * @param virt Virtual address to look up. + * + * @return Physical address or @c INVALID_PHYS_ADDR if entry it not + * terminal. + */ + unsigned long (*get_phys)(pt_entry_t pte, unsigned long virt); + /** + * Extract access flags from given entry. + * @param pte Reference to page table entry. + * + * @return Access flags, see @ref PAGE_ACCESS_FLAGS. + * + * @note Only valid for terminal entries. + */ + unsigned long (*get_flags)(pt_entry_t pte); + + /** + * Set entry to physical address of next-level page table. + * @param pte Reference to page table entry. + * @param next_pt Reference to page table of next level. + */ + void (*set_next_pt)(pt_entry_t pte, unsigned long next_pt); + /** + * Get physical address of next-level page table from entry. + * @param pte Reference to page table entry. + * + * @return Physical address. + * + * @note Only valid for non-terminal entries. + */ + unsigned long (*get_next_pt)(pt_entry_t pte); + + /** + * Invalidate entry. + * @param pte Reference to page table entry. + */ + void (*clear_entry)(pt_entry_t pte); + + /** + * Returns true if given page table contains no valid entries. + * @param page_table Reference to page table. + * + * @return True if table is empty. + */ + bool (*page_table_empty)(page_table_t page_table); +}; + +/** Describes the root of hierarchical paging structures. */ +struct paging_structures { + /** True if used for hypervisor itself. */ + bool hv_paging; + /** Pointer to array of paging parameters and callbacks, first element + * describing the root level, NULL if paging is disabled. */ + const struct paging *root_paging; + /** Reference to root-level page table, ignored if root_paging is NULL. + */ + page_table_t root_table; +}; + +/** + * Describes the root of hierarchical paging structures managed by a guest + * (cell). + */ +struct guest_paging_structures { + /** Pointer to array of paging parameters and callbacks, first element + * describing the root level. */ + const struct paging *root_paging; + /** Guest-physical address of the root-level page table. */ + unsigned long root_table_gphys; +}; + +#include + +extern unsigned long page_offset; + +extern struct page_pool mem_pool; +extern struct page_pool remap_pool; + +extern struct paging_structures hv_paging_structs; +extern struct paging_structures parking_pt; + +unsigned long paging_get_phys_invalid(pt_entry_t pte, unsigned long virt); + +void *page_alloc(struct page_pool *pool, unsigned int num); +void *page_alloc_aligned(struct page_pool *pool, unsigned int num); +void page_free(struct page_pool *pool, void *first_page, unsigned int num); + +/** + * Translate virtual hypervisor address to physical address. + * @param hvirt Virtual address in hypervisor address space. + * + * @return Corresponding physical address. + * + * @see paging_phys2hvirt + * @see paging_virt2phys + * @see arch_paging_gphys2phys + */ +static inline unsigned long paging_hvirt2phys(const volatile void *hvirt) +{ + return (unsigned long)hvirt - page_offset; +} + +/** + * Translate physical address to virtual hypervisor address. + * @param phys Physical address to translate. + * + * @return Corresponding virtual address in hypervisor address space. + * + * @see paging_hvirt2phys + * @see paging_virt2phys + * @see arch_paging_gphys2phys + */ +static inline void *paging_phys2hvirt(unsigned long phys) +{ + return (void *)phys + page_offset; +} + +unsigned long paging_virt2phys(const struct paging_structures *pg_structs, + unsigned long virt, unsigned long flags); + +/** + * Translate guest-physical (cell) address into host-physical address. + * @param gphys Guest-physical address to translate. + * @param flags Access flags to validate during the translation. + * + * @return Corresponding physical address or @c INVALID_PHYS_ADDR if the + * guest-physical address could not be translated or the requested + * access is not supported by the mapping. + * + * @see paging_phys2hvirt + * @see paging_hvirt2phys + * @see paging_virt2phys + */ +unsigned long arch_paging_gphys2phys(unsigned long gphys, unsigned long flags); + +int paging_create(const struct paging_structures *pg_structs, + unsigned long phys, unsigned long size, unsigned long virt, + unsigned long access_flags, unsigned long paging_flags); +int paging_destroy(const struct paging_structures *pg_structs, + unsigned long virt, unsigned long size, + unsigned long paging_flags); + +void *paging_map_device(unsigned long phys, unsigned long size); +void paging_unmap_device(unsigned long phys, void *virt, unsigned long size); + +int paging_create_hvpt_link(const struct paging_structures *pg_dest_structs, + unsigned long virt); + +void *paging_get_guest_pages(const struct guest_paging_structures *pg_structs, + unsigned long gaddr, unsigned int num, + unsigned long flags); + +int paging_map_all_per_cpu(unsigned int cpu, bool enable); + +int paging_init(void); + +/** + * Perform architecture-specific initialization of the page management + * subsystem. + */ +void arch_paging_init(void); + +void paging_dump_stats(const char *when); + +/* --- To be provided by asm/paging.h --- */ + +/** + * @def PAGE_SIZE + * Size of the smallest page the architecture supports. + * + * @def PAGE_MASK + * Use for zeroing-out the page offset bits (of the smallest page). + * + * @def PAGE_OFFS_MASK + * Use for zeroing-out the page number bits (of the smallest page). + */ + +/** + * @def MAX_PAGE_TABLE_LEVELS + * Maximum number of page table levels of the architecture for the hypervisor + * address space. + */ + +/** + * @defgroup PAGE_ACCESS_FLAGS Page Access flags + * @{ + * + * @def PAGE_DEFAULT_FLAGS + * Page access flags for full access. + * + * @def PAGE_READONLY_FLAGS + * Page access flags for read-only access. + * + * @def PAGE_PRESENT_FLAGS + * Page access flags that indicate presence of the page (unspecified access). + * + * @def PAGE_NONPRESENT_FLAGS + * Page access flags for a non-present page. + * + * @} + */ + +/** + * @def INVALID_PHYS_ADDR + * Physical address value that represents an invalid address, thus is never + * used by the architecture. + */ + +/** + * @def REMAP_BASE + * Start address of remapping region in the hypervisor address space. + * + * @def NUM_REMAP_BITMAP_PAGES + * Number of pages for the used-pages bitmap which records allocations in the + * remapping region. + */ + +/** + * @def NUM_TEMPORARY_PAGES + * Number of pages used for each CPU in the temporary remapping region. + */ + +/** + * @typedef pt_entry_t + * Page table entry reference. + */ + +/** + * @fn void arch_paging_flush_page_tlbs(unsigned long page_addr) + * Flush TLBs related to the specified page. + * @param page_addr Virtual page address. + * + * @see arch_paging_flush_cpu_caches + */ + +/** + * @fn void arch_paging_flush_cpu_caches(void *addr, long size) + * Flush caches related to the specified region. + * @param addr Pointer to the region to flush. + * @param size Size of the region. + * + * @see arch_paging_flush_page_tlbs + */ + +#endif /* !__ASSEMBLY__ */ + +/** @} */ +#endif /* !_JAILHOUSE_PAGING_H */ diff --git a/hypervisor/include/jailhouse/pci.h b/hypervisor/include/jailhouse/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..ee530c037f56a39103fb81b49442d220ae8a36a0 --- /dev/null +++ b/hypervisor/include/jailhouse/pci.h @@ -0,0 +1,247 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Ivan Kolchin + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_PCI_H +#define _JAILHOUSE_PCI_H + +#include + +#define PCI_CFG_COMMAND 0x04 +# define PCI_CMD_MEM (1 << 1) +# define PCI_CMD_MASTER (1 << 2) +# define PCI_CMD_INTX_OFF (1 << 10) +#define PCI_CFG_STATUS 0x06 +# define PCI_STS_CAPS (1 << 4) +#define PCI_CFG_BAR 0x10 +#define PCI_CFG_BAR_END 0x27 +#define PCI_CFG_ROMBAR 0x30 +#define PCI_CFG_CAPS 0x34 +#define PCI_CFG_INT 0x3c + +#define PCI_CONFIG_HEADER_SIZE 0x40 + +#define PCI_NUM_BARS 6 + +#define PCI_DEV_CLASS_OTHER 0xff + +#define PCI_IVSHMEM_NUM_MMIO_REGIONS 2 + +struct cell; +struct ivshmem_endpoint; + +/** + * @defgroup PCI PCI Subsystem + * + * The PCI subsystem provides access to PCI resources for the hypervisor and + * manages the cell's access to device configuration spaces and MSI-X tables. + * The subsystem depends on IOMMU services to configure DMA and interrupt + * mappings. + * + * @{ + */ + +/** Extract PCI bus from BDF form. */ +#define PCI_BUS(bdf) ((bdf) >> 8) +/** Extract PCI device/function from BDF form. */ +#define PCI_DEVFN(bdf) ((bdf) & 0xff) +/** Extract PCI bus, device and function as parameter list from BDF form. */ +#define PCI_BDF_PARAMS(bdf) (bdf) >> 8, ((bdf) >> 3) & 0x1f, (bdf) & 7 + +/** MSI-X vectors supported per device without extra allocation. */ +#define PCI_EMBEDDED_MSIX_VECTS 16 + +/** + * Access moderation return codes. + * See pci_cfg_read_moderate() and pci_cfg_write_moderate(). + */ +enum pci_access { PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM, PCI_ACCESS_DONE }; + +/** MSI config space registers. See PCI specification. */ +union pci_msi_registers { + /** @privatesection */ + struct { + u16 padding; + u16 enable:1, + ignore1:3, + mme:3, + ignore2:9; + u32 address; + u16 data; + } __attribute__((packed)) msg32; + struct { + u32 padding; /* use msg32 */ + u64 address; + u16 data; + } __attribute__((packed)) msg64; + u32 raw[4]; + /** @publicsection */ +} __attribute__((packed)); + +/** MSI-X config space registers. See PCI specification. */ +union pci_msix_registers { + /** @privatesection */ + struct { + u16 padding; + u16 ignore:14, + fmask:1, + enable:1; + } __attribute__((packed)); + u32 raw; + /** @publicsection */ +} __attribute__((packed)); + +#define PCI_MSIX_CTRL_RW_MASK (BIT_MASK(15, 14) << 16) + +/** MSI-X table entry. See PCI specification. */ +union pci_msix_vector { + /** @privatesection */ + struct { + u64 address; + u32 data; + u32 masked:1; + u32 reserved:31; + } __attribute__((packed)); + u32 raw[4]; + /** @publicsection */ +} __attribute__((packed)); + +struct pci_ivshmem_endpoint; + +/** + * PCI device state. + */ +struct pci_device { + /** Reference to static device configuration. */ + const struct jailhouse_pci_device *info; + /** Owning cell. */ + struct cell *cell; + /** Shadow BAR */ + u32 bar[PCI_NUM_BARS]; + + /** Shadow state of MSI config space registers. */ + union pci_msi_registers msi_registers; + + /** Shadow state of MSI-X config space registers. */ + union pci_msix_registers msix_registers; + /** ivshmem specific data. */ + struct ivshmem_endpoint *ivshmem_endpoint; + /** Real MSI-X table. */ + union pci_msix_vector *msix_table; + /** Shadow state of MSI-X table. */ + union pci_msix_vector *msix_vectors; + /** Buffer for shadow table of up to PCI_EMBEDDED_MSIX_VECTS vectors. */ + union pci_msix_vector msix_vector_array[PCI_EMBEDDED_MSIX_VECTS]; +}; + +u32 pci_read_config(u16 bdf, u16 address, unsigned int size); +void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size); + +struct pci_device *pci_get_assigned_device(const struct cell *cell, u16 bdf); + +enum pci_access pci_cfg_read_moderate(struct pci_device *device, u16 address, + unsigned int size, u32 *value); +enum pci_access pci_cfg_write_moderate(struct pci_device *device, u16 address, + unsigned int size, u32 value); + +void pci_reset_device(struct pci_device *device); + +void pci_cell_reset(struct cell *cell); + +void pci_config_commit(struct cell *cell_added_removed); + +unsigned int pci_enabled_msi_vectors(struct pci_device *device); + +void pci_prepare_handover(void); + +/** + * Read from PCI config space via architecture-specific method. + * @param bdf 16-bit bus/device/function ID of target. + * @param address Config space access address. + * @param size Access size (1, 2 or 4 bytes). + * + * @return Read value. + * + * @see pci_read_config + * @see arch_pci_write_config + */ +u32 arch_pci_read_config(u16 bdf, u16 address, unsigned int size); + +/** + * Write to PCI config space via architecture-specific method. + * @param bdf 16-bit bus/device/function ID of target. + * @param address Config space access address. + * @param value Value to be written. + * @param size Access size (1, 2 or 4 bytes). + * + * @see pci_write_config + * @see arch_pci_read_config + */ +void arch_pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size); + +/** + * Perform architecture-specific steps on physical PCI device addition. + * @param cell Cell to which the device is added. + * @param device Device to be added. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_pci_remove_physical_device + */ +int arch_pci_add_physical_device(struct cell *cell, struct pci_device *device); + +/** + * Perform architecture-specific steps on physical PCI device removal. + * @param device Device to be removed. + * + * @see arch_pci_add_physical_device + */ +void arch_pci_remove_physical_device(struct pci_device *device); + +/** + * Avoid MSI vector delivery of a given device or re-enable it. + * @param device Device to be silenced. + * @param cap MSI capability of the device. + * @param suppress True to disable delivery, false to allow it again. + * + * @note As events may be lost while a MSI vector is suppressed, re-enabling it + * may require injecting one event unconditionally. + */ +void arch_pci_set_suppress_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap, + bool suppress); + +/** + * Update MSI vector mapping for a given device. + * @param device Device to be updated. + * @param cap MSI capability of the device. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_pci_update_msix_vector + */ +int arch_pci_update_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap); + +/** + * Update MSI-X vector mapping for a given device and vector. + * @param device Device to be updated. + * @param index MSI-X vector number. + * + * @return 0 on success, negative error code otherwise. + * + * @see arch_pci_update_msi + */ +int arch_pci_update_msix_vector(struct pci_device *device, unsigned int index); + +/** @} PCI */ +#endif /* !_JAILHOUSE_PCI_H */ diff --git a/hypervisor/include/jailhouse/percpu.h b/hypervisor/include/jailhouse/percpu.h new file mode 100644 index 0000000000000000000000000000000000000000..4f0867daf3d6a05b160d83051a1d84087c03cdcf --- /dev/null +++ b/hypervisor/include/jailhouse/percpu.h @@ -0,0 +1,152 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_PERCPU_H +#define _JAILHOUSE_PERCPU_H + +/** + * @defgroup Per-CPU Per-CPU Subsystem + * + * The per-CPU subsystem provides a CPU-local state structure and accessors. + */ + +#include +#include +#include + +/** + * @ingroup Per-CPU + * @{ + */ + +/** Per-CPU states accessible across all CPUs. */ +struct public_per_cpu { + /** Per-CPU root page table. Public because it has to be accessible for + * page walks at any time. */ + u8 root_table_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); + + /** Logical CPU ID (same as Linux). */ + unsigned int cpu_id; + /** Owning cell. */ + struct cell *cell; + + /** Statistic counters. */ + u32 stats[JAILHOUSE_NUM_CPU_STATS]; + + /** State of the shutdown process. Possible values: + * @li SHUTDOWN_NONE: no shutdown in progress + * @li SHUTDOWN_STARTED: shutdown in progress + * @li negative error code: shutdown failed + */ + int shutdown_state; + /** True if CPU violated a cell boundary or cause some other failure in + * guest mode. */ + bool failed; + + /** Set to true for instructing the CPU to suspend. */ + volatile bool suspend_cpu; + /** True if CPU is suspended. */ + volatile bool cpu_suspended; + /** Set to true for a pending TLB flush for the paging layer that does + * host physical <-> guest physical memory mappings. */ + bool flush_vcpu_caches; + + ARCH_PUBLIC_PERCPU_FIELDS; +} __attribute__((aligned(PAGE_SIZE))); + +/** Per-CPU states. */ +struct per_cpu { + /* Must be first field! */ + union { + /** Stack used while in hypervisor mode. */ + u8 stack[STACK_SIZE]; + struct { + u8 __fill[STACK_SIZE - sizeof(union registers)]; + /** Guest registers saved on stack during VM exit. */ + union registers guest_regs; + }; + }; + + /** Per-CPU paging structures. */ + struct paging_structures pg_structs; + + ARCH_PERCPU_FIELDS; + + /* Must be last field! */ + struct public_per_cpu public; +} __attribute__((aligned(PAGE_SIZE))); + +/** + * Retrieve the data structure of the current CPU. + * + * @return Pointer to per-CPU data structure. + */ +static inline struct per_cpu *this_cpu_data(void) +{ + return (struct per_cpu *)LOCAL_CPU_BASE; +} + +/** + * Retrieve the publicly accessible data structure of the current CPU. + * + * @return Pointer to public per-CPU data structure. + */ +static inline struct public_per_cpu *this_cpu_public(void) +{ + return &this_cpu_data()->public; +} + +/** + * Retrieve the ID of the current CPU. + * + * @return CPU ID. + */ +static inline unsigned int this_cpu_id(void) +{ + return this_cpu_public()->cpu_id; +} + +/** + * Retrieve the cell owning the current CPU. + * + * @return Pointer to cell. + */ +static inline struct cell *this_cell(void) +{ + return this_cpu_public()->cell; +} + +/** + * Retrieve the data structure of the specified CPU. + * @param cpu ID of the target CPU. + * + * @return Pointer to per-CPU data structure. + */ +static inline struct per_cpu *per_cpu(unsigned int cpu) +{ + return (struct per_cpu *)(__page_pool + cpu * sizeof(struct per_cpu)); +} + +/** + * Retrieve the publicly accessible data structure of the specified CPU. + * @param cpu ID of the target CPU. + * + * @return Pointer to public per-CPU data structure. + */ +static inline struct public_per_cpu *public_per_cpu(unsigned int cpu) +{ + return &per_cpu(cpu)->public; +} + +/** @} **/ + +#endif /* !_JAILHOUSE_PERCPU_H */ diff --git a/hypervisor/include/jailhouse/printk.h b/hypervisor/include/jailhouse/printk.h new file mode 100644 index 0000000000000000000000000000000000000000..be1e861f0aa2761d9267ff9072dfc517ee03e95c --- /dev/null +++ b/hypervisor/include/jailhouse/printk.h @@ -0,0 +1,32 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +void __attribute__((format(printf, 1, 2))) printk(const char *fmt, ...); + +void __attribute__((format(printf, 1, 2))) panic_printk(const char *fmt, ...); + +#ifdef CONFIG_TRACE_ERROR +#define trace_error(code) ({ \ + printk("%s:%d: returning error %s\n", __FILE__, __LINE__, #code); \ + code; \ +}) +#else /* !CONFIG_TRACE_ERROR */ +#define trace_error(code) code +#endif /* !CONFIG_TRACE_ERROR */ + +void arch_dbg_write_init(void); +extern void (*arch_dbg_write)(const char *msg); + +extern bool virtual_console; +extern volatile struct jailhouse_virt_console console; diff --git a/hypervisor/include/jailhouse/processor.h b/hypervisor/include/jailhouse/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..639b2e5e003c792ca54602858b6dce6fddca6d71 --- /dev/null +++ b/hypervisor/include/jailhouse/processor.h @@ -0,0 +1,19 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#ifndef _JAILHOUSE_PROCESSOR_H +#define _JAILHOUSE_PROCESSOR_H + +#include + +unsigned long phys_processor_id(void); + +#endif diff --git a/hypervisor/include/jailhouse/stdarg.h b/hypervisor/include/jailhouse/stdarg.h new file mode 100644 index 0000000000000000000000000000000000000000..7c8633d4527f4b0f02262b5ded4a391ed8e7e364 --- /dev/null +++ b/hypervisor/include/jailhouse/stdarg.h @@ -0,0 +1,17 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2022 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +typedef __builtin_va_list va_list; + +#define va_start(ap, last) __builtin_va_start(ap, last) +#define va_arg(ap, type) __builtin_va_arg(ap, type) +#define va_end(ap) __builtin_va_end(ap) diff --git a/hypervisor/include/jailhouse/string.h b/hypervisor/include/jailhouse/string.h new file mode 100644 index 0000000000000000000000000000000000000000..7dc3de3b73b3abc1a53762821d4995fa043a3d14 --- /dev/null +++ b/hypervisor/include/jailhouse/string.h @@ -0,0 +1,30 @@ +#ifndef _JAILHOUSE_STRING_H +#define _JAILHOUSE_STRING_H + +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include + +void *memcpy(void *d, const void *s, size_t n); +void *memset(void *s, int c, size_t n); + +int strcmp(const char *s1, const char *s2); + +/* + * Indirect stringification. Doing two levels allows the parameter to be a + * macro itself. + */ + +#define __stringify_1(x...) #x +#define __stringify(x...) __stringify_1(x) + +#endif diff --git a/hypervisor/include/jailhouse/types.h b/hypervisor/include/jailhouse/types.h new file mode 100644 index 0000000000000000000000000000000000000000..6d78ad6d891fee527515abcb2a1badcd2bc1484c --- /dev/null +++ b/hypervisor/include/jailhouse/types.h @@ -0,0 +1,66 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef _JAILHOUSE_TYPES_H +#define _JAILHOUSE_TYPES_H + +#include + +#define NULL ((void *)0) + +#ifndef __ASSEMBLY__ + +typedef enum { true = 1, false = 0 } bool; + +/** Describes a CPU set. */ +struct cpu_set { + /** Maximum CPU ID expressible with this set. */ + unsigned long max_cpu_id; + /** Bitmap of CPUs in the set. + * @note Typically, the bitmap is extended by embedding this structure + * into a larger buffer. */ + unsigned long bitmap[1]; +}; + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +typedef s8 __s8; +typedef u8 __u8; + +typedef s16 __s16; +typedef u16 __u16; + +typedef s32 __s32; +typedef u32 __u32; + +typedef s64 __s64; +typedef u64 __u64; + +#if BITS_PER_LONG == 64 +typedef unsigned long size_t; +#else +typedef unsigned int size_t; +#endif + +#endif /* !__ASSEMBLY__ */ + +#endif /* !_JAILHOUSE_JAILHOUSE_TYPES_H */ diff --git a/hypervisor/include/jailhouse/uart.h b/hypervisor/include/jailhouse/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..7eb6800ff4a15beecefd2c88748dc1e0bc59c38f --- /dev/null +++ b/hypervisor/include/jailhouse/uart.h @@ -0,0 +1,33 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +struct uart_chip { + /* must be set by the caller */ + void *virt_base; + struct jailhouse_console *debug_console; + + /* driver selects defaults, if used */ + void (*reg_out)(struct uart_chip *chip, unsigned int reg, u32 value); + u32 (*reg_in)(struct uart_chip *chip, unsigned int reg); + + /* set by the driver */ + void (*init)(struct uart_chip *chip); + bool (*is_busy)(struct uart_chip *chip); + void (*write_char)(struct uart_chip *chip, char c); +}; + +void uart_write(const char *msg); + +extern struct uart_chip *uart; +extern struct uart_chip uart_8250_ops; diff --git a/hypervisor/include/jailhouse/unit.h b/hypervisor/include/jailhouse/unit.h new file mode 100644 index 0000000000000000000000000000000000000000..40e1cbfe25f504b856f50604106a779027149e58 --- /dev/null +++ b/hypervisor/include/jailhouse/unit.h @@ -0,0 +1,54 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +struct unit { + const char *name; + + int (*init)(void); + void (*shutdown)(void); + + unsigned int (*mmio_count_regions)(struct cell *); + int (*cell_init)(struct cell *); + void (*cell_exit)(struct cell *); +}; + +#define DEFINE_UNIT(__name, __description) \ + static const struct unit unit_##__name \ + __attribute__((section(".units"), aligned(8), used)) = { \ + .name = __description, \ + .init = __name##_init, \ + .shutdown = __name##_shutdown, \ + .mmio_count_regions = __name##_mmio_count_regions, \ + .cell_init = __name##_cell_init, \ + .cell_exit = __name##_cell_exit, \ + } + +#define DEFINE_UNIT_SHUTDOWN_STUB(__name) \ + static void __name##_shutdown(void) { } + +#define DEFINE_UNIT_MMIO_COUNT_REGIONS_STUB(__name) \ + static unsigned int __name##_mmio_count_regions(struct cell *cell) \ + { return 0; } + +extern struct unit __unit_array_start[0], __unit_array_end[0]; + +#define for_each_unit(unit) \ + for ((unit) = __unit_array_start; (unit) < __unit_array_end; (unit)++) + +#define for_each_unit_before_reverse(unit, before_unit) \ + for ((unit) = before_unit - 1; (unit) >= __unit_array_start; \ + (unit)--) + +#define for_each_unit_reverse(unit) \ + for_each_unit_before_reverse(unit, __unit_array_end) diff --git a/hypervisor/include/jailhouse/utils.h b/hypervisor/include/jailhouse/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..5c9730eb345e9e366c5a0348e1b0dc4d893fc9d4 --- /dev/null +++ b/hypervisor/include/jailhouse/utils.h @@ -0,0 +1,45 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Partly derived from Linux kernel code. + */ + +/* + * We need guards around ARRAY_SIZE as there is a duplicate definition in + * jailhouse/cell-config.h due to header license incompatibility. Once + * ARRAY_SIZE is replaced in cell-config.h, this guard can be removed. + */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#endif + +#define BUG() *(int *)0 = 0xdead + +/* sizeof() for a structure/union field */ +#define FIELD_SIZEOF(type, fld) (sizeof(((type *)0)->fld)) + +/* create 64-bit mask with bytes 0 to size-1 set to 0xff */ +#define BYTE_MASK(size) (0xffffffffffffffffULL >> ((8 - (size)) * 8)) + +/* create 64-bit mask with all bits in [last:first] set */ +#define BIT_MASK(last, first) \ + ((0xffffffffffffffffULL >> (64 - ((last) + 1 - (first)))) << (first)) + +/* extract the field value at [last:first] from an input of up to 64 bits */ +#define GET_FIELD(value, last, first) \ + (((value) & BIT_MASK((last), (first))) >> (first)) + +/* set the field value at [last:first] from an input of up to 64 bits*/ +#define SET_FIELD(value, last, first) \ + ((value) << (first) & BIT_MASK((last), (first))) + +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) diff --git a/hypervisor/ivshmem.c b/hypervisor/ivshmem.c new file mode 100644 index 0000000000000000000000000000000000000000..a5cdcf9370780ee45db063447bcba1f59964922b --- /dev/null +++ b/hypervisor/ivshmem.c @@ -0,0 +1,550 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2019 + * + * Authors: + * Henning Schild + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/** @addtogroup IVSHMEM + * Inter Cell communication using a virtual PCI device. The device provides + * shared memory and interrupts based on MSI-X. + * + * The implementation in Jailhouse provides a shared memory device between + * 2 or more cells. The link between the PCI devices is established by + * choosing the same BDF. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_VENDOR_ID_SIEMENS 0x110a +#define IVSHMEM_DEVICE_ID 0x4106 + +#define IVSHMEM_MAX_PEERS 12 + +#define IVSHMEM_CFG_VNDR_CAP 0x40 +#define IVSHMEM_CFG_MSIX_CAP (IVSHMEM_CFG_VNDR_CAP + \ + IVSHMEM_CFG_VNDR_LEN) + +#define IVSHMEM_CFG_SHMEM_STATE_TAB_SZ (IVSHMEM_CFG_VNDR_CAP + 0x04) +#define IVSHMEM_CFG_SHMEM_RW_SZ (IVSHMEM_CFG_VNDR_CAP + 0x08) +#define IVSHMEM_CFG_SHMEM_OUTPUT_SZ (IVSHMEM_CFG_VNDR_CAP + 0x10) +#define IVSHMEM_CFG_SHMEM_ADDR (IVSHMEM_CFG_VNDR_CAP + 0x18) +#define IVSHMEM_CFG_VNDR_LEN 0x20 + +#define IVSHMEM_CFG_ONESHOT_INT (1 << 24) + +/* + * Make the region two times as large as the MSI-X table to guarantee a + * power-of-2 size (encoding constraint of a BAR). + */ +#define IVSHMEM_MSIX_SIZE (0x10 * IVSHMEM_MSIX_VECTORS * 2) + +#define IVSHMEM_REG_ID 0x00 +#define IVSHMEM_REG_MAX_PEERS 0x04 +#define IVSHMEM_REG_INT_CTRL 0x08 +#define IVSHMEM_REG_DOORBELL 0x0c +#define IVSHMEM_REG_STATE 0x10 + +struct ivshmem_link { + struct ivshmem_endpoint eps[IVSHMEM_MAX_PEERS]; + unsigned int peers; + u16 bdf; + struct ivshmem_link *next; +}; + +static struct ivshmem_link *ivshmem_links; + +static const u32 default_cspace[IVSHMEM_CFG_SIZE / sizeof(u32)] = { + [0x00/4] = (IVSHMEM_DEVICE_ID << 16) | PCI_VENDOR_ID_SIEMENS, + [0x04/4] = (PCI_STS_CAPS << 16), + [0x08/4] = PCI_DEV_CLASS_OTHER << 24, + [0x2c/4] = (IVSHMEM_DEVICE_ID << 16) | PCI_VENDOR_ID_SIEMENS, + [PCI_CFG_CAPS/4] = IVSHMEM_CFG_VNDR_CAP, + [IVSHMEM_CFG_VNDR_CAP/4] = (IVSHMEM_CFG_VNDR_LEN << 16) | + (IVSHMEM_CFG_MSIX_CAP << 8) | PCI_CAP_ID_VNDR, + [IVSHMEM_CFG_MSIX_CAP/4] = (0x00 << 8) | PCI_CAP_ID_MSIX, + [(IVSHMEM_CFG_MSIX_CAP + 0x4)/4] = 1, + [(IVSHMEM_CFG_MSIX_CAP + 0x8)/4] = 0x10 * IVSHMEM_MSIX_VECTORS | 1, +}; + +static void ivshmem_trigger_interrupt(struct ivshmem_endpoint *ive, + unsigned int vector) +{ + /* + * Hold the IRQ lock while sending the interrupt so that ivshmem_exit + * and ivshmem_register_mmio can synchronize on the completion of the + * delivery. + */ + spin_lock(&ive->irq_lock); + + if (ive->int_ctrl_reg & IVSHMEM_INT_ENABLE) { + if (ive->cspace[IVSHMEM_CFG_VNDR_CAP/4] & + IVSHMEM_CFG_ONESHOT_INT) + ive->int_ctrl_reg = 0; + + arch_ivshmem_trigger_interrupt(ive, vector); + } + + spin_unlock(&ive->irq_lock); +} + +static u32 *ivshmem_map_state_table(struct ivshmem_endpoint *ive) +{ + /* + * Cannot fail: upper levels of page table were already created by + * paging_init, and we always map single pages, thus only update the + * leaf entry and do not have to deal with huge pages. + */ + paging_create(&this_cpu_data()->pg_structs, + ive->shmem[0].phys_start, PAGE_SIZE, + TEMPORARY_MAPPING_BASE, PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + + return (u32 *)TEMPORARY_MAPPING_BASE; +} + + +static void ivshmem_write_state(struct ivshmem_endpoint *ive, u32 new_state) +{ + const struct jailhouse_pci_device *dev_info = ive->device->info; + u32 *state_table = ivshmem_map_state_table(ive); + struct ivshmem_endpoint *target_ive; + unsigned int id; + + state_table[dev_info->shmem_dev_id] = new_state; + memory_barrier(); + + if (ive->state != new_state) { + ive->state = new_state; + + for (id = 0; id < dev_info->shmem_peers; id++) { + target_ive = &ive->link->eps[id]; + if (target_ive != ive) + ivshmem_trigger_interrupt(target_ive, 0); + } + } +} + +int ivshmem_update_msix_vector(struct pci_device *device, unsigned int vector) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + union pci_msix_registers cap; + bool enabled; + + cap.raw = ive->cspace[IVSHMEM_CFG_MSIX_CAP/4]; + enabled = cap.enable && !cap.fmask && + !device->msix_vectors[vector].masked && + ive->cspace[PCI_CFG_COMMAND/4] & PCI_CMD_MASTER; + + return arch_ivshmem_update_msix(ive, vector, enabled); +} + +int ivshmem_update_msix(struct pci_device *device) +{ + unsigned int vector, num_vectors = device->info->num_msix_vectors; + int err = 0; + + for (vector = 0; vector < num_vectors && !err; vector++) + err = ivshmem_update_msix_vector(device, vector); + + return err; +} + +static void ivshmem_update_intx(struct ivshmem_endpoint *ive) +{ + bool masked = ive->cspace[PCI_CFG_COMMAND/4] & PCI_CMD_INTX_OFF; + + if (ive->device->info->num_msix_vectors == 0) + arch_ivshmem_update_intx(ive, !masked); +} + +static enum mmio_result ivshmem_register_mmio(void *arg, + struct mmio_access *mmio) +{ + struct ivshmem_endpoint *target_ive, *ive = arg; + unsigned int num_vectors, vector, target; + + switch (mmio->address) { + case IVSHMEM_REG_ID: + /* read-only ID */ + mmio->value = ive->device->info->shmem_dev_id; + break; + case IVSHMEM_REG_MAX_PEERS: + /* read-only number of peers */ + mmio->value = ive->device->info->shmem_peers; + break; + case IVSHMEM_REG_INT_CTRL: + if (mmio->is_write) { + /* + * The spinlock acts as barrier, ensuring that + * interrupts are disabled on return. + */ + spin_lock(&ive->irq_lock); + ive->int_ctrl_reg = mmio->value & IVSHMEM_INT_ENABLE; + spin_unlock(&ive->irq_lock); + + ivshmem_update_intx(ive); + if (ivshmem_update_msix(ive->device)) + return MMIO_ERROR; + } else { + mmio->value = ive->int_ctrl_reg; + } + break; + case IVSHMEM_REG_DOORBELL: + if (mmio->is_write) { + /* + * All peers have the same number of MSI-X vectors, + * thus we can derive the limit from the local device. + */ + num_vectors = ive->device->info->num_msix_vectors; + if (num_vectors == 0) + num_vectors = 1; /* INTx means one vector */ + + vector = GET_FIELD(mmio->value, 15, 0); + /* ignore out-of-range requests */ + if (vector >= num_vectors) + break; + + target = GET_FIELD(mmio->value, 31, 16); + if (target >= IVSHMEM_MAX_PEERS) + break; + + target_ive = &ive->link->eps[target]; + + ivshmem_trigger_interrupt(target_ive, vector); + } else { + mmio->value = 0; + } + break; + case IVSHMEM_REG_STATE: + if (mmio->is_write) + ivshmem_write_state(ive, mmio->value); + else + mmio->value = ive->state; + break; + default: + /* ignore any other access */ + mmio->value = 0; + break; + } + return MMIO_HANDLED; +} + +static enum mmio_result ivshmem_msix_mmio(void *arg, struct mmio_access *mmio) +{ + unsigned int vector = mmio->address / sizeof(union pci_msix_vector); + struct ivshmem_endpoint *ive = arg; + u32 *msix_table = (u32 *)ive->device->msix_vectors; + + if (mmio->address % 4) + goto fail; + + /* MSI-X PBA */ + if (mmio->address >= 0x10 * IVSHMEM_MSIX_VECTORS) { + if (mmio->is_write) { + goto fail; + } else { + mmio->value = 0; + return MMIO_HANDLED; + } + /* MSI-X Table */ + } else { + if (vector >= ive->device->info->num_msix_vectors) + goto fail; + if (mmio->is_write) { + msix_table[mmio->address / 4] = mmio->value; + if (ivshmem_update_msix_vector(ive->device, vector)) + return MMIO_ERROR; + } else { + mmio->value = msix_table[mmio->address / 4]; + } + return MMIO_HANDLED; + } + +fail: + panic_printk("FATAL: Invalid PCI MSI-X table/PBA access, device " + "%02x:%02x.%x\n", PCI_BDF_PARAMS(ive->device->info->bdf)); + return MMIO_ERROR; +} + +/** + * update the command register + * note that we only accept writes to two flags + */ +static int ivshmem_write_command(struct ivshmem_endpoint *ive, u16 val) +{ + u16 *cmd = (u16 *)&ive->cspace[PCI_CFG_COMMAND/4]; + struct pci_device *device = ive->device; + int err; + + if ((val & PCI_CMD_MASTER) != (*cmd & PCI_CMD_MASTER)) { + *cmd = (*cmd & ~PCI_CMD_MASTER) | (val & PCI_CMD_MASTER); + err = ivshmem_update_msix(device); + if (err) + return err; + } + + if ((val & PCI_CMD_MEM) != (*cmd & PCI_CMD_MEM)) { + if (*cmd & PCI_CMD_MEM) { + mmio_region_unregister(device->cell, ive->ioregion[0]); + mmio_region_unregister(device->cell, ive->ioregion[1]); + } + if (val & PCI_CMD_MEM) { + ive->ioregion[0] = device->bar[0] & ~0xf; + /* Derive the size of region 0 from its BAR mask. */ + mmio_region_register(device->cell, ive->ioregion[0], + ~device->info->bar_mask[0] + 1, + ivshmem_register_mmio, ive); + + ive->ioregion[1] = device->bar[1] & ~0xf; + mmio_region_register(device->cell, ive->ioregion[1], + IVSHMEM_MSIX_SIZE, + ivshmem_msix_mmio, ive); + } + *cmd = (*cmd & ~PCI_CMD_MEM) | (val & PCI_CMD_MEM); + } + + if ((val & PCI_CMD_INTX_OFF) != (*cmd & PCI_CMD_INTX_OFF)) { + *cmd = (*cmd & ~PCI_CMD_INTX_OFF) | (val & PCI_CMD_INTX_OFF); + ivshmem_update_intx(ive); + } + + return 0; +} + +/** + * Handler for MMIO-write-accesses to PCI config space of this virtual device. + * @param device The device that access should be performed on. + * @param row Config space DWORD row of the access. + * @param mask Mask selected the DWORD bytes to write. + * @param value DWORD to write to the config space. + * + * @return PCI_ACCESS_REJECT or PCI_ACCESS_DONE. + * + * @see pci_cfg_write_moderate + */ +enum pci_access ivshmem_pci_cfg_write(struct pci_device *device, + unsigned int row, u32 mask, u32 value) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + + if (row >= ARRAY_SIZE(default_cspace)) + return PCI_ACCESS_REJECT; + + value |= ive->cspace[row] & ~mask; + + switch (row) { + case PCI_CFG_COMMAND / 4: + if (ivshmem_write_command(ive, value)) + return PCI_ACCESS_REJECT; + break; + case IVSHMEM_CFG_MSIX_CAP / 4: + ive->cspace[IVSHMEM_CFG_MSIX_CAP/4] &= ~PCI_MSIX_CTRL_RW_MASK; + ive->cspace[IVSHMEM_CFG_MSIX_CAP/4] |= + value & PCI_MSIX_CTRL_RW_MASK; + if (ivshmem_update_msix(device)) + return PCI_ACCESS_REJECT; + break; + case IVSHMEM_CFG_VNDR_CAP / 4: + ive->cspace[IVSHMEM_CFG_VNDR_CAP/4] &= ~IVSHMEM_CFG_ONESHOT_INT; + ive->cspace[IVSHMEM_CFG_VNDR_CAP/4] |= + value & IVSHMEM_CFG_ONESHOT_INT; + break; + } + return PCI_ACCESS_DONE; +} + +/** + * Handler for MMIO-read-accesses to PCI config space of this virtual device. + * @param device The device that access should be performed on. + * @param address Config space address accessed. + * @param value Pointer to the return value. + * + * @return PCI_ACCESS_DONE. + * + * @see pci_cfg_read_moderate + */ +enum pci_access ivshmem_pci_cfg_read(struct pci_device *device, u16 address, + u32 *value) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + + if (address < sizeof(default_cspace)) + *value = ive->cspace[address / 4] >> ((address % 4) * 8); + else + *value = -1; + return PCI_ACCESS_DONE; +} + +/** + * Register a new ivshmem device. + * @param cell The cell the device should be attached to. + * @param device The device to be registered. + * + * @return 0 on success, negative error code otherwise. + */ +int ivshmem_init(struct cell *cell, struct pci_device *device) +{ + const struct jailhouse_pci_device *dev_info = device->info; + struct ivshmem_endpoint *ive; + struct ivshmem_link *link; + unsigned int peer_id, id; + struct pci_device *peer; + + printk("Adding virtual PCI device %02x:%02x.%x to cell \"%s\"\n", + PCI_BDF_PARAMS(dev_info->bdf), cell->config->name); + + if (dev_info->shmem_regions_start + 2 + dev_info->shmem_peers > + cell->config->num_memory_regions || + dev_info->num_msix_vectors > IVSHMEM_MSIX_VECTORS) + return trace_error(-EINVAL); + + for (link = ivshmem_links; link; link = link->next) + if (link->bdf == dev_info->bdf) + break; + + id = dev_info->shmem_dev_id; + if (id >= IVSHMEM_MAX_PEERS) + return trace_error(-EINVAL); + + if (link) { + if (link->eps[id].device) + return trace_error(-EBUSY); + + printk("Shared memory connection established, peer cells:\n"); + for (peer_id = 0; peer_id < IVSHMEM_MAX_PEERS; peer_id++) { + peer = link->eps[peer_id].device; + if (peer && peer_id != id) + printk(" \"%s\"\n", peer->cell->config->name); + } + } else { + link = page_alloc(&mem_pool, PAGES(sizeof(*link))); + if (!link) + return -ENOMEM; + + link->bdf = dev_info->bdf; + link->next = ivshmem_links; + ivshmem_links = link; + } + + link->peers++; + ive = &link->eps[id]; + + ive->device = device; + ive->link = link; + ive->shmem = jailhouse_cell_mem_regions(cell->config) + + dev_info->shmem_regions_start; + if (link->peers == 1) + memset(ivshmem_map_state_table(ive), 0, + dev_info->shmem_peers * sizeof(u32)); + device->ivshmem_endpoint = ive; + + device->cell = cell; + pci_reset_device(device); + + return 0; +} + +void ivshmem_reset(struct pci_device *device) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + unsigned int n; + + /* + * Hold the spinlock while invalidating in order to synchronize with + * any in-flight interrupt from remote sides. + */ + spin_lock(&ive->irq_lock); + ive->int_ctrl_reg = 0; + memset(&ive->irq_cache, 0, sizeof(ive->irq_cache)); + spin_unlock(&ive->irq_lock); + + if (ive->cspace[PCI_CFG_COMMAND/4] & PCI_CMD_MEM) { + mmio_region_unregister(device->cell, ive->ioregion[0]); + mmio_region_unregister(device->cell, ive->ioregion[1]); + } + + memset(device->bar, 0, sizeof(device->bar)); + device->msix_registers.raw = 0; + + memcpy(ive->cspace, &default_cspace, sizeof(default_cspace)); + + ive->cspace[0x08/4] |= device->info->shmem_protocol << 8; + + if (device->info->num_msix_vectors == 0) { + /* let the PIN rotate based on the device number */ + ive->cspace[PCI_CFG_INT/4] = + (((device->info->bdf >> 3) & 0x3) + 1) << 8; + /* disable MSI-X capability */ + ive->cspace[IVSHMEM_CFG_VNDR_CAP/4] &= 0xffff00ff; + } else { + ive->cspace[IVSHMEM_CFG_MSIX_CAP/4] |= + (device->info->num_msix_vectors - 1) << 16; + for (n = 0; n < device->info->num_msix_vectors; n++) + device->msix_vectors[n].masked = 1; + } + + ive->cspace[IVSHMEM_CFG_SHMEM_STATE_TAB_SZ/4] = (u32)ive->shmem[0].size; + + ive->cspace[IVSHMEM_CFG_SHMEM_RW_SZ/4] = (u32)ive->shmem[1].size; + ive->cspace[IVSHMEM_CFG_SHMEM_RW_SZ/4 + 1] = + (u32)(ive->shmem[1].size >> 32); + + ive->cspace[IVSHMEM_CFG_SHMEM_OUTPUT_SZ/4] = (u32)ive->shmem[2].size; + ive->cspace[IVSHMEM_CFG_SHMEM_OUTPUT_SZ/4 + 1] = + (u32)(ive->shmem[2].size >> 32); + + ive->cspace[IVSHMEM_CFG_SHMEM_ADDR/4] = (u32)ive->shmem[0].virt_start; + ive->cspace[IVSHMEM_CFG_SHMEM_ADDR/4 + 1] = + (u32)(ive->shmem[0].virt_start >> 32); + + ivshmem_write_state(ive, 0); +} + +/** + * Unregister a ivshmem device, typically when the corresponding cell exits. + * @param device The device to be stopped. + * + */ +void ivshmem_exit(struct pci_device *device) +{ + struct ivshmem_endpoint *ive = device->ivshmem_endpoint; + struct ivshmem_link **linkp; + + /* + * Hold the spinlock while invalidating in order to synchronize with + * any in-flight interrupt from remote sides. + */ + spin_lock(&ive->irq_lock); + memset(&ive->irq_cache, 0, sizeof(ive->irq_cache)); + spin_unlock(&ive->irq_lock); + + ivshmem_write_state(ive, 0); + + ive->device = NULL; + + if (--ive->link->peers > 0) + return; + + for (linkp = &ivshmem_links; *linkp; linkp = &(*linkp)->next) { + if (*linkp != ive->link) + continue; + + *linkp = ive->link->next; + page_free(&mem_pool, ive->link, PAGES(sizeof(*ive->link))); + break; + } +} diff --git a/hypervisor/lib.c b/hypervisor/lib.c new file mode 100644 index 0000000000000000000000000000000000000000..3fcd41b0beeed38affc7ab0053b8f8b346184585 --- /dev/null +++ b/hypervisor/lib.c @@ -0,0 +1,43 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +void *memset(void *s, int c, size_t n) +{ + u8 *p = s; + + while (n-- > 0) + *p++ = c; + return s; +} + +int strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2) { + if (*s1 == '\0') + return 0; + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +void *memcpy(void *dest, const void *src, size_t n) +{ + const u8 *s = src; + u8 *d = dest; + + while (n-- > 0) + *d++ = *s++; + return dest; +} diff --git a/hypervisor/mmio.c b/hypervisor/mmio.c new file mode 100644 index 0000000000000000000000000000000000000000..3747bf6fcf9967cb57abcd0f3d91ac3a31f47bdd --- /dev/null +++ b/hypervisor/mmio.c @@ -0,0 +1,369 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * Perform MMIO-specific initialization for a new cell. + * @param cell Cell to be initialized. + * + * @return 0 on success, negative error code otherwise. + * + * @see mmio_cell_exit + */ +int mmio_cell_init(struct cell *cell) +{ + const struct jailhouse_memory *mem; + const struct unit *unit; + unsigned int n; + void *pages; + + /* cell is zero-initialized */; + for_each_unit(unit) + cell->max_mmio_regions += unit->mmio_count_regions(cell); + + for_each_mem_region(mem, cell->config, n) + if (JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) + cell->max_mmio_regions++; + + pages = page_alloc(&mem_pool, + PAGES(cell->max_mmio_regions * + (sizeof(struct mmio_region_location) + + sizeof(struct mmio_region_handler)))); + if (!pages) + return -ENOMEM; + + cell->mmio_locations = pages; + cell->mmio_handlers = pages + + cell->max_mmio_regions * sizeof(struct mmio_region_location); + + return 0; +} + +static void copy_region(struct cell *cell, unsigned int src, unsigned dst) +{ + cell->mmio_locations[dst] = cell->mmio_locations[src]; + cell->mmio_handlers[dst] = cell->mmio_handlers[src]; +} + +/** + * Register a MMIO region access handler for a cell. + * @param cell Cell than can access the region. + * @param start Region start address in cell address space. + * @param size Region size. + * @param handler Access handler. + * @param handler_arg Opaque argument to pass to handler. + * + * @see mmio_region_unregister + */ +void mmio_region_register(struct cell *cell, unsigned long start, + unsigned long size, mmio_handler handler, + void *handler_arg) +{ + unsigned int index, n; + + spin_lock(&cell->mmio_region_lock); + + if (cell->num_mmio_regions >= cell->max_mmio_regions) { + spin_unlock(&cell->mmio_region_lock); + + printk("WARNING: Overflow during MMIO region registration!\n"); + return; + } + + for (index = 0; index < cell->num_mmio_regions; index++) + if (cell->mmio_locations[index].start > start) + break; + + /* + * Advance the generation to odd value, indicating that modifications + * are ongoing. Commit this change via a barrier so that other CPUs + * will see this before we start changing any field. + */ + cell->mmio_generation++; + memory_barrier(); + + for (n = cell->num_mmio_regions; n > index; n--) + copy_region(cell, n - 1, n); + + cell->mmio_locations[index].start = start; + cell->mmio_locations[index].size = size; + cell->mmio_handlers[index].function = handler; + cell->mmio_handlers[index].arg = handler_arg; + + cell->num_mmio_regions++; + + /* Ensure all fields are committed before advancing the generation. */ + memory_barrier(); + cell->mmio_generation++; + + spin_unlock(&cell->mmio_region_lock); +} + +static int find_region(struct cell *cell, unsigned long address, + unsigned int size, unsigned long *region_base, + struct mmio_region_handler *handler) +{ + unsigned int range_start, range_size, index; + struct mmio_region_location region; + unsigned long generation; + +restart: + generation = cell->mmio_generation; + + /* + * Ensure that the generation value was read prior to reading any other + * field. + */ + memory_load_barrier(); + + /* Odd number? Then we have an ongoing modification and must restart. */ + if (generation & 1) { + cpu_relax(); + goto restart; + } + + range_start = 0; + range_size = cell->num_mmio_regions; + + while (range_size > 0) { + index = range_start + range_size / 2; + region = cell->mmio_locations[index]; + + /* + * Ensure the region location was read prior to checking the + * generation again. + */ + memory_load_barrier(); + + /* + * If the generation changed meanwhile, the fields we read + * could have been inconsistent. + */ + if (cell->mmio_generation != generation) + goto restart; + + if (address < region.start) { + range_size = index - range_start; + } else if (region.start + region.size < address + size) { + range_size -= index + 1 - range_start; + range_start = index + 1; + } else { + if (region_base != NULL) { + *region_base = region.start; + *handler = cell->mmio_handlers[index]; + } + + /* + * Ensure everything was read prior to checking the + * generation for the last time. + */ + memory_load_barrier(); + + /* final check of consistency */ + if (cell->mmio_generation != generation) + goto restart; + + return index; + } + } + return -1; +} + +/** + * Unregister MMIO region from a cell. + * @param cell Cell the region belongs to. + * @param start Region start address as it was passed to + * mmio_region_register(). + * + * @see mmio_region_register + */ +void mmio_region_unregister(struct cell *cell, unsigned long start) +{ + int index; + + spin_lock(&cell->mmio_region_lock); + + index = find_region(cell, start, 1, NULL, NULL); + if (index >= 0) { + /* + * Advance the generation to odd value, indicating that + * modifications are ongoing. Commit this change via a barrier + * so that other CPUs will see it before we start. + */ + cell->mmio_generation++; + memory_barrier(); + + for (/* empty */; (u32)index < cell->num_mmio_regions; index++) + copy_region(cell, index + 1, index); + + cell->num_mmio_regions--; + + /* + * Ensure all regions and their number are committed before + * advancing the generation. + */ + memory_barrier(); + cell->mmio_generation++; + } + spin_unlock(&cell->mmio_region_lock); +} + +/** + * Dispatch MMIO access of a cell CPU. + * @param mmio MMIO access description. @a mmio->value will receive the + * result of a successful read access. All @a mmio fields + * may have been modified on return. + * + * @return MMIO_HANDLED on success, MMIO_UNHANDLED if no region is registered + * for the access address and size, or MMIO_ERROR if an access error was + * detected. + * + * @see mmio_region_register + * @see mmio_region_unregister + */ +enum mmio_result mmio_handle_access(struct mmio_access *mmio) +{ + struct mmio_region_handler handler; + unsigned long region_base; + + if (find_region(this_cell(), mmio->address, mmio->size, ®ion_base, + &handler) < 0) + return MMIO_UNHANDLED; + + mmio->address -= region_base; + return handler.function(handler.arg, mmio); +} + +/** + * Perform MMIO-specific cleanup for a cell under destruction. + * @param cell Cell to be destructed. + * + * @see mmio_cell_init + */ +void mmio_cell_exit(struct cell *cell) +{ + page_free(&mem_pool, cell->mmio_locations, + PAGES(cell->max_mmio_regions * + (sizeof(struct mmio_region_location) + + sizeof(struct mmio_region_handler)))); +} + +void mmio_perform_access(void *base, struct mmio_access *mmio) +{ + void *addr = base + mmio->address; + + if (mmio->is_write) + switch (mmio->size) { + case 1: + mmio_write8(addr, mmio->value); + break; + case 2: + mmio_write16(addr, mmio->value); + break; + case 4: + mmio_write32(addr, mmio->value); + break; +#if BITS_PER_LONG == 64 + case 8: + mmio_write64(addr, mmio->value); + break; +#endif + } + else + switch (mmio->size) { + case 1: + mmio->value = mmio_read8(addr); + break; + case 2: + mmio->value = mmio_read16(addr); + break; + case 4: + mmio->value = mmio_read32(addr); + break; +#if BITS_PER_LONG == 64 + case 8: + mmio->value = mmio_read64(addr); + break; +#endif + } +} + +static enum mmio_result mmio_handle_subpage(void *arg, struct mmio_access *mmio) +{ + const struct jailhouse_memory *mem = arg; + u64 perm = mmio->is_write ? JAILHOUSE_MEM_WRITE : JAILHOUSE_MEM_READ; + unsigned long page_phys = + ((unsigned long)mem->phys_start + mmio->address) & PAGE_MASK; + unsigned long virt_base; + int err; + + /* check read/write access permissions */ + if (!(mem->flags & perm)) + goto invalid_access; + + /* width bit according to access size needs to be set */ + if (!((mmio->size << JAILHOUSE_MEM_IO_WIDTH_SHIFT) & mem->flags)) + goto invalid_access; + + /* naturally unaligned access needs to be allowed explicitly */ + if (mmio->address & (mmio->size - 1) && + !(mem->flags & JAILHOUSE_MEM_IO_UNALIGNED)) + goto invalid_access; + + err = paging_create(&this_cpu_data()->pg_structs, page_phys, PAGE_SIZE, + TEMPORARY_MAPPING_BASE, + PAGE_DEFAULT_FLAGS | PAGE_FLAG_DEVICE, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + if (err) + goto invalid_access; + + /* + * This virt_base gives the following effective virtual address in + * mmio_perform_access: + * + * TEMPORARY_MAPPING_BASE + (mem->phys_start & PAGE_OFFS_MASK) + + * (mmio->address & PAGE_OFFS_MASK) + * + * Reason: mmio_perform_access does addr = base + mmio->address. + */ + virt_base = TEMPORARY_MAPPING_BASE + (mem->phys_start & PAGE_OFFS_MASK) + - (mmio->address & PAGE_MASK); + mmio_perform_access((void *)virt_base, mmio); + return MMIO_HANDLED; + +invalid_access: + panic_printk("FATAL: Invalid MMIO %s, address: %lx, size: %x\n", + mmio->is_write ? "write" : "read", + (unsigned long)mem->phys_start + mmio->address, + mmio->size); + return MMIO_ERROR; +} + +int mmio_subpage_register(struct cell *cell, const struct jailhouse_memory *mem) +{ + mmio_region_register(cell, mem->virt_start, mem->size, + mmio_handle_subpage, (void *)mem); + return 0; +} + +void mmio_subpage_unregister(struct cell *cell, + const struct jailhouse_memory *mem) +{ + mmio_region_unregister(cell, mem->virt_start); +} diff --git a/hypervisor/paging.c b/hypervisor/paging.c new file mode 100644 index 0000000000000000000000000000000000000000..532682baac236b3ee425a222006f10b19f04408a --- /dev/null +++ b/hypervisor/paging.c @@ -0,0 +1,728 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +#define BITS_PER_PAGE (PAGE_SIZE * 8) + +#define INVALID_PAGE_NR (~0UL) + +#define PAGE_SCRUB_ON_FREE 0x1 + +/** + * Offset between virtual and physical hypervisor addresses. + * + * Jailhouse operates in a physically contiguous memory region, + * enabling offset-based address conversion. + * @note Private, use page_map_hvirt2phys() or page_map_phys2hvirt() instead. + */ +unsigned long page_offset; + +/** Page pool containing physical pages for use by the hypervisor. */ +struct page_pool mem_pool; +/** Page pool containing virtual pages for remappings by the hypervisor. */ +struct page_pool remap_pool = { + .base_address = (void *)REMAP_BASE, + .pages = BITS_PER_PAGE * NUM_REMAP_BITMAP_PAGES, +}; + +/** Descriptor of the hypervisor paging structures. */ +struct paging_structures hv_paging_structs; + +/** Descriptor of paging structures used when parking CPUs. */ +struct paging_structures parking_pt; + +/** + * Trivial implementation of paging::get_phys (for non-terminal levels) + * @param pte See paging::get_phys. + * @param virt See paging::get_phys. + * + * @return @c INVALID_PHYS_ADDR. + * + * @see paging + */ +unsigned long paging_get_phys_invalid(pt_entry_t pte, unsigned long virt) +{ + return INVALID_PHYS_ADDR; +} + +static unsigned long find_next_free_page(struct page_pool *pool, + unsigned long start) +{ + unsigned long bmp_pos, bmp_val, page_nr; + unsigned long start_mask = 0; + + if (start >= pool->pages) + return INVALID_PAGE_NR; + + /* + * If we don't start on the beginning of a bitmap word, create a mask + * to mark the pages before the start page as (virtually) used. + */ + if (start % BITS_PER_LONG > 0) + start_mask = ~0UL >> (BITS_PER_LONG - (start % BITS_PER_LONG)); + + for (bmp_pos = start / BITS_PER_LONG; + bmp_pos < pool->pages / BITS_PER_LONG; bmp_pos++) { + bmp_val = pool->used_bitmap[bmp_pos] | start_mask; + start_mask = 0; + if (bmp_val != ~0UL) { + page_nr = ffzl(bmp_val) + bmp_pos * BITS_PER_LONG; + if (page_nr >= pool->pages) + break; + return page_nr; + } + } + + return INVALID_PAGE_NR; +} + +/** + * Allocate consecutive pages from the specified pool. + * @param pool Page pool to allocate from. + * @param num Number of pages. + * @param align_mask Choose start so that start_page_no & align_mask == 0. + * + * @return Pointer to first page or NULL if allocation failed. + * + * @see page_free + */ +static void *page_alloc_internal(struct page_pool *pool, unsigned int num, + unsigned long align_mask) +{ + unsigned long aligned_start, pool_start, next, start, last; + unsigned int allocated; + + pool_start = (unsigned long)pool->base_address >> PAGE_SHIFT; + + /* The pool itself might not be aligned as required. */ + aligned_start = ((pool_start + align_mask) & ~align_mask) - pool_start; + next = aligned_start; + +restart: + /* Forward the search start to the next aligned page. */ + if ((next - aligned_start) & align_mask) + next += num - ((next - aligned_start) & align_mask); + + start = next = find_next_free_page(pool, next); + if (start == INVALID_PAGE_NR || num == 0) + return NULL; + + /* Enforce alignment (none of align_mask is 0). */ + if ((start - aligned_start) & align_mask) + goto restart; + + for (allocated = 1, last = start; allocated < num; + allocated++, last = next) { + next = find_next_free_page(pool, last + 1); + if (next == INVALID_PAGE_NR) + return NULL; + if (next != last + 1) + goto restart; /* not consecutive */ + } + + for (allocated = 0; allocated < num; allocated++) + set_bit(start + allocated, pool->used_bitmap); + + pool->used_pages += num; + + return pool->base_address + start * PAGE_SIZE; +} + +/** + * Allocate consecutive pages from the specified pool. + * @param pool Page pool to allocate from. + * @param num Number of pages. + * + * @return Pointer to first page or NULL if allocation failed. + * + * @see page_free + */ +void *page_alloc(struct page_pool *pool, unsigned int num) +{ + return page_alloc_internal(pool, num, 0); +} + +/** + * Allocate aligned consecutive pages from the specified pool. + * @param pool Page pool to allocate from. + * @param num Number of pages. Num needs to be a power of 2. + * + * @return Pointer to first page or NULL if allocation failed. + * + * @see page_free + */ +void *page_alloc_aligned(struct page_pool *pool, unsigned int num) +{ + return page_alloc_internal(pool, num, num - 1); +} + +/** + * Release pages to the specified pool. + * @param pool Page pool to release to. + * @param page Address of first page. + * @param num Number of pages. + * + * @see page_alloc + */ +void page_free(struct page_pool *pool, void *page, unsigned int num) +{ + unsigned long page_nr; + + if (!page) + return; + + while (num-- > 0) { + if (pool->flags & PAGE_SCRUB_ON_FREE) + memset(page, 0, PAGE_SIZE); + page_nr = (page - pool->base_address) / PAGE_SIZE; + clear_bit(page_nr, pool->used_bitmap); + pool->used_pages--; + page += PAGE_SIZE; + } +} + +/** + * Translate virtual to physical address according to given paging structures. + * @param pg_structs Paging structures to use for translation. + * @param virt Virtual address. + * @param flags Access flags that have to be supported by the mapping, + * see @ref PAGE_ACCESS_FLAGS. + * + * @return Physical address on success or @c INVALID_PHYS_ADDR if the virtual + * address could not be translated or the requested access is not + * supported by the mapping. + * + * @see paging_phys2hvirt + * @see paging_hvirt2phys + * @see arch_paging_gphys2phys + */ +unsigned long paging_virt2phys(const struct paging_structures *pg_structs, + unsigned long virt, unsigned long flags) +{ + const struct paging *paging = pg_structs->root_paging; + page_table_t pt = pg_structs->root_table; + unsigned long phys; + pt_entry_t pte; + + while (1) { + pte = paging->get_entry(pt, virt); + if (!paging->entry_valid(pte, flags)) + return INVALID_PHYS_ADDR; + phys = paging->get_phys(pte, virt); + if (phys != INVALID_PHYS_ADDR) + return phys; + pt = paging_phys2hvirt(paging->get_next_pt(pte)); + paging++; + } +} + +static void flush_pt_entry(pt_entry_t pte, unsigned long paging_flags) +{ + if (paging_flags & PAGING_COHERENT) + arch_paging_flush_cpu_caches(pte, sizeof(*pte)); +} + +static int split_hugepage(bool hv_paging, const struct paging *paging, + pt_entry_t pte, unsigned long virt, + unsigned long paging_flags) +{ + unsigned long phys = paging->get_phys(pte, virt); + struct paging_structures sub_structs; + unsigned long page_mask, flags; + + if (phys == INVALID_PHYS_ADDR) + return 0; + + page_mask = ~((unsigned long)paging->page_size - 1); + phys &= page_mask; + virt &= page_mask; + + flags = paging->get_flags(pte); + + sub_structs.hv_paging = hv_paging; + sub_structs.root_paging = paging + 1; + sub_structs.root_table = page_alloc(&mem_pool, 1); + if (!sub_structs.root_table) + return -ENOMEM; + paging->set_next_pt(pte, paging_hvirt2phys(sub_structs.root_table)); + flush_pt_entry(pte, paging_flags); + + return paging_create(&sub_structs, phys, paging->page_size, virt, + flags, paging_flags); +} + +/** + * Create or modify a page map. + * @param pg_structs Descriptor of paging structures to be used. + * @param phys Physical address of the region to be mapped. + * @param size Size of the region. + * @param virt Virtual address the region should be mapped to. + * @param access_flags Flags describing the permitted page access, see + * @ref PAGE_ACCESS_FLAGS. + * @param paging_flags Flags describing the paging mode, see @ref PAGING_FLAGS. + * + * @return 0 on success, negative error code otherwise. + * + * @note The function aims at using the largest possible page size for the + * mapping but does not consolidate with neighboring mappings. + * + * @see paging_destroy + * @see paging_get_guest_pages + */ +int paging_create(const struct paging_structures *pg_structs, + unsigned long phys, unsigned long size, unsigned long virt, + unsigned long access_flags, unsigned long paging_flags) +{ + phys &= PAGE_MASK; + virt &= PAGE_MASK; + size = PAGE_ALIGN(size); + + while (size > 0) { + const struct paging *paging = pg_structs->root_paging; + page_table_t pt = pg_structs->root_table; + struct paging_structures sub_structs; + pt_entry_t pte; + int err; + + while (1) { + pte = paging->get_entry(pt, virt); + if (paging->page_size > 0 && + paging->page_size <= size && + ((phys | virt) & (paging->page_size - 1)) == 0 && + (paging_flags & PAGING_HUGE || + paging->page_size == PAGE_SIZE)) { + /* + * We might be overwriting a more fine-grained + * mapping, so release it first. This cannot + * fail as we are working along hugepage + * boundaries. + */ + if (paging->page_size > PAGE_SIZE) { + sub_structs.root_paging = paging; + sub_structs.root_table = pt; + sub_structs.hv_paging = + pg_structs->hv_paging; + paging_destroy(&sub_structs, virt, + paging->page_size, + paging_flags); + } + paging->set_terminal(pte, phys, access_flags); + flush_pt_entry(pte, paging_flags); + break; + } + if (paging->entry_valid(pte, PAGE_PRESENT_FLAGS)) { + err = split_hugepage(pg_structs->hv_paging, + paging, pte, virt, + paging_flags); + if (err) + return err; + pt = paging_phys2hvirt( + paging->get_next_pt(pte)); + } else { + pt = page_alloc(&mem_pool, 1); + if (!pt) + return -ENOMEM; + paging->set_next_pt(pte, + paging_hvirt2phys(pt)); + flush_pt_entry(pte, paging_flags); + } + paging++; + } + if (pg_structs->hv_paging) + arch_paging_flush_page_tlbs(virt); + + phys += paging->page_size; + virt += paging->page_size; + size -= paging->page_size; + } + return 0; +} + +/** + * Destroy a page map. + * @param pg_structs Descriptor of paging structures to be used. + * @param virt Virtual address the region to be unmapped. + * @param size Size of the region. + * @param paging_flags Flags describing the paging mode, see @ref PAGING_FLAGS. + * + * @return 0 on success, negative error code otherwise. + * + * @note If required, this function tries to break up hugepages if they should + * be unmapped only partially. This may require allocating additional pages for + * the paging structures, thus can fail. Unmap request that covers only full + * pages never fail. + * + * @see paging_create + */ +int paging_destroy(const struct paging_structures *pg_structs, + unsigned long virt, unsigned long size, + unsigned long paging_flags) +{ + size = PAGE_ALIGN(size); + + while (size > 0) { + const struct paging *paging = pg_structs->root_paging; + page_table_t pt[MAX_PAGE_TABLE_LEVELS]; + unsigned long page_size; + pt_entry_t pte; + int n = 0; + int err; + + /* walk down the page table, saving intermediate tables */ + pt[0] = pg_structs->root_table; + while (1) { + pte = paging->get_entry(pt[n], virt); + if (!paging->entry_valid(pte, PAGE_PRESENT_FLAGS)) + break; + if (paging->get_phys(pte, virt) != INVALID_PHYS_ADDR) { + unsigned long page_start; + + /* + * If the region to be unmapped doesn't fully + * cover the hugepage, the hugepage will need to + * be split. + */ + page_size = paging->page_size ? + paging->page_size : PAGE_SIZE; + page_start = virt & ~(page_size-1); + + /* + * It's possible that virt + size overflows to + * exactly 0 (e.g. a 512MB region starting at + * 0xe0000000 with 32-bit addresses) during + * normal execution. Any overflow beyond that is + * a programming error. + * + * To handle this case, subtract 1 from the size + * when comparing both sides. Note that size and + * page_size are always > 0, so there's no risk + * of underflow. + */ + if (virt <= page_start && + virt + (size - 1) >= + page_start + (page_size - 1)) + break; + + err = split_hugepage(pg_structs->hv_paging, + paging, pte, virt, + paging_flags); + if (err) + return err; + } + pt[++n] = paging_phys2hvirt(paging->get_next_pt(pte)); + paging++; + } + /* advance by page size of current level paging */ + page_size = paging->page_size ? paging->page_size : PAGE_SIZE; + + /* walk up again, clearing entries, releasing empty tables */ + while (1) { + paging->clear_entry(pte); + flush_pt_entry(pte, paging_flags); + if (n == 0 || !paging->page_table_empty(pt[n])) + break; + page_free(&mem_pool, pt[n], 1); + paging--; + pte = paging->get_entry(pt[--n], virt); + } + if (pg_structs->hv_paging) + arch_paging_flush_page_tlbs(virt); + + if (page_size > size) + break; + virt += page_size; + size -= page_size; + } + return 0; +} + +static unsigned long +paging_gvirt2gphys(const struct guest_paging_structures *pg_structs, + unsigned long gvirt, unsigned long tmp_page, + unsigned long flags) +{ + unsigned long page_table_gphys = pg_structs->root_table_gphys; + const struct paging *paging = pg_structs->root_paging; + unsigned long gphys, phys; + pt_entry_t pte; + int err; + + while (1) { + /* map guest page table */ + phys = arch_paging_gphys2phys(page_table_gphys, + PAGE_READONLY_FLAGS); + if (phys == INVALID_PHYS_ADDR) + return INVALID_PHYS_ADDR; + err = paging_create(&this_cpu_data()->pg_structs, phys, + PAGE_SIZE, tmp_page, PAGE_READONLY_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + if (err) + return INVALID_PHYS_ADDR; + + /* evaluate page table entry */ + pte = paging->get_entry((page_table_t)tmp_page, gvirt); + if (!paging->entry_valid(pte, flags)) + return INVALID_PHYS_ADDR; + gphys = paging->get_phys(pte, gvirt); + if (gphys != INVALID_PHYS_ADDR) + return gphys; + page_table_gphys = paging->get_next_pt(pte); + paging++; + } +} + +/** + * Map physical device resource into hypervisor address space. + * @param phys Physical address of the resource. + * @param size Size of the resource. + * + * @return Virtual mapping address of the resource or NULL on error. + */ +void *paging_map_device(unsigned long phys, unsigned long size) +{ + void *virt; + + virt = page_alloc(&remap_pool, PAGES(size)); + if (!virt) + return NULL; + + if (paging_create(&hv_paging_structs, phys, size, (unsigned long)virt, + PAGE_DEFAULT_FLAGS | PAGE_FLAG_DEVICE, + PAGING_NON_COHERENT | PAGING_HUGE) != 0) { + page_free(&remap_pool, virt, PAGES(size)); + return NULL; + } + + return virt; +} + +/** + * Unmap physical device resource from hypervisor address space. + * @param phys Physical address of the resource. + * @param virt Virtual address of the resource. + * @param size Size of the resource. + * + * @note Unmap must use the same parameters as provided to / returned by + * paging_map_device(). + */ +void paging_unmap_device(unsigned long phys, void *virt, unsigned long size) +{ + /* Cannot fail if paired with paging_map_device. */ + paging_destroy(&hv_paging_structs, (unsigned long)virt, size, + PAGING_NON_COHERENT); + page_free(&remap_pool, virt, PAGES(size)); +} + +/** + * Create a top-level link to the common hypervisor page table. + * @param pg_dest_structs Descriptor of the target paging structures. + * @param virt Virtual start address of the linked region. + * + * @return 0 on success, negative error code otherwise. + * + * @note The link is only created at the lop level of page table. The source + * needs to point the page table hierarchy, not a terminal entry. + */ +int paging_create_hvpt_link(const struct paging_structures *pg_dest_structs, + unsigned long virt) +{ + const struct paging *paging = hv_paging_structs.root_paging; + pt_entry_t source_pte, dest_pte; + + source_pte = paging->get_entry(hv_paging_structs.root_table, virt); + dest_pte = paging->get_entry(pg_dest_structs->root_table, virt); + + /* + * Source page table must by populated and the to-be-linked + * region must not be a terminal entry. + */ + if (!paging->entry_valid(source_pte, PAGE_PRESENT_FLAGS) || + paging->get_phys(source_pte, virt) != INVALID_PHYS_ADDR) + return trace_error(-EINVAL); + + paging->set_next_pt(dest_pte, paging->get_next_pt(source_pte)); + + /* Mapping is always non-coherent, so no flush_pt_entry needed. */ + arch_paging_flush_page_tlbs(virt); + + return 0; +} + +/** + * Map guest (cell) pages into the hypervisor address space. + * @param pg_structs Descriptor of the guest paging structures if @c gaddr + * is a guest-virtual address or @c NULL if it is a + * guest-physical address. + * @param gaddr Guest address of the first page to be mapped. + * @param num Number of pages to be mapped. + * @param flags Access flags for the hypervisor mapping, see + * @ref PAGE_ACCESS_FLAGS. + * + * @return Pointer to first mapped page or @c NULL on error. + * + * @note The mapping is done only for the calling CPU and must thus only be + * used by the very same CPU. + * + * @note The mapping is only temporary, valid until the next invocation of + * page_map_get_guest_pages() on this CPU. It does not require explicit + * unmapping when it is no longer needed. + */ +void *paging_get_guest_pages(const struct guest_paging_structures *pg_structs, + unsigned long gaddr, unsigned int num, + unsigned long flags) +{ + unsigned long phys, gphys, page_virt = TEMPORARY_MAPPING_BASE; + int err; + + if (num > NUM_TEMPORARY_PAGES) + return NULL; + while (num-- > 0) { + if (pg_structs && pg_structs->root_paging) + gphys = paging_gvirt2gphys(pg_structs, gaddr, + page_virt, flags); + else + gphys = gaddr; + + phys = arch_paging_gphys2phys(gphys, flags); + if (phys == INVALID_PHYS_ADDR) + return NULL; + /* map guest page */ + err = paging_create(&this_cpu_data()->pg_structs, phys, + PAGE_SIZE, page_virt, flags, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + if (err) + return NULL; + gaddr += PAGE_SIZE; + page_virt += PAGE_SIZE; + } + return (void *)TEMPORARY_MAPPING_BASE; +} + +int paging_map_all_per_cpu(unsigned int cpu, bool enable) +{ + struct per_cpu *cpu_data = per_cpu(cpu); + + /* + * Note that the physical address does not matter for !enable because + * we mark all pages non-present in that case. + */ + return paging_create(&hv_paging_structs, paging_hvirt2phys(cpu_data), + sizeof(struct per_cpu) - sizeof(struct public_per_cpu), + (unsigned long)cpu_data, + enable ? PAGE_DEFAULT_FLAGS : PAGE_NONPRESENT_FLAGS, + PAGING_NON_COHERENT | PAGING_HUGE); +} + +/** + * Initialize the page mapping subsystem. + * + * @return 0 on success, negative error code otherwise. + */ +int paging_init(void) +{ + unsigned long n, per_cpu_pages, config_pages, bitmap_pages; + unsigned long vaddr, flags; + int err; + + per_cpu_pages = hypervisor_header.max_cpus * + sizeof(struct per_cpu) / PAGE_SIZE; + + config_pages = PAGES(jailhouse_system_config_size(system_config)); + + page_offset = JAILHOUSE_BASE - + system_config->hypervisor_memory.phys_start; + + mem_pool.pages = (system_config->hypervisor_memory.size - + (__page_pool - (u8 *)&hypervisor_header)) / PAGE_SIZE; + bitmap_pages = (mem_pool.pages + BITS_PER_PAGE - 1) / BITS_PER_PAGE; + + if (mem_pool.pages <= per_cpu_pages + config_pages + bitmap_pages) + return -ENOMEM; + + mem_pool.base_address = __page_pool; + mem_pool.used_bitmap = + (unsigned long *)(__page_pool + per_cpu_pages * PAGE_SIZE + + config_pages * PAGE_SIZE); + mem_pool.used_pages = per_cpu_pages + config_pages + bitmap_pages; + for (n = 0; n < mem_pool.used_pages; n++) + set_bit(n, mem_pool.used_bitmap); + mem_pool.flags = PAGE_SCRUB_ON_FREE; + + remap_pool.used_bitmap = page_alloc(&mem_pool, NUM_REMAP_BITMAP_PAGES); + + hv_paging_structs.hv_paging = true; + hv_paging_structs.root_table = + (page_table_t)public_per_cpu(0)->root_table_page; + + arch_paging_init(); + + parking_pt.root_table = page_alloc_aligned(&mem_pool, + CELL_ROOT_PT_PAGES); + if (!parking_pt.root_table) + return -ENOMEM; + + /* Replicate hypervisor mapping of Linux */ + err = paging_create(&hv_paging_structs, + paging_hvirt2phys(&hypervisor_header), + system_config->hypervisor_memory.size, + (unsigned long)&hypervisor_header, + PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_HUGE); + if (err) + return err; + + /* + * Make sure any permission changes on the per_cpu region can be + * performed without allocations of page table pages. + */ + for (n = 0; n < hypervisor_header.max_cpus; n++) { + err = paging_map_all_per_cpu(n, true); + if (err) + return err; + } + + if (CON_IS_MMIO(system_config->debug_console.flags)) { + vaddr = (unsigned long)hypervisor_header.debug_console_base; + /* check if console overlaps remapping region */ + if (vaddr + system_config->debug_console.size >= REMAP_BASE && + vaddr < REMAP_BASE + remap_pool.pages * PAGE_SIZE) + return trace_error(-EINVAL); + + flags = PAGE_DEFAULT_FLAGS | PAGE_FLAG_DEVICE; + if (system_config->debug_console.type == + JAILHOUSE_CON_TYPE_EFIFB) + flags = PAGE_DEFAULT_FLAGS | PAGE_FLAG_FRAMEBUFFER; + err = paging_create(&hv_paging_structs, + system_config->debug_console.address, + system_config->debug_console.size, vaddr, + flags, PAGING_NON_COHERENT | PAGING_HUGE); + if (err) + return err; + } + + return 0; +} + +/** + * Dump usage statistic of the page pools. + * @param when String that characterizes the associated event. + */ +void paging_dump_stats(const char *when) +{ + printk("Page pool usage %s: mem %ld/%ld, remap %ld/%ld\n", when, + mem_pool.used_pages, mem_pool.pages, + remap_pool.used_pages, remap_pool.pages); +} diff --git a/hypervisor/pci.c b/hypervisor/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..6934c33d742763da9e752bd13b8fa835b332ebcd --- /dev/null +++ b/hypervisor/pci.c @@ -0,0 +1,890 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Ivan Kolchin + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSIX_VECTOR_CTRL_DWORD 3 + +#define for_each_configured_pci_device(dev, cell) \ + for ((dev) = (cell)->pci_devices; \ + (u32)((dev) - (cell)->pci_devices) < \ + (cell)->config->num_pci_devices; \ + (dev)++) + +#define for_each_pci_cap(cap, dev, counter) \ + for ((cap) = jailhouse_cell_pci_caps((dev)->cell->config) + \ + (dev)->info->caps_start, (counter) = 0; \ + (counter) < (dev)->info->num_caps; \ + (cap)++, (counter)++) + +/* entry for PCI config space access control */ +struct pci_cfg_control { + enum { + PCI_CONFIG_DENY, + PCI_CONFIG_ALLOW, + PCI_CONFIG_RDONLY, + } type; /* Access type */ + u32 mask; /* Bit set: access type applies; bit cleared: deny access */ +}; + +/* --- Access control for writing to PCI config space registers --- */ +/* Type 1: Endpoints */ +static const struct pci_cfg_control endpoint_write[PCI_CONFIG_HEADER_SIZE] = { + [0x04/4] = {PCI_CONFIG_ALLOW, 0xffffffff}, /* Command, Status */ + [0x0c/4] = {PCI_CONFIG_ALLOW, 0xffffffff}, /* BIST, Header Type (r/o), + Latency, Cacheline */ + [0x30/4] = {PCI_CONFIG_RDONLY, 0xffffffff}, /* ROM BAR */ + [0x3c/4] = {PCI_CONFIG_ALLOW, 0x000000ff}, /* Int Line */ +}; + +/* Type 2: Bridges + * Note: Ignore limit/base reprogramming attempts because the root cell will + * perform them on bus rescans. */ +static const struct pci_cfg_control bridge_write[PCI_CONFIG_HEADER_SIZE] = { + [0x04/4] = {PCI_CONFIG_ALLOW, 0xffffffff}, /* Command, Status */ + [0x0c/4] = {PCI_CONFIG_ALLOW, 0xffffffff}, /* BIST, Header Type (r/o), + Latency, Cacheline */ + [0x1c/4] = {PCI_CONFIG_RDONLY, 0x0000ffff}, /* I/O Limit & Base */ + [0x20/4 ... /* Memory Limit/Base, Prefetch Memory Limit/Base, */ + 0x30/4] = {PCI_CONFIG_RDONLY, 0xffffffff}, /* I/O Limit & Base */ + [0x3c/4] = {PCI_CONFIG_ALLOW, 0xffff00ff}, /* Int Line, Bridge Ctrl */ +}; + +static void *pci_space; +static u64 mmcfg_start, mmcfg_size; +static u8 end_bus; + +static unsigned int pci_mmio_count_regions(struct cell *cell) +{ + const struct jailhouse_pci_device *dev_infos = + jailhouse_cell_pci_devices(cell->config); + unsigned int n, regions = 0; + + if (system_config->platform_info.pci_mmconfig_base) + regions++; + + for (n = 0; n < cell->config->num_pci_devices; n++) + if (dev_infos[n].type == JAILHOUSE_PCI_TYPE_IVSHMEM) + regions += PCI_IVSHMEM_NUM_MMIO_REGIONS; + else if (dev_infos[n].msix_address) + regions++; + + return regions; +} + +static void *pci_get_device_mmcfg_base(u16 bdf) +{ + return pci_space + ((unsigned long)bdf << 12); +} + +/** + * Read from PCI config space. + * @param bdf 16-bit bus/device/function ID of target. + * @param address Config space access address. + * @param size Access size (1, 2 or 4 bytes). + * + * @return Read value. + * + * @see pci_write_config + */ +u32 pci_read_config(u16 bdf, u16 address, unsigned int size) +{ + void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address; + + if (!pci_space || PCI_BUS(bdf) > end_bus) + return arch_pci_read_config(bdf, address, size); + + if (size == 1) + return mmio_read8(mmcfg_addr); + else if (size == 2) + return mmio_read16(mmcfg_addr); + else + return mmio_read32(mmcfg_addr); +} + +/** + * Write to PCI config space. + * @param bdf 16-bit bus/device/function ID of target. + * @param address Config space access address. + * @param value Value to be written. + * @param size Access size (1, 2 or 4 bytes). + * + * @see pci_read_config + */ +void pci_write_config(u16 bdf, u16 address, u32 value, unsigned int size) +{ + void *mmcfg_addr = pci_get_device_mmcfg_base(bdf) + address; + + if (!pci_space || PCI_BUS(bdf) > end_bus) + return arch_pci_write_config(bdf, address, value, size); + + if (size == 1) + mmio_write8(mmcfg_addr, value); + else if (size == 2) + mmio_write16(mmcfg_addr, value); + else + mmio_write32(mmcfg_addr, value); +} + +/** + * Look up device owned by a cell. + * @param[in] cell Owning cell. + * @param bdf 16-bit bus/device/function ID. + * + * @return Pointer to owned PCI device or NULL. + */ +struct pci_device *pci_get_assigned_device(const struct cell *cell, u16 bdf) +{ + const struct jailhouse_pci_device *dev_info = + jailhouse_cell_pci_devices(cell->config); + u32 n; + + /* We iterate over the static device information to increase cache + * locality. */ + for (n = 0; n < cell->config->num_pci_devices; n++) + if (dev_info[n].bdf == bdf) + return cell->pci_devices[n].cell ? + &cell->pci_devices[n] : NULL; + + return NULL; +} + +/** + * Look up capability at given config space address. + * @param device The device to be accessed. + * @param address Config space access address. + * + * @return Corresponding capability structure or NULL if none found. + * + * @private + */ +static const struct jailhouse_pci_capability * +pci_find_capability(struct pci_device *device, u16 address) +{ + const struct jailhouse_pci_capability *cap = + jailhouse_cell_pci_caps(device->cell->config) + + device->info->caps_start; + u32 n; + + for (n = 0; n < device->info->num_caps; n++, cap++) + if (cap->start <= address && cap->start + cap->len > address) + return cap; + + return NULL; +} + +/** + * Moderate config space read access. + * @param device The device to be accessed. If NULL, access will be + * emulated, returning a value of -1. + * @param address Config space address. + * @param size Access size (1, 2 or 4 bytes). + * @param value Pointer to buffer to receive the emulated value if + * PCI_ACCESS_DONE is returned. + * + * @return PCI_ACCESS_PERFORM or PCI_ACCESS_DONE. + * + * @see pci_cfg_write_moderate + */ +enum pci_access pci_cfg_read_moderate(struct pci_device *device, u16 address, + unsigned int size, u32 *value) +{ + const struct jailhouse_pci_capability *cap; + unsigned int bar_no, cap_offs; + + if (!device) { + *value = -1; + return PCI_ACCESS_DONE; + } + + /* Emulate BARs for physical and virtual devices */ + if (device->info->type != JAILHOUSE_PCI_TYPE_BRIDGE) { + /* Emulate BAR access, always returning the shadow value. */ + if (address >= PCI_CFG_BAR && address <= PCI_CFG_BAR_END) { + bar_no = (address - PCI_CFG_BAR) / 4; + *value = device->bar[bar_no] >> ((address % 4) * 8); + return PCI_ACCESS_DONE; + } + + /* We do not expose ROMs. */ + if (address >= PCI_CFG_ROMBAR && address < PCI_CFG_CAPS) { + *value = 0; + return PCI_ACCESS_DONE; + } + } + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return ivshmem_pci_cfg_read(device, address, value); + + if (address < PCI_CONFIG_HEADER_SIZE) + return PCI_ACCESS_PERFORM; + + cap = pci_find_capability(device, address); + if (!cap) + return PCI_ACCESS_PERFORM; + + cap_offs = address - cap->start; + if (cap->id == PCI_CAP_ID_MSI && cap_offs >= 4 && + (cap_offs < 10 || (device->info->msi_64bits && cap_offs < 14))) { + *value = device->msi_registers.raw[cap_offs / 4] >> + ((cap_offs % 4) * 8); + return PCI_ACCESS_DONE; + } + + return PCI_ACCESS_PERFORM; +} + +static int pci_update_msix(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + unsigned int n; + int result; + + for (n = 0; n < device->info->num_msix_vectors; n++) { + result = arch_pci_update_msix_vector(device, n); + if (result < 0) + return result; + } + return 0; +} + +/** + * Moderate config space write access. + * @param device The device to be accessed. If NULL, access will be + * rejected. + * @param address Config space address. + * @param size Access size (1, 2 or 4 bytes). + * @param value Value to be written. + * + * @return PCI_ACCESS_REJECT, PCI_ACCESS_PERFORM or PCI_ACCESS_DONE. + * + * @see pci_cfg_read_moderate + */ +enum pci_access pci_cfg_write_moderate(struct pci_device *device, u16 address, + unsigned int size, u32 value) +{ + const struct jailhouse_pci_capability *cap; + /* initialize list to work around wrong compiler warning */ + unsigned int bias_shift = (address % 4) * 8; + u32 mask = BYTE_MASK(size) << bias_shift; + struct pci_cfg_control cfg_control; + unsigned int bar_no, cap_offs; + + if (!device) + return PCI_ACCESS_REJECT; + + value <<= bias_shift; + + /* Emulate BARs for physical and virtual devices */ + if (device->info->type != JAILHOUSE_PCI_TYPE_BRIDGE && + address >= PCI_CFG_BAR && address <= PCI_CFG_BAR_END) { + bar_no = (address - PCI_CFG_BAR) / 4; + mask &= device->info->bar_mask[bar_no]; + device->bar[bar_no] &= ~mask; + device->bar[bar_no] |= value & mask; + return PCI_ACCESS_DONE; + } + + if (address < PCI_CONFIG_HEADER_SIZE) { + if (device->info->type == JAILHOUSE_PCI_TYPE_BRIDGE) + cfg_control = bridge_write[address / 4]; + else /* physical or virtual device */ + cfg_control = endpoint_write[address / 4]; + + if ((cfg_control.mask & mask) != mask) + return PCI_ACCESS_REJECT; + + switch (cfg_control.type) { + case PCI_CONFIG_ALLOW: + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return ivshmem_pci_cfg_write(device, + address / 4, mask, value); + return PCI_ACCESS_PERFORM; + case PCI_CONFIG_RDONLY: + return PCI_ACCESS_DONE; + default: + return PCI_ACCESS_REJECT; + } + } + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) + return ivshmem_pci_cfg_write(device, address / 4, mask, value); + + cap = pci_find_capability(device, address); + if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE)) + return PCI_ACCESS_REJECT; + + cap_offs = address - cap->start; + if (cap->id == PCI_CAP_ID_MSI && + (cap_offs < 10 || (device->info->msi_64bits && cap_offs < 14))) { + device->msi_registers.raw[cap_offs / 4] &= ~mask; + device->msi_registers.raw[cap_offs / 4] |= value; + + if (arch_pci_update_msi(device, cap) < 0) + return PCI_ACCESS_REJECT; + + /* + * Address and data words are emulated, the control word is + * written as-is. + */ + if (cap_offs >= 4) + return PCI_ACCESS_DONE; + } else if (cap->id == PCI_CAP_ID_MSIX && cap_offs < 4) { + device->msix_registers.raw &= ~mask; + device->msix_registers.raw |= value; + + if (pci_update_msix(device, cap) < 0) + return PCI_ACCESS_REJECT; + } + + return PCI_ACCESS_PERFORM; +} + +static enum mmio_result pci_msix_access_handler(void *arg, + struct mmio_access *mmio) +{ + unsigned int dword = + (mmio->address % sizeof(union pci_msix_vector)) >> 2; + struct pci_device *device = arg; + unsigned int index; + + /* access must be DWORD-aligned */ + if (mmio->address & 0x3) + goto invalid_access; + + index = mmio->address / sizeof(union pci_msix_vector); + + if (mmio->is_write) { + /* + * The PBA may share a page with the MSI-X table. Writing to + * PBA entries is undefined. We declare it as invalid. + */ + if (index >= device->info->num_msix_vectors) + goto invalid_access; + + device->msix_vectors[index].raw[dword] = mmio->value; + if (arch_pci_update_msix_vector(device, index) < 0) + goto invalid_access; + + if (dword == MSIX_VECTOR_CTRL_DWORD) + mmio_write32(&device->msix_table[index].raw[dword], + mmio->value); + } else { + if (index >= device->info->num_msix_vectors || + dword == MSIX_VECTOR_CTRL_DWORD) + mmio->value = mmio_read32(((void *)device->msix_table) + + mmio->address); + else + mmio->value = device->msix_vectors[index].raw[dword]; + } + return MMIO_HANDLED; + +invalid_access: + panic_printk("FATAL: Invalid PCI MSI-X table/PBA access, device " + "%02x:%02x.%x\n", PCI_BDF_PARAMS(device->info->bdf)); + return MMIO_ERROR; +} + +static enum mmio_result pci_mmconfig_access_handler(void *arg, + struct mmio_access *mmio) +{ + u32 reg_addr = mmio->address & 0xfff; + u16 bdf = mmio->address >> 12; + struct pci_device *device; + enum pci_access result; + u32 val; + + /* only up to 4-byte accesses supported */ + if (mmio->size > 4) + goto invalid_access; + + device = pci_get_assigned_device(this_cell(), bdf); + + if (mmio->is_write) { + result = pci_cfg_write_moderate(device, reg_addr, mmio->size, + mmio->value); + if (result == PCI_ACCESS_REJECT) + goto invalid_access; + } else { + result = pci_cfg_read_moderate(device, reg_addr, mmio->size, + &val); + if (result != PCI_ACCESS_PERFORM) + mmio->value = val; + } + if (result == PCI_ACCESS_PERFORM) + mmio_perform_access(pci_space, mmio); + + return MMIO_HANDLED; + +invalid_access: + panic_printk("FATAL: Invalid PCI MMCONFIG write, device %02x:%02x.%x, " + "reg: 0x%x, size: %d\n", PCI_BDF_PARAMS(bdf), reg_addr, + mmio->size); + return MMIO_ERROR; + +} + +/** + * Retrieve number of enabled MSI vector of a device. + * @param device The device to be examined. + * + * @return number of vectors. + */ +unsigned int pci_enabled_msi_vectors(struct pci_device *device) +{ + return device->msi_registers.msg32.enable ? + 1 << device->msi_registers.msg32.mme : 0; +} + +static void pci_save_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + u16 bdf = device->info->bdf; + unsigned int n; + + for (n = 0; n < (device->info->msi_64bits ? 4 : 3); n++) + device->msi_registers.raw[n] = + pci_read_config(bdf, cap->start + n * 4, 4); +} + +static void pci_restore_msi(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + unsigned int n; + + for (n = 1; n < (device->info->msi_64bits ? 4 : 3); n++) + pci_write_config(device->info->bdf, cap->start + n * 4, + device->msi_registers.raw[n], 4); +} + +static void pci_suppress_msix(struct pci_device *device, + const struct jailhouse_pci_capability *cap, + bool suppressed) +{ + union pci_msix_registers regs = device->msix_registers; + + if (suppressed) + regs.fmask = 1; + pci_write_config(device->info->bdf, cap->start, regs.raw, 4); +} + +static void pci_save_msix(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + unsigned int n, r; + + device->msix_registers.raw = + pci_read_config(device->info->bdf, cap->start, 4); + + for (n = 0; n < device->info->num_msix_vectors; n++) + for (r = 0; r < 4; r++) + device->msix_vectors[n].raw[r] = + mmio_read32(&device->msix_table[n].raw[r]); +} + +static void pci_restore_msix(struct pci_device *device, + const struct jailhouse_pci_capability *cap) +{ + unsigned int n, r; + + for (n = 0; n < device->info->num_msix_vectors; n++) + /* only restore address/data, control is write-through */ + for (r = 0; r < 3; r++) + mmio_write32(&device->msix_table[n].raw[r], + device->msix_vectors[n].raw[r]); + pci_suppress_msix(device, cap, false); +} + +/** + * Prepare the handover of PCI devices to Jailhouse or back to Linux. + */ +void pci_prepare_handover(void) +{ + const struct jailhouse_pci_capability *cap; + struct pci_device *device; + unsigned int n; + + if (!root_cell.pci_devices) + return; + + for_each_configured_pci_device(device, &root_cell) { + if (!device->cell) + continue; + for_each_pci_cap(cap, device, n) { + if (cap->id == PCI_CAP_ID_MSI) + arch_pci_set_suppress_msi(device, cap, true); + else if (cap->id == PCI_CAP_ID_MSIX) + pci_suppress_msix(device, cap, true); + } + } +} + +void pci_reset_device(struct pci_device *device) +{ + const struct jailhouse_pci_capability *cap; + unsigned int n; + + memset(&device->msi_registers, 0, sizeof(device->msi_registers)); + for (n = 0; n < device->info->num_msix_vectors; n++) { + device->msix_vectors[n].address = 0; + device->msix_vectors[n].data = 0; + device->msix_vectors[n].masked = 1; + } + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) { + ivshmem_reset(device); + return; + } + + /* Make sure we can reach the MSI-X registers. */ + pci_write_config(device->info->bdf, PCI_CFG_COMMAND, PCI_CMD_MEM, 2); + + for_each_pci_cap(cap, device, n) { + if (cap->id == PCI_CAP_ID_MSI || cap->id == PCI_CAP_ID_MSIX) + /* Disable MSI/MSI-X by clearing the control word. */ + pci_write_config(device->info->bdf, cap->start+2, 0, 2); + if (cap->id == PCI_CAP_ID_MSIX) + /* Mask each MSI-X vector also physically. */ + for (n = 0; n < device->info->num_msix_vectors; n++) + mmio_write32(&device->msix_table[n].raw[3], + device->msix_vectors[n].raw[3]); + } + + /* + * Silence INTx of the physical device by setting the mask bit. + * This is a deviation from the specified reset state. + */ + pci_write_config(device->info->bdf, PCI_CFG_COMMAND, + PCI_CMD_INTX_OFF, 2); +} + +static int pci_add_physical_device(struct cell *cell, struct pci_device *device) +{ + unsigned int n, pages, size = device->info->msix_region_size; + int err; + + printk("Adding PCI device %02x:%02x.%x to cell \"%s\"\n", + PCI_BDF_PARAMS(device->info->bdf), cell->config->name); + + for (n = 0; n < PCI_NUM_BARS; n ++) + device->bar[n] = pci_read_config(device->info->bdf, + PCI_CFG_BAR + n * 4, 4); + + err = arch_pci_add_physical_device(cell, device); + if (err) + return err; + + if (device->info->msix_address) { + device->msix_table = + paging_map_device(device->info->msix_address, size); + if (!device->msix_table) { + err = -ENOMEM; + goto error_remove_dev; + } + + if (device->info->num_msix_vectors > PCI_EMBEDDED_MSIX_VECTS) { + pages = PAGES(sizeof(union pci_msix_vector) * + device->info->num_msix_vectors); + device->msix_vectors = page_alloc(&mem_pool, pages); + if (!device->msix_vectors) { + err = -ENOMEM; + goto error_unmap_table; + } + } + + mmio_region_register(cell, device->info->msix_address, size, + pci_msix_access_handler, device); + } + + device->cell = cell; + if (cell != &root_cell) + pci_reset_device(device); + + return 0; + +error_unmap_table: + paging_unmap_device(device->info->msix_address, device->msix_table, + size); +error_remove_dev: + arch_pci_remove_physical_device(device); + return err; +} + +static void pci_remove_physical_device(struct pci_device *device) +{ + struct cell *cell = device->cell; + + printk("Removing PCI device %02x:%02x.%x from cell \"%s\"\n", + PCI_BDF_PARAMS(device->info->bdf), cell->config->name); + + pci_reset_device(device); + arch_pci_remove_physical_device(device); + + device->cell = NULL; + + if (!device->msix_table) + return; + + paging_unmap_device(device->info->msix_address, device->msix_table, + device->info->msix_region_size); + + if (device->msix_vectors != device->msix_vector_array) + page_free(&mem_pool, device->msix_vectors, + PAGES(sizeof(union pci_msix_vector) * + device->info->num_msix_vectors)); + + mmio_region_unregister(cell, device->info->msix_address); +} + +static void pci_cell_exit(struct cell *cell); + +/** + * Perform PCI-specific initialization for a new cell. + * @param cell Cell to be initialized. + * + * @return 0 on success, negative error code otherwise. + * + * @see pci_cell_exit + */ +static int pci_cell_init(struct cell *cell) +{ + unsigned int devlist_pages = PAGES(cell->config->num_pci_devices * + sizeof(struct pci_device)); + const struct jailhouse_pci_device *dev_infos = + jailhouse_cell_pci_devices(cell->config); + const struct jailhouse_pci_capability *cap; + struct pci_device *device, *root_device; + unsigned int ndev, ncap; + int err; + + if (mmcfg_start != 0) + mmio_region_register(cell, mmcfg_start, mmcfg_size, + pci_mmconfig_access_handler, NULL); + + if (cell->config->num_pci_devices == 0) + return 0; + + cell->pci_devices = page_alloc(&mem_pool, devlist_pages); + if (!cell->pci_devices) + return -ENOMEM; + + /* + * We order device states in the same way as the static information + * so that we can use the index of the latter to find the former. For + * the other way around and for obtaining the owner cell, we use more + * handy pointers. The cell pointer also encodes active ownership. + */ + for (ndev = 0; ndev < cell->config->num_pci_devices; ndev++) { + device = &cell->pci_devices[ndev]; + device->info = &dev_infos[ndev]; + device->msix_vectors = device->msix_vector_array; + + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) { + err = ivshmem_init(cell, device); + if (err) + goto error; + + continue; + } + + root_device = pci_get_assigned_device(&root_cell, + dev_infos[ndev].bdf); + if (root_device) + pci_remove_physical_device(root_device); + + err = pci_add_physical_device(cell, device); + if (err) + goto error; + + for_each_pci_cap(cap, device, ncap) + if (cap->id == PCI_CAP_ID_MSI) + pci_save_msi(device, cap); + else if (cap->id == PCI_CAP_ID_MSIX) + pci_save_msix(device, cap); + } + + if (cell == &root_cell) + pci_prepare_handover(); + + return 0; +error: + pci_cell_exit(cell); + return err; +} + +void pci_cell_reset(struct cell *cell) +{ + struct pci_device *device; + + for_each_configured_pci_device(device, cell) + if (device->cell) + pci_reset_device(device); +} + +static void pci_return_device_to_root_cell(struct pci_device *device) +{ + struct pci_device *root_device; + + for_each_configured_pci_device(root_device, &root_cell) + if (root_device->info->domain == device->info->domain && + root_device->info->bdf == device->info->bdf) { + if (pci_add_physical_device(&root_cell, + root_device) < 0) + printk("WARNING: Failed to re-assign PCI " + "device to root cell\n"); + break; + } +} + +/** + * Perform PCI-specific cleanup for a cell under destruction. + * @param cell Cell to be destructed. + * + * @see pci_cell_init + */ +static void pci_cell_exit(struct cell *cell) +{ + unsigned int devlist_pages = PAGES(cell->config->num_pci_devices * + sizeof(struct pci_device)); + struct pci_device *device; + + /* + * Do not destroy the root cell. We will shut down the complete + * hypervisor instead. + */ + if (cell == &root_cell) + return; + + for_each_configured_pci_device(device, cell) + if (device->cell) { + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) { + ivshmem_exit(device); + } else { + pci_remove_physical_device(device); + pci_return_device_to_root_cell(device); + } + } + + page_free(&mem_pool, cell->pci_devices, devlist_pages); +} + +/** + * Apply PCI-specific configuration changes. + * @param cell_added_removed Cell that was added or removed to/from the + * system or NULL. + * + * @see arch_config_commit + */ +void pci_config_commit(struct cell *cell_added_removed) +{ + const struct jailhouse_pci_capability *cap; + struct pci_device *device; + unsigned int n; + int err = 0; + + if (!cell_added_removed) + return; + + for_each_configured_pci_device(device, &root_cell) { + if (!device->cell) + continue; + for_each_pci_cap(cap, device, n) { + if (cap->id == PCI_CAP_ID_MSI) { + err = arch_pci_update_msi(device, cap); + if (device->cell == &root_cell) + arch_pci_set_suppress_msi(device, cap, + false); + } else if (cap->id == PCI_CAP_ID_MSIX) { + err = pci_update_msix(device, cap); + if (device->cell == &root_cell) + pci_suppress_msix(device, cap, false); + } + if (err) + goto error; + } + if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM) { + err = ivshmem_update_msix(device); + if (err) { + cap = NULL; + goto error; + } + } + } + return; + +error: + panic_printk("FATAL: Unsupported MSI/MSI-X state, device %02x:%02x.%x", + PCI_BDF_PARAMS(device->info->bdf)); + if (cap) + panic_printk(", cap %d\n", cap->id); + else + panic_printk("\n"); + panic_stop(); +} + +/** + * Initialization of PCI subsystem. + * + * @return 0 on success, negative error code otherwise. + */ +static int pci_init(void) +{ + mmcfg_start = system_config->platform_info.pci_mmconfig_base; + end_bus = system_config->platform_info.pci_mmconfig_end_bus; + mmcfg_size = (end_bus + 1) * 256 * 4096; + + if (mmcfg_start != 0 && !system_config->platform_info.pci_is_virtual) { + pci_space = paging_map_device(mmcfg_start, mmcfg_size); + if (!pci_space) + return -ENOMEM; + } + + return pci_cell_init(&root_cell); +} + +/** + * Shut down the PCI layer during hypervisor deactivation. + */ +static void pci_shutdown(void) +{ + const struct jailhouse_pci_capability *cap; + struct pci_device *device; + unsigned int n; + + if (!root_cell.pci_devices) + return; + + for_each_configured_pci_device(device, &root_cell) { + if (!device->cell) + continue; + + for_each_pci_cap(cap, device, n) + if (cap->id == PCI_CAP_ID_MSI) + pci_restore_msi(device, cap); + else if (cap->id == PCI_CAP_ID_MSIX) + pci_restore_msix(device, cap); + + if (device->cell != &root_cell) + pci_write_config(device->info->bdf, PCI_CFG_COMMAND, + PCI_CMD_INTX_OFF, 2); + } +} + +DEFINE_UNIT(pci, "PCI"); diff --git a/hypervisor/printk.c b/hypervisor/printk.c new file mode 100644 index 0000000000000000000000000000000000000000..d2ca6eb24abea7e6942e2e416bb7974f8393a901 --- /dev/null +++ b/hypervisor/printk.c @@ -0,0 +1,276 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2022 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +bool virtual_console = false; +volatile struct jailhouse_virt_console console + __attribute__((section(".console"))); + +static spinlock_t printk_lock; + +static void console_write(const char *msg) +{ + arch_dbg_write(msg); + + if (!virtual_console) + return; + + console.busy = true; + /* ensure the busy flag is visible prior to updates of the content */ + memory_barrier(); + while (*msg) { + if (panic_in_progress && panic_cpu != phys_processor_id()) + break; + + console.content[console.tail % sizeof(console.content)] = + *msg++; + console.tail++; + } + /* ensure that all updates are committed before clearing busy */ + memory_barrier(); + console.busy = false; +} + +static void dbg_write_stub(const char *msg) +{ +} + +void (*arch_dbg_write)(const char *msg) = dbg_write_stub; + +#if BITS_PER_LONG < 64 + +static unsigned long long div_u64_u64(unsigned long long dividend, + unsigned long long divisor) +{ + unsigned long long result = 0; + unsigned long long tmp_res, tmp_div; + + while (dividend >= divisor) { + tmp_div = divisor << 1; + tmp_res = 1; + while (dividend >= tmp_div) { + tmp_res <<= 1; + if (tmp_div & (1ULL << 63)) + break; + tmp_div <<= 1; + } + dividend -= divisor * tmp_res; + result += tmp_res; + } + return result; +} + +#else /* BITS_PER_LONG >= 64 */ + +static inline unsigned long long div_u64_u64(unsigned long long dividend, + unsigned long long divisor) +{ + return dividend / divisor; +} + +#endif /* BITS_PER_LONG >= 64 */ + +static char *uint2str(unsigned long long value, char *buf) +{ + unsigned long long digit, divisor = 10000000000000000000ULL; + int first_digit = 1; + + while (divisor > 0) { + digit = div_u64_u64(value, divisor); + value -= digit * divisor; + if (!first_digit || digit > 0 || divisor == 1) { + *buf++ = '0' + digit; + first_digit = 0; + } + divisor = div_u64_u64(divisor, 10); + } + + return buf; +} + +static char *int2str(long long value, char *buf) +{ + if (value < 0) { + *buf++ = '-'; + value = -value; + } + return uint2str(value, buf); +} + +static char *hex2str(unsigned long long value, char *buf, + unsigned long long leading_zero_mask) +{ + static const char hexdigit[] = "0123456789abcdef"; + unsigned long long digit, divisor = 0x1000000000000000ULL; + int first_digit = 1; + + while (divisor > 0) { + digit = div_u64_u64(value, divisor); + value -= digit * divisor; + if (!first_digit || digit > 0 || divisor == 1 || + divisor & leading_zero_mask) { + *buf++ = hexdigit[digit]; + first_digit = 0; + } + divisor >>= 4; + } + + return buf; +} + +static char *align(char *p1, char *p0, unsigned int width, char fill) +{ + unsigned int n; + + /* Note: p1 > p0 here */ + if ((unsigned int)(p1 - p0) >= width) + return p1; + + for (n = 1; p1 - n >= p0; n++) + *(p0 + width - n) = *(p1 - n); + memset(p0, fill, width - (p1 - p0)); + return p0 + width; +} + +static void __vprintk(const char *fmt, va_list ap) +{ + char buf[128]; + char *p, *p0; + char c, fill; + unsigned long long v; + unsigned int width; + enum {SZ_NORMAL, SZ_LONG, SZ_LONGLONG} length; + + p = buf; + + while (1) { + c = *fmt++; + if (c == 0) { + break; + } else if (c == '%') { + *p = 0; + console_write(buf); + p = buf; + + c = *fmt++; + + width = 0; + p0 = p; + fill = (c == '0') ? '0' : ' '; + while (c >= '0' && c <= '9') { + width = width * 10 + c - '0'; + c = *fmt++; + if (width >= sizeof(buf) - 1) + width = 0; + } + + length = SZ_NORMAL; + if (c == 'l') { + length = SZ_LONG; + c = *fmt++; + if (c == 'l') { + length = SZ_LONGLONG; + c = *fmt++; + } + } + + switch (c) { + case 'c': + *p++ = (unsigned char)va_arg(ap, int); + break; + case 'd': + if (length == SZ_LONGLONG) + v = va_arg(ap, long long); + else if (length == SZ_LONG) + v = va_arg(ap, long); + else + v = va_arg(ap, int); + p = int2str(v, p); + p = align(p, p0, width, fill); + break; + case 'p': + *p++ = '0'; + *p++ = 'x'; + v = va_arg(ap, unsigned long); + p = hex2str(v, p, (unsigned long)-1); + break; + case 's': + console_write(va_arg(ap, const char *)); + break; + case 'u': + case 'x': + if (length == SZ_LONGLONG) + v = va_arg(ap, unsigned long long); + else if (length == SZ_LONG) + v = va_arg(ap, unsigned long); + else + v = va_arg(ap, unsigned int); + if (c == 'u') + p = uint2str(v, p); + else + p = hex2str(v, p, 0); + p = align(p, p0, width, fill); + break; + default: + *p++ = '%'; + *p++ = c; + break; + } + } else { + *p++ = c; + } + if (p >= &buf[sizeof(buf) - 1]) { + *p = 0; + console_write(buf); + p = buf; + } + } + + *p = 0; + console_write(buf); +} + +void printk(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + spin_lock(&printk_lock); + __vprintk(fmt, ap); + spin_unlock(&printk_lock); + + va_end(ap); +} + +void panic_printk(const char *fmt, ...) +{ + unsigned long cpu_id = phys_processor_id(); + va_list ap; + + if (atomic_test_and_set_bit(0, &panic_in_progress) && + panic_cpu != cpu_id) + return; + panic_cpu = cpu_id; + + va_start(ap, fmt); + + __vprintk(fmt, ap); + + va_end(ap); +} diff --git a/hypervisor/setup.c b/hypervisor/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..f0ee089676fdc8f2c510c34282b41b8a018743cc --- /dev/null +++ b/hypervisor/setup.c @@ -0,0 +1,279 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern u8 __text_start[]; + +static const __attribute__((aligned(PAGE_SIZE))) u8 empty_page[PAGE_SIZE]; + +static spinlock_t init_lock; +static unsigned int master_cpu_id = INVALID_CPU_ID; +static volatile unsigned int entered_cpus, initialized_cpus; +static volatile int error; + +static void init_early(unsigned int cpu_id) +{ + unsigned long core_and_percpu_size = hypervisor_header.core_size + + sizeof(struct per_cpu) * hypervisor_header.max_cpus; + u64 hyp_phys_start, hyp_phys_end; + struct jailhouse_memory hv_page; + + master_cpu_id = cpu_id; + + system_config = (struct jailhouse_system *) + (JAILHOUSE_BASE + core_and_percpu_size); + + virtual_console = SYS_FLAGS_VIRTUAL_DEBUG_CONSOLE(system_config->flags); + + arch_dbg_write_init(); + + printk("\nInitializing Jailhouse hypervisor %s on CPU %d\n", + JAILHOUSE_VERSION, cpu_id); + printk("Code location: %p\n", __text_start); + + gcov_init(); + + error = paging_init(); + if (error) + return; + + root_cell.config = &system_config->root_cell; + + error = cell_init(&root_cell); + if (error) + return; + + error = arch_init_early(); + if (error) + return; + + /* + * Back the region of the hypervisor core and per-CPU page with empty + * pages for Linux. This allows to fault-in the hypervisor region into + * Linux' page table before shutdown without triggering violations. + * + * Allow read access to the console page, if the hypervisor has the + * debug console flag JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE set. + */ + hyp_phys_start = system_config->hypervisor_memory.phys_start; + hyp_phys_end = hyp_phys_start + system_config->hypervisor_memory.size; + + hv_page.virt_start = hyp_phys_start; + hv_page.size = PAGE_SIZE; + hv_page.flags = JAILHOUSE_MEM_READ; + while (hv_page.virt_start < hyp_phys_end) { + if (virtual_console && + hv_page.virt_start == paging_hvirt2phys(&console)) + hv_page.phys_start = paging_hvirt2phys(&console); + else + hv_page.phys_start = paging_hvirt2phys(empty_page); + error = arch_map_memory_region(&root_cell, &hv_page); + if (error) + return; + hv_page.virt_start += PAGE_SIZE; + } + + paging_dump_stats("after early setup"); + printk("Initializing processors:\n"); +} + +static void cpu_init(struct per_cpu *cpu_data) +{ + int err = -EINVAL; + + printk(" CPU %d... ", cpu_data->public.cpu_id); + + if (!cpu_id_valid(cpu_data->public.cpu_id)) + goto failed; + + cpu_data->public.cell = &root_cell; + + /* set up per-CPU page table */ + cpu_data->pg_structs.hv_paging = true; + cpu_data->pg_structs.root_paging = hv_paging_structs.root_paging; + cpu_data->pg_structs.root_table = + (page_table_t)cpu_data->public.root_table_page; + + err = paging_create_hvpt_link(&cpu_data->pg_structs, JAILHOUSE_BASE); + if (err) + goto failed; + + if (CON_IS_MMIO(system_config->debug_console.flags)) { + err = paging_create_hvpt_link(&cpu_data->pg_structs, + (unsigned long)hypervisor_header.debug_console_base); + if (err) + goto failed; + } + + /* set up private mapping of per-CPU data structure */ + err = paging_create(&cpu_data->pg_structs, paging_hvirt2phys(cpu_data), + sizeof(*cpu_data), LOCAL_CPU_BASE, + PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_HUGE); + if (err) + goto failed; + + err = arch_cpu_init(cpu_data); + if (err) + goto failed; + + /* Make sure any remappings to the temporary regions can be performed + * without allocations of page table pages. */ + err = paging_create(&cpu_data->pg_structs, 0, + NUM_TEMPORARY_PAGES * PAGE_SIZE, + TEMPORARY_MAPPING_BASE, PAGE_NONPRESENT_FLAGS, + PAGING_NON_COHERENT | PAGING_NO_HUGE); + if (err) + goto failed; + + printk("OK\n"); + + /* + * If this CPU is last, make sure everything was committed before we + * signal the other CPUs spinning on initialized_cpus that they can + * continue. + */ + memory_barrier(); + initialized_cpus++; + return; + +failed: + printk("FAILED\n"); + error = err; +} + +static void init_late(void) +{ + unsigned int n, cpu, expected_cpus = 0; + const struct jailhouse_memory *mem; + struct unit *unit; + + for_each_cpu(cpu, root_cell.cpu_set) + expected_cpus++; + if (hypervisor_header.online_cpus != expected_cpus) { + error = trace_error(-EINVAL); + return; + } + + for_each_unit(unit) { + printk("Initializing unit: %s\n", unit->name); + error = unit->init(); + if (error) + return; + } + + for_each_mem_region(mem, root_cell.config, n) { + if (JAILHOUSE_MEMORY_IS_SUBPAGE(mem)) + error = mmio_subpage_register(&root_cell, mem); + else + error = arch_map_memory_region(&root_cell, mem); + if (error) + return; + } + + config_commit(&root_cell); + + paging_dump_stats("after late setup"); +} + +/* + * This is the architecture independent C entry point, which is called by + * arch_entry. This routine is called on each CPU when initializing Jailhouse. + */ +int entry(unsigned int cpu_id, struct per_cpu *cpu_data) +{ + static volatile bool activate; + bool master = false; + + cpu_data->public.cpu_id = cpu_id; + + spin_lock(&init_lock); + + /* + * If this CPU is last, make sure everything was committed before we + * signal the other CPUs spinning on entered_cpus that they can + * continue. + */ + memory_barrier(); + entered_cpus++; + + spin_unlock(&init_lock); + + while (entered_cpus < hypervisor_header.online_cpus) + cpu_relax(); + + spin_lock(&init_lock); + + if (master_cpu_id == INVALID_CPU_ID) { + /* Only the master CPU, the first to enter this + * function, performs system-wide initializations. */ + master = true; + init_early(cpu_id); + } + + if (!error) + cpu_init(cpu_data); + + spin_unlock(&init_lock); + + while (!error && initialized_cpus < hypervisor_header.online_cpus) + cpu_relax(); + + if (!error && master) { + init_late(); + if (!error) { + /* + * Make sure everything was committed before we signal + * the other CPUs that they can continue. + */ + memory_barrier(); + activate = true; + } + } else { + while (!error && !activate) + cpu_relax(); + } + + if (error) { + if (master) + shutdown(); + arch_cpu_restore(cpu_id, error); + return error; + } + + if (master) + printk("Activating hypervisor\n"); + + /* point of no return */ + arch_cpu_activate_vmm(); +} + +/** Hypervisor description header. */ +struct jailhouse_header __attribute__((section(".header"))) +hypervisor_header = { + .signature = JAILHOUSE_SIGNATURE, + .core_size = (unsigned long)__page_pool - JAILHOUSE_BASE, + .percpu_size = sizeof(struct per_cpu), + .entry = arch_entry - JAILHOUSE_BASE, + .console_page = (unsigned long)&console - JAILHOUSE_BASE, +}; diff --git a/hypervisor/uart-8250.c b/hypervisor/uart-8250.c new file mode 100644 index 0000000000000000000000000000000000000000..e61128204f10e1e1d111fe04bbf1aca5abf9f911 --- /dev/null +++ b/hypervisor/uart-8250.c @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#define UART_TX 0x0 +#define UART_DLL 0x0 +#define UART_DLM 0x1 +#define UART_LCR 0x3 +#define UART_LCR_8N1 0x03 +#define UART_LCR_DLAB 0x80 +#define UART_LSR 0x5 +#define UART_LSR_THRE 0x20 + +static void reg_out_mmio8(struct uart_chip *chip, unsigned int reg, u32 value) +{ + mmio_write8(chip->virt_base + reg, value); +} + +static u32 reg_in_mmio8(struct uart_chip *chip, unsigned int reg) +{ + return mmio_read8(chip->virt_base + reg); +} + +static void reg_out_mmio32(struct uart_chip *chip, unsigned int reg, u32 value) +{ + mmio_write32(chip->virt_base + reg * 4, value); +} + +static u32 reg_in_mmio32(struct uart_chip *chip, unsigned int reg) +{ + return mmio_read32(chip->virt_base + reg * 4); +} + +static void uart_init(struct uart_chip *chip) +{ + const u32 flags = system_config->debug_console.flags; + + if (CON_IS_MMIO(flags) && CON_USES_REGDIST_1(flags)) { + chip->reg_out = reg_out_mmio8; + chip->reg_in = reg_in_mmio8; + } + + /* only initialise if divider is not zero */ + if (!chip->debug_console->divider) + return; + + chip->reg_out(chip, UART_LCR, UART_LCR_DLAB); + chip->reg_out(chip, UART_DLL, chip->debug_console->divider & 0xff); + chip->reg_out(chip, UART_DLM, + (chip->debug_console->divider >> 8) & 0xff); + chip->reg_out(chip, UART_LCR, UART_LCR_8N1); +} + +static bool uart_is_busy(struct uart_chip *chip) +{ + return !(chip->reg_in(chip, UART_LSR) & UART_LSR_THRE); +} + +static void uart_write_char(struct uart_chip *chip, char c) +{ + chip->reg_out(chip, UART_TX, c); +} + +struct uart_chip uart_8250_ops = { + .init = uart_init, + .is_busy = uart_is_busy, + .write_char = uart_write_char, + .reg_out = reg_out_mmio32, + .reg_in = reg_in_mmio32, +}; diff --git a/hypervisor/uart.c b/hypervisor/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..6980970f672d2ca7869fc0e6600fc9fc394caa84 --- /dev/null +++ b/hypervisor/uart.c @@ -0,0 +1,45 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2016 + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Ralf Ramsauer + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +struct uart_chip *uart = NULL; + +static void uart_write_char(char c) +{ + while (uart->is_busy(uart)) + cpu_relax(); + if (panic_in_progress && panic_cpu != phys_processor_id()) + return; + uart->write_char(uart, c); +} + +void uart_write(const char *msg) +{ + char c; + + while (1) { + c = *msg++; + if (!c) + break; + + if (c == '\n') + uart_write_char('\r'); + + uart_write_char(c); + } +} diff --git a/include/arch/arm-common/asm/jailhouse_hypercall.h b/include/arch/arm-common/asm/jailhouse_hypercall.h new file mode 100644 index 0000000000000000000000000000000000000000..3988fd79cad4846e8ef254bb768d47e21054fc4e --- /dev/null +++ b/include/arch/arm-common/asm/jailhouse_hypercall.h @@ -0,0 +1,118 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define JAILHOUSE_HVC_CODE 0x4a48 + +/* CPU statistics, common part */ +#define JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE JAILHOUSE_GENERIC_CPU_STATS +#define JAILHOUSE_CPU_STAT_VMEXITS_VIRQ JAILHOUSE_GENERIC_CPU_STATS + 1 +#define JAILHOUSE_CPU_STAT_VMEXITS_VSGI JAILHOUSE_GENERIC_CPU_STATS + 2 +#define JAILHOUSE_CPU_STAT_VMEXITS_PSCI JAILHOUSE_GENERIC_CPU_STATS + 3 +#define JAILHOUSE_CPU_STAT_VMEXITS_SMCCC JAILHOUSE_GENERIC_CPU_STATS + 4 + +#ifndef __ASSEMBLY__ + +struct jailhouse_comm_region { + COMM_REGION_GENERIC_HEADER; + __u8 gic_version; + __u8 padding[7]; + __u64 gicd_base; + __u64 gicc_base; + __u64 gicr_base; + __u32 vpci_irq_base; +} __attribute__((packed)); + +static inline __jh_arg jailhouse_call(__jh_arg num) +{ + register __jh_arg num_result asm(JAILHOUSE_CALL_NUM_RESULT) = num; + + asm volatile( + JAILHOUSE_CALL_INS + : "+r" (num_result) + : : "memory", JAILHOUSE_CALL_ARG1, JAILHOUSE_CALL_ARG2, + JAILHOUSE_CALL_CLOBBERED); + return num_result; +} + +static inline __jh_arg jailhouse_call_arg1(__jh_arg num, __jh_arg arg1) +{ + register __jh_arg num_result asm(JAILHOUSE_CALL_NUM_RESULT) = num; + register __jh_arg __arg1 asm(JAILHOUSE_CALL_ARG1) = arg1; + + asm volatile( + JAILHOUSE_CALL_INS + : "+r" (num_result), "+r" (__arg1) + : : "memory", JAILHOUSE_CALL_ARG2, JAILHOUSE_CALL_CLOBBERED); + return num_result; +} + +static inline __jh_arg jailhouse_call_arg2(__jh_arg num, __jh_arg arg1, + __jh_arg arg2) +{ + register __jh_arg num_result asm(JAILHOUSE_CALL_NUM_RESULT) = num; + register __jh_arg __arg1 asm(JAILHOUSE_CALL_ARG1) = arg1; + register __jh_arg __arg2 asm(JAILHOUSE_CALL_ARG2) = arg2; + + asm volatile( + JAILHOUSE_CALL_INS + : "+r" (num_result), "+r" (__arg1), "+r" (__arg2) + : : "memory", JAILHOUSE_CALL_CLOBBERED); + return num_result; +} + +static inline void +jailhouse_send_msg_to_cell(struct jailhouse_comm_region *comm_region, + __jh_arg msg) +{ + comm_region->reply_from_cell = JAILHOUSE_MSG_NONE; + /* ensure reply was cleared before sending new message */ + asm volatile("dmb ishst" : : : "memory"); + comm_region->msg_to_cell = msg; +} + +static inline void +jailhouse_send_reply_from_cell(struct jailhouse_comm_region *comm_region, + __jh_arg reply) +{ + comm_region->msg_to_cell = JAILHOUSE_MSG_NONE; + /* ensure message was cleared before sending reply */ + asm volatile("dmb ishst" : : : "memory"); + comm_region->reply_from_cell = reply; +} + +#endif /* !__ASSEMBLY__ */ diff --git a/include/arch/arm/asm/jailhouse_hypercall.h b/include/arch/arm/asm/jailhouse_hypercall.h new file mode 100644 index 0000000000000000000000000000000000000000..7cd6bc6313d4c98297a80f8ba7faa370d574580c --- /dev/null +++ b/include/arch/arm/asm/jailhouse_hypercall.h @@ -0,0 +1,54 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define JAILHOUSE_CALL_INS ".arch_extension virt\n\t" \ + "hvc #0x4a48" +#define JAILHOUSE_CALL_NUM_RESULT "r0" +#define JAILHOUSE_CALL_ARG1 "r1" +#define JAILHOUSE_CALL_ARG2 "r2" +#define JAILHOUSE_CALL_CLOBBERED "r3" + +/* CPU statistics, arm-specific part */ +#define JAILHOUSE_CPU_STAT_VMEXITS_CP15 JAILHOUSE_GENERIC_CPU_STATS + 5 +#define JAILHOUSE_NUM_CPU_STATS JAILHOUSE_GENERIC_CPU_STATS + 6 + +#ifndef __ASSEMBLY__ +typedef __u32 __jh_arg; +#endif + +#include "../arm-common/asm/jailhouse_hypercall.h" diff --git a/include/arch/arm64/asm/jailhouse_hypercall.h b/include/arch/arm64/asm/jailhouse_hypercall.h new file mode 100644 index 0000000000000000000000000000000000000000..9c94930f1aa9c7a5adf66c070d387250a724303c --- /dev/null +++ b/include/arch/arm64/asm/jailhouse_hypercall.h @@ -0,0 +1,52 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define JAILHOUSE_CALL_INS "hvc #0x4a48" +#define JAILHOUSE_CALL_NUM_RESULT "x0" +#define JAILHOUSE_CALL_ARG1 "x1" +#define JAILHOUSE_CALL_ARG2 "x2" +#define JAILHOUSE_CALL_CLOBBERED "x3" + +/* CPU statistics, arm64-specific part */ +#define JAILHOUSE_NUM_CPU_STATS JAILHOUSE_GENERIC_CPU_STATS + 5 + +#ifndef __ASSEMBLY__ +typedef __u64 __jh_arg; +#endif + +#include "../arm-common/asm/jailhouse_hypercall.h" diff --git a/include/arch/x86/asm/jailhouse_hypercall.h b/include/arch/x86/asm/jailhouse_hypercall.h new file mode 100644 index 0000000000000000000000000000000000000000..8dffb5c01a4d2e0e7719bc48108b052bec87abd9 --- /dev/null +++ b/include/arch/x86/asm/jailhouse_hypercall.h @@ -0,0 +1,201 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +/* + * As this is never called on a CPU without VM extensions, + * we assume that where VMCALL isn't available, VMMCALL is. + */ +#define JAILHOUSE_CALL_CODE \ + "cmpb $0x01, %[use_vmcall]\n\t"\ + "jne 1f\n\t"\ + "vmcall\n\t"\ + "jmp 2f\n\t"\ + "1: vmmcall\n\t"\ + "2:" + +#define JAILHOUSE_CALL_RESULT "=a" (result) +#define JAILHOUSE_USE_VMCALL [use_vmcall] "m" (jailhouse_use_vmcall) +#define JAILHOUSE_CALL_NUM "a" (num) +#define JAILHOUSE_CALL_ARG1 "D" (arg1) +#define JAILHOUSE_CALL_ARG2 "S" (arg2) + +/* CPU statistics */ +#define JAILHOUSE_CPU_STAT_VMEXITS_PIO JAILHOUSE_GENERIC_CPU_STATS +#define JAILHOUSE_CPU_STAT_VMEXITS_XAPIC JAILHOUSE_GENERIC_CPU_STATS + 1 +#define JAILHOUSE_CPU_STAT_VMEXITS_CR JAILHOUSE_GENERIC_CPU_STATS + 2 +#define JAILHOUSE_CPU_STAT_VMEXITS_CPUID JAILHOUSE_GENERIC_CPU_STATS + 3 +#define JAILHOUSE_CPU_STAT_VMEXITS_XSETBV JAILHOUSE_GENERIC_CPU_STATS + 4 +#define JAILHOUSE_CPU_STAT_VMEXITS_EXCEPTION JAILHOUSE_GENERIC_CPU_STATS + 5 +#define JAILHOUSE_CPU_STAT_VMEXITS_MSR_OTHER JAILHOUSE_GENERIC_CPU_STATS + 6 +#define JAILHOUSE_CPU_STAT_VMEXITS_MSR_X2APIC_ICR \ + JAILHOUSE_GENERIC_CPU_STATS + 7 +#define JAILHOUSE_NUM_CPU_STATS JAILHOUSE_GENERIC_CPU_STATS + 8 + +/* CPUID interface */ +#define JAILHOUSE_CPUID_SIGNATURE 0x40000000 +#define JAILHOUSE_CPUID_FEATURES 0x40000001 + +/** + * @defgroup Hypercalls Hypercall Subsystem + * + * The hypercall subsystem provides an interface for cells to invoke Jailhouse + * services and interact via the communication region. + * + * @{ + */ + +/** + * This variable selects the x86 hypercall instruction to be used by + * jailhouse_call(), jailhouse_call_arg1(), and jailhouse_call_arg2(). + * A caller should define and initialize the variable before calling + * any of these functions. + * + * @li @c false Use AMD's VMMCALL. + * @li @c true Use Intel's VMCALL. + */ +extern bool jailhouse_use_vmcall; + +#ifdef DOXYGEN_CPP +/* included to expand COMM_REGION_GENERIC_HEADER */ +#include +#endif + +/** Communication region between hypervisor and a cell. */ +struct jailhouse_comm_region { + COMM_REGION_GENERIC_HEADER; + + /** I/O port address of the PM timer (x86-specific). */ + __u16 pm_timer_address; + /** Number of CPUs available to the cell (x86-specific). */ + __u16 num_cpus; + /** Calibrated TSC frequency in kHz (x86-specific). */ + __u32 tsc_khz; + /** Calibrated APIC timer frequency in kHz or 0 if TSC deadline timer + * is available (x86-specific). */ + __u32 apic_khz; +} __attribute__((packed)); + +/** + * Invoke a hypervisor without additional arguments. + * @param num Hypercall number. + * + * @return Result of the hypercall, semantic depends on the invoked service. + */ +static inline __u32 jailhouse_call(__u32 num) +{ + __u32 result; + + asm volatile(JAILHOUSE_CALL_CODE + : JAILHOUSE_CALL_RESULT + : JAILHOUSE_USE_VMCALL, JAILHOUSE_CALL_NUM + : "memory"); + return result; +} + +/** + * Invoke a hypervisor with one argument. + * @param num Hypercall number. + * @param arg1 First argument. + * + * @return Result of the hypercall, semantic depends on the invoked service. + */ +static inline __u32 jailhouse_call_arg1(__u32 num, unsigned long arg1) +{ + __u32 result; + + asm volatile(JAILHOUSE_CALL_CODE + : JAILHOUSE_CALL_RESULT + : JAILHOUSE_USE_VMCALL, + JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1 + : "memory"); + return result; +} + +/** + * Invoke a hypervisor with two arguments. + * @param num Hypercall number. + * @param arg1 First argument. + * @param arg2 Second argument. + * + * @return Result of the hypercall, semantic depends on the invoked service. + */ +static inline __u32 jailhouse_call_arg2(__u32 num, unsigned long arg1, + unsigned long arg2) +{ + __u32 result; + + asm volatile(JAILHOUSE_CALL_CODE + : JAILHOUSE_CALL_RESULT + : JAILHOUSE_USE_VMCALL, + JAILHOUSE_CALL_NUM, JAILHOUSE_CALL_ARG1, JAILHOUSE_CALL_ARG2 + : "memory"); + return result; +} + +/** + * Send a message from the hypervisor to a cell via the communication region. + * @param comm_region Pointer to Communication Region. + * @param msg Message to be sent. + */ +static inline void +jailhouse_send_msg_to_cell(struct jailhouse_comm_region *comm_region, + __u32 msg) +{ + comm_region->reply_from_cell = JAILHOUSE_MSG_NONE; + /* ensure reply was cleared before sending new message */ + asm volatile("mfence" : : : "memory"); + comm_region->msg_to_cell = msg; +} + +/** + * Send a reply message from a cell to the hypervisor via the communication + * region. + * @param comm_region Pointer to Communication Region. + * @param reply Reply to be sent. + */ +static inline void +jailhouse_send_reply_from_cell(struct jailhouse_comm_region *comm_region, + __u32 reply) +{ + comm_region->msg_to_cell = JAILHOUSE_MSG_NONE; + /* ensure message was cleared before sending reply */ + asm volatile("mfence" : : : "memory"); + comm_region->reply_from_cell = reply; +} + +/** @} **/ diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h new file mode 100644 index 0000000000000000000000000000000000000000..92b22a9ef1f7028b434ef509f85bf613f3017c7b --- /dev/null +++ b/include/jailhouse/cell-config.h @@ -0,0 +1,445 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_CELL_CONFIG_H +#define _JAILHOUSE_CELL_CONFIG_H + +#include +#include + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) +#endif + +/* + * Incremented on any layout or semantic change of system or cell config. + * Also update formats and HEADER_REVISION in pyjailhouse/config_parser.py. + */ +#define JAILHOUSE_CONFIG_REVISION 13 + +#define JAILHOUSE_CELL_NAME_MAXLEN 31 + +#define JAILHOUSE_CELL_PASSIVE_COMMREG 0x00000001 +#define JAILHOUSE_CELL_TEST_DEVICE 0x00000002 +#define JAILHOUSE_CELL_AARCH32 0x00000004 + +/* + * The flag JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED allows inmates to invoke + * the dbg putc hypercall. + * + * If JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE is set, inmates should use the + * virtual console. This flag implies JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED. + */ +#define JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED 0x40000000 +#define JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE 0x80000000 + +#define CELL_FLAGS_VIRTUAL_CONSOLE_ACTIVE(flags) \ + !!((flags) & JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE) +#define CELL_FLAGS_VIRTUAL_CONSOLE_PERMITTED(flags) \ + !!((flags) & JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED) + +#define JAILHOUSE_CELL_DESC_SIGNATURE "JHCELL" + +/** + * The jailhouse cell configuration. + * + * @note Keep Config._HEADER_FORMAT in jailhouse-cell-linux in sync with this + * structure. + */ +struct jailhouse_cell_desc { + char signature[6]; + __u16 revision; + + char name[JAILHOUSE_CELL_NAME_MAXLEN+1]; + __u32 id; /* set by the driver */ + __u32 flags; + + __u32 cpu_set_size; + __u32 num_memory_regions; + __u32 num_cache_regions; + __u32 num_irqchips; + __u32 num_pio_regions; + __u32 num_pci_devices; + __u32 num_pci_caps; + __u32 num_stream_ids; + + __u32 vpci_irq_base; + + __u64 cpu_reset_address; + __u64 msg_reply_timeout; + + __u32 use_virt_cpuid; + + struct jailhouse_console console; +} __attribute__((packed)); + +#define JAILHOUSE_MEM_READ 0x0001 +#define JAILHOUSE_MEM_WRITE 0x0002 +#define JAILHOUSE_MEM_EXECUTE 0x0004 +#define JAILHOUSE_MEM_DMA 0x0008 +#define JAILHOUSE_MEM_IO 0x0010 +#define JAILHOUSE_MEM_COMM_REGION 0x0020 +#define JAILHOUSE_MEM_LOADABLE 0x0040 +#define JAILHOUSE_MEM_ROOTSHARED 0x0080 +#define JAILHOUSE_MEM_NO_HUGEPAGES 0x0100 +#define JAILHOUSE_MEM_IO_UNALIGNED 0x8000 +#define JAILHOUSE_MEM_IO_WIDTH_SHIFT 16 /* uses bits 16..19 */ +#define JAILHOUSE_MEM_IO_8 (1 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) +#define JAILHOUSE_MEM_IO_16 (2 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) +#define JAILHOUSE_MEM_IO_32 (4 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) +#define JAILHOUSE_MEM_IO_64 (8 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) + +struct jailhouse_memory { + __u64 phys_start; + __u64 virt_start; + __u64 size; + __u64 flags; +} __attribute__((packed)); + +#define JAILHOUSE_SHMEM_NET_REGIONS(start, dev_id) \ + { \ + .phys_start = start, \ + .virt_start = start, \ + .size = 0x1000, \ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, \ + }, \ + { 0 }, \ + { \ + .phys_start = (start) + 0x1000, \ + .virt_start = (start) + 0x1000, \ + .size = 0x7f000, \ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | \ + ((dev_id == 0) ? JAILHOUSE_MEM_WRITE : 0), \ + }, \ + { \ + .phys_start = (start) + 0x80000, \ + .virt_start = (start) + 0x80000, \ + .size = 0x7f000, \ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED | \ + ((dev_id == 1) ? JAILHOUSE_MEM_WRITE : 0), \ + } + +#define JAILHOUSE_MEMORY_IS_SUBPAGE(mem) \ + ((mem)->virt_start & PAGE_OFFS_MASK || (mem)->size & PAGE_OFFS_MASK) + +#define JAILHOUSE_CACHE_L3_CODE 0x01 +#define JAILHOUSE_CACHE_L3_DATA 0x02 +#define JAILHOUSE_CACHE_L3 (JAILHOUSE_CACHE_L3_CODE | \ + JAILHOUSE_CACHE_L3_DATA) + +#define JAILHOUSE_CACHE_ROOTSHARED 0x0001 + +struct jailhouse_cache { + __u32 start; + __u32 size; + __u8 type; + __u8 padding; + __u16 flags; +} __attribute__((packed)); + +struct jailhouse_irqchip { + __u64 address; + __u32 id; + __u32 pin_base; + __u32 pin_bitmap[4]; +} __attribute__((packed)); + +#define JAILHOUSE_PCI_TYPE_DEVICE 0x01 +#define JAILHOUSE_PCI_TYPE_BRIDGE 0x02 +#define JAILHOUSE_PCI_TYPE_IVSHMEM 0x03 + +#define JAILHOUSE_SHMEM_PROTO_UNDEFINED 0x0000 +#define JAILHOUSE_SHMEM_PROTO_VETH 0x0001 +#define JAILHOUSE_SHMEM_PROTO_CUSTOM 0x4000 /* 0x4000..0x7fff */ +#define JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT 0x8000 /* 0x8000..0xbfff */ +#define JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK 0xc000 /* 0xc000..0xffff */ + +#define VIRTIO_DEV_NET 1 +#define VIRTIO_DEV_BLOCK 2 +#define VIRTIO_DEV_CONSOLE 3 + +struct jailhouse_pci_device { + __u8 type; + __u8 iommu; + __u16 domain; + __u16 bdf; + __u32 bar_mask[6]; + __u16 caps_start; + __u16 num_caps; + __u8 num_msi_vectors; + __u8 msi_64bits:1; + __u8 msi_maskable:1; + __u16 num_msix_vectors; + __u16 msix_region_size; + __u64 msix_address; + /** First memory region index of shared memory device. */ + __u32 shmem_regions_start; + /** ID of shared memory device (0..shmem_peers-1). */ + __u8 shmem_dev_id; + /** Maximum number of peers connected via this shared memory device. */ + __u8 shmem_peers; + /** PCI subclass and interface ID of shared memory device. */ + __u16 shmem_protocol; +} __attribute__((packed)); + +#define JAILHOUSE_IVSHMEM_BAR_MASK_INTX \ + { \ + 0xfffff000, 0x00000000, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000000, \ + } + +#define JAILHOUSE_IVSHMEM_BAR_MASK_MSIX \ + { \ + 0xfffff000, 0xfffff000, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000000, \ + } + +#define JAILHOUSE_IVSHMEM_BAR_MASK_INTX_64K \ + { \ + 0xffff0000, 0x00000000, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000000, \ + } + +#define JAILHOUSE_IVSHMEM_BAR_MASK_MSIX_64K \ + { \ + 0xffff0000, 0xffff0000, 0x00000000, \ + 0x00000000, 0x00000000, 0x00000000, \ + } + +#define JAILHOUSE_PCI_EXT_CAP 0x8000 + +#define JAILHOUSE_PCICAPS_WRITE 0x0001 + +struct jailhouse_pci_capability { + __u16 id; + __u16 start; + __u16 len; + __u16 flags; +} __attribute__((packed)); + +#define JAILHOUSE_APIC_MODE_AUTO 0 +#define JAILHOUSE_APIC_MODE_XAPIC 1 +#define JAILHOUSE_APIC_MODE_X2APIC 2 + +#define JAILHOUSE_MAX_IOMMU_UNITS 8 + +#define JAILHOUSE_IOMMU_AMD 1 +#define JAILHOUSE_IOMMU_INTEL 2 +#define JAILHOUSE_IOMMU_SMMUV3 3 +#define JAILHOUSE_IOMMU_PVU 4 +#define JAILHOUSE_IOMMU_ARM_MMU500 5 + +struct jailhouse_iommu { + __u32 type; + __u64 base; + __u32 size; + + union { + struct { + __u16 bdf; + __u8 base_cap; + __u8 msi_cap; + __u32 features; + } __attribute__((packed)) amd; + + struct { + __u64 tlb_base; + __u32 tlb_size; + } __attribute__((packed)) tipvu; + }; +} __attribute__((packed)); + +union jailhouse_stream_id { + __u32 id; + struct { + /* Note: both mask_out and id are only 15 bits wide. */ + __u16 id; + /* Mask out irrelevant bits in id: + * if mask_out[i] == 1, then id[i] is ignored. + */ + __u16 mask_out; + } __attribute__((packed)) mmu500; +} __attribute__((packed)); + +struct jailhouse_pio { + __u16 base; + __u16 length; +} __attribute__((packed)); + +#define PIO_RANGE(__base, __length) \ + { \ + .base = __base, \ + .length = __length, \ + } + +#define JAILHOUSE_SYSTEM_SIGNATURE "JHSYST" + +/* + * The flag JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE allows the root cell to read + * from the virtual console. + */ +#define JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE 0x0001 + +#define SYS_FLAGS_VIRTUAL_DEBUG_CONSOLE(flags) \ + !!((flags) & JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE) + +/** + * General descriptor of the system. + */ +struct jailhouse_system { + char signature[6]; + __u16 revision; + __u32 flags; + + /** Jailhouse's location in memory */ + struct jailhouse_memory hypervisor_memory; + struct jailhouse_console debug_console; + struct { + __u64 pci_mmconfig_base; + __u8 pci_mmconfig_end_bus; + __u8 pci_is_virtual; + __u16 pci_domain; + struct jailhouse_iommu iommu_units[JAILHOUSE_MAX_IOMMU_UNITS]; + union { + struct { + __u16 pm_timer_address; + __u8 apic_mode; + __u8 padding; + __u32 vtd_interrupt_limit; + __u32 tsc_khz; + __u32 apic_khz; + } __attribute__((packed)) x86; + struct { + u8 maintenance_irq; + u8 gic_version; + u8 padding[2]; + u64 gicd_base; + u64 gicc_base; + u64 gich_base; + u64 gicv_base; + u64 gicr_base; + } __attribute__((packed)) arm; + } __attribute__((packed)); + } __attribute__((packed)) platform_info; + struct jailhouse_cell_desc root_cell; +} __attribute__((packed)); + +static inline __u32 +jailhouse_cell_config_size(struct jailhouse_cell_desc *cell) +{ + return sizeof(struct jailhouse_cell_desc) + + cell->cpu_set_size + + cell->num_memory_regions * sizeof(struct jailhouse_memory) + + cell->num_cache_regions * sizeof(struct jailhouse_cache) + + cell->num_irqchips * sizeof(struct jailhouse_irqchip) + + cell->num_pio_regions * sizeof(struct jailhouse_pio) + + cell->num_pci_devices * sizeof(struct jailhouse_pci_device) + + cell->num_pci_caps * sizeof(struct jailhouse_pci_capability) + + cell->num_stream_ids * sizeof(__u32); +} + +static inline __u32 +jailhouse_system_config_size(struct jailhouse_system *system) +{ + return sizeof(*system) - sizeof(system->root_cell) + + jailhouse_cell_config_size(&system->root_cell); +} + +static inline const unsigned long * +jailhouse_cell_cpu_set(const struct jailhouse_cell_desc *cell) +{ + return (const unsigned long *)((const void *)cell + + sizeof(struct jailhouse_cell_desc)); +} + +static inline const struct jailhouse_memory * +jailhouse_cell_mem_regions(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_memory *) + ((void *)jailhouse_cell_cpu_set(cell) + cell->cpu_set_size); +} + +static inline const struct jailhouse_cache * +jailhouse_cell_cache_regions(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_cache *) + ((void *)jailhouse_cell_mem_regions(cell) + + cell->num_memory_regions * sizeof(struct jailhouse_memory)); +} + +static inline const struct jailhouse_irqchip * +jailhouse_cell_irqchips(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_irqchip *) + ((void *)jailhouse_cell_cache_regions(cell) + + cell->num_cache_regions * sizeof(struct jailhouse_cache)); +} + +static inline const struct jailhouse_pio * +jailhouse_cell_pio(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_pio *) + ((void *)jailhouse_cell_irqchips(cell) + + cell->num_irqchips * sizeof(struct jailhouse_irqchip)); +} + +static inline const struct jailhouse_pci_device * +jailhouse_cell_pci_devices(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_pci_device *) + ((void *)jailhouse_cell_pio(cell) + + cell->num_pio_regions * sizeof(struct jailhouse_pio)); +} + +static inline const struct jailhouse_pci_capability * +jailhouse_cell_pci_caps(const struct jailhouse_cell_desc *cell) +{ + return (const struct jailhouse_pci_capability *) + ((void *)jailhouse_cell_pci_devices(cell) + + cell->num_pci_devices * sizeof(struct jailhouse_pci_device)); +} + +static inline const union jailhouse_stream_id * +jailhouse_cell_stream_ids(const struct jailhouse_cell_desc *cell) +{ + return (const union jailhouse_stream_id *) + ((void *)jailhouse_cell_pci_caps(cell) + + cell->num_pci_caps * sizeof(struct jailhouse_pci_capability)); +} + +#endif /* !_JAILHOUSE_CELL_CONFIG_H */ diff --git a/include/jailhouse/console.h b/include/jailhouse/console.h new file mode 100644 index 0000000000000000000000000000000000000000..e7c934a56fe22ac11e6c8507ce084888327875e5 --- /dev/null +++ b/include/jailhouse/console.h @@ -0,0 +1,100 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_CONSOLE_H +#define _JAILHOUSE_CONSOLE_H + +/* Those definitions are used for the type in struct jailhouse_console */ +#define JAILHOUSE_CON_TYPE_NONE 0x0000 +#define JAILHOUSE_CON_TYPE_EFIFB 0x0001 +#define JAILHOUSE_CON_TYPE_8250 0x0002 +#define JAILHOUSE_CON_TYPE_PL011 0x0003 +#define JAILHOUSE_CON_TYPE_XUARTPS 0x0004 +#define JAILHOUSE_CON_TYPE_MVEBU 0x0005 +#define JAILHOUSE_CON_TYPE_HSCIF 0x0006 +#define JAILHOUSE_CON_TYPE_SCIFA 0x0007 +#define JAILHOUSE_CON_TYPE_IMX 0x0008 +#define JAILHOUSE_CON_TYPE_IMX_LPUART 0x0009 +#define JAILHOUSE_CON_TYPE_SCIF 0x000a + +/* Flags: bit 0 is used to select PIO (cleared) or MMIO (set) access */ +#define JAILHOUSE_CON_ACCESS_PIO 0x0000 +#define JAILHOUSE_CON_ACCESS_MMIO 0x0001 + +#define CON_IS_MMIO(flags) !!((flags) & JAILHOUSE_CON_ACCESS_MMIO) + +/* + * Flags: bit 1 is used to select 1 (cleared) or 4-bytes (set) register distance. + * 1 byte implied 8-bit access, 4 bytes 32-bit access. + */ +#define JAILHOUSE_CON_REGDIST_1 0x0000 +#define JAILHOUSE_CON_REGDIST_4 0x0002 + +#define CON_USES_REGDIST_1(flags) (((flags) & JAILHOUSE_CON_REGDIST_4) == 0) + +/* Flags: bit 2 is used to select framebuffer format */ +#define JAILHOUSE_CON_FB_1024x768 0x0000 +#define JAILHOUSE_CON_FB_1920x1080 0x0004 + +#define FB_IS_1920x1080(flags) !!((flags) & JAILHOUSE_CON_FB_1920x1080) + +/* Bits 3-11: Reserved */ + +/* Bit 12 is used to indicate to clear instead of to set the clock gate */ +#define JAILHOUSE_CON_INVERTED_GATE 0x1000 + +#define CON_HAS_INVERTED_GATE(flags) !!((flags) & JAILHOUSE_CON_INVERTED_GATE) + +/* Bit 13 is used to apply (set) or skip (clear) a MDR quirk on the console */ +#define JAILHOUSE_CON_MDR_QUIRK 0x2000 + +#define CON_HAS_MDR_QUIRK(flags) !!((flags) & JAILHOUSE_CON_MDR_QUIRK) + +/* Bits 14-15: Reserved */ + +struct jailhouse_console { + __u64 address; + __u32 size; + __u16 type; + __u16 flags; + __u32 divider; + __u32 gate_nr; + __u64 clock_reg; +} __attribute__((packed)); + +#endif /* !_JAILHOUSE_CONSOLE_H */ diff --git a/include/jailhouse/hypercall.h b/include/jailhouse/hypercall.h new file mode 100644 index 0000000000000000000000000000000000000000..07574d3d9c7111f76414e1d51a07a73a53b616b4 --- /dev/null +++ b/include/jailhouse/hypercall.h @@ -0,0 +1,128 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_HYPERCALL_H +#define _JAILHOUSE_HYPERCALL_H + +#include + +#define JAILHOUSE_HC_DISABLE 0 +#define JAILHOUSE_HC_CELL_CREATE 1 +#define JAILHOUSE_HC_CELL_START 2 +#define JAILHOUSE_HC_CELL_SET_LOADABLE 3 +#define JAILHOUSE_HC_CELL_DESTROY 4 +#define JAILHOUSE_HC_HYPERVISOR_GET_INFO 5 +#define JAILHOUSE_HC_CELL_GET_STATE 6 +#define JAILHOUSE_HC_CPU_GET_INFO 7 +#define JAILHOUSE_HC_DEBUG_CONSOLE_PUTC 8 + +/* Hypervisor information type */ +#define JAILHOUSE_INFO_MEM_POOL_SIZE 0 +#define JAILHOUSE_INFO_MEM_POOL_USED 1 +#define JAILHOUSE_INFO_REMAP_POOL_SIZE 2 +#define JAILHOUSE_INFO_REMAP_POOL_USED 3 +#define JAILHOUSE_INFO_NUM_CELLS 4 + +/* Hypervisor information type */ +#define JAILHOUSE_CPU_INFO_STATE 0 +#define JAILHOUSE_CPU_INFO_STAT_BASE 1000 + +/* CPU state */ +#define JAILHOUSE_CPU_RUNNING 0 +#define JAILHOUSE_CPU_FAILED 2 /* terminal state */ + +/* CPU statistics */ +#define JAILHOUSE_CPU_STAT_VMEXITS_TOTAL 0 +#define JAILHOUSE_CPU_STAT_VMEXITS_MMIO 1 +#define JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT 2 +#define JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL 3 +#define JAILHOUSE_GENERIC_CPU_STATS 4 + +#define JAILHOUSE_MSG_NONE 0 + +/* messages to cell */ +#define JAILHOUSE_MSG_SHUTDOWN_REQUEST 1 +#define JAILHOUSE_MSG_RECONFIG_COMPLETED 2 + +/* replies from cell */ +#define JAILHOUSE_MSG_UNKNOWN 1 +#define JAILHOUSE_MSG_REQUEST_DENIED 2 +#define JAILHOUSE_MSG_REQUEST_APPROVED 3 +#define JAILHOUSE_MSG_RECEIVED 4 + +/* cell state, initialized by hypervisor, updated by cell */ +#define JAILHOUSE_CELL_RUNNING 0 +#define JAILHOUSE_CELL_RUNNING_LOCKED 1 +#define JAILHOUSE_CELL_SHUT_DOWN 2 /* terminal state */ +#define JAILHOUSE_CELL_FAILED 3 /* terminal state */ +#define JAILHOUSE_CELL_FAILED_COMM_REV 4 /* terminal state */ + +/* indicates if inmate may use the Debug Console putc hypercall */ +#define JAILHOUSE_COMM_FLAG_DBG_PUTC_PERMITTED 0x0001 +/* indicates if inmate shall use Debug Console putc as output channel */ +#define JAILHOUSE_COMM_FLAG_DBG_PUTC_ACTIVE 0x0002 + +#define JAILHOUSE_COMM_HAS_DBG_PUTC_PERMITTED(flags) \ + !!((flags) & JAILHOUSE_COMM_FLAG_DBG_PUTC_PERMITTED) +#define JAILHOUSE_COMM_HAS_DBG_PUTC_ACTIVE(flags) \ + !!((flags) & JAILHOUSE_COMM_FLAG_DBG_PUTC_ACTIVE) + +#define COMM_REGION_ABI_REVISION 2 +#define COMM_REGION_MAGIC "JHCOMM" + +#define COMM_REGION_GENERIC_HEADER \ + /** Communication region magic JHCOMM */ \ + char signature[6]; \ + /** Communication region ABI revision */ \ + __u16 revision; \ + /** Cell state, initialized by hypervisor, updated by cell. */ \ + volatile __u32 cell_state; \ + /** Message code sent from hypervisor to cell. */ \ + volatile __u32 msg_to_cell; \ + /** Reply code sent from cell to hypervisor. */ \ + volatile __u32 reply_from_cell; \ + /** Holds static flags, see JAILHOUSE_COMM_FLAG_*. */ \ + __u32 flags; \ + /** Debug console that may be accessed by the inmate. */ \ + struct jailhouse_console console; \ + /** Base address of PCI memory mapped config. */ \ + __u64 pci_mmconfig_base; + +#include + +#endif /* !_JAILHOUSE_HYPERCALL_H */ diff --git a/include/jailhouse/pci_defs.h b/include/jailhouse/pci_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..63c61daf588cf2b37c4e41cf39835e7753364689 --- /dev/null +++ b/include/jailhouse/pci_defs.h @@ -0,0 +1,81 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */ +#define PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ + +#define PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ +#define PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel Capability */ +#define PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ +#define PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ +#define PCI_EXT_CAP_ID_RCLD 0x05 /* Root Complex Link Declaration */ +#define PCI_EXT_CAP_ID_RCILC 0x06 /* Root Complex Internal Link Control */ +#define PCI_EXT_CAP_ID_RCEC 0x07 /* Root Complex Event Collector */ +#define PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function VC Capability */ +#define PCI_EXT_CAP_ID_VC9 0x09 /* same as _VC */ +#define PCI_EXT_CAP_ID_RCRB 0x0A /* Root Complex RB? */ +#define PCI_EXT_CAP_ID_VNDR 0x0B /* Vendor-Specific */ +#define PCI_EXT_CAP_ID_CAC 0x0C /* Config Access - obsolete */ +#define PCI_EXT_CAP_ID_ACS 0x0D /* Access Control Services */ +#define PCI_EXT_CAP_ID_ARI 0x0E /* Alternate Routing ID */ +#define PCI_EXT_CAP_ID_ATS 0x0F /* Address Translation Services */ +#define PCI_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virtualization */ +#define PCI_EXT_CAP_ID_MRIOV 0x11 /* Multi Root I/O Virtualization */ +#define PCI_EXT_CAP_ID_MCAST 0x12 /* Multicast */ +#define PCI_EXT_CAP_ID_PRI 0x13 /* Page Request Interface */ +#define PCI_EXT_CAP_ID_AMD_XXX 0x14 /* Reserved for AMD */ +#define PCI_EXT_CAP_ID_REBAR 0x15 /* Resizable BAR */ +#define PCI_EXT_CAP_ID_DPA 0x16 /* Dynamic Power Allocation */ +#define PCI_EXT_CAP_ID_TPH 0x17 /* TPH Requester */ +#define PCI_EXT_CAP_ID_LTR 0x18 /* Latency Tolerance Reporting */ +#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */ +#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ +#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ +#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ +#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */ +#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ diff --git a/inmates/Makefile b/inmates/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b4d4366cb9d7c5dd29c0448dbdcf25f6b016b241 --- /dev/null +++ b/inmates/Makefile @@ -0,0 +1,49 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +-include $(GEN_CONFIG_MK) + +INMATES_LIB = $(src)/lib/$(SRCARCH) +export INMATES_LIB + +INCLUDES := -I$(INMATES_LIB) \ + -I$(src)/../include/arch/$(SRCARCH) \ + -I$(src)/lib/include \ + -I$(src)/../include + +LINUXINCLUDE := $(INCLUDES) +KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE +KBUILD_CFLAGS := -g -Os -Werror -Wall -Wstrict-prototypes -Wtype-limits \ + -Wmissing-declarations -Wmissing-prototypes \ + -fno-strict-aliasing -fomit-frame-pointer -fno-pic \ + -fno-common -fno-stack-protector -ffreestanding \ + -ffunction-sections \ + -D__LINUX_COMPILER_TYPES_H +ifneq ($(wildcard $(INC_CONFIG_H)),) +KBUILD_CFLAGS += -include $(INC_CONFIG_H) +endif +ifeq ($(SRCARCH),arm) +KBUILD_CFLAGS += -march=armv7ve -msoft-float +KBUILD_AFLAGS += -march=armv7ve -msoft-float +endif + +OBJCOPYFLAGS := -O binary --remove-section=.note.gnu.property +# prior to 4.19 +LDFLAGS += --gc-sections -T +# since 4.19 +KBUILD_LDFLAGS += --gc-sections -T + +subdir-y := lib/$(SRCARCH) demos/$(SRCARCH) tests/$(SRCARCH) tools/$(SRCARCH) + +# demos, tests and tools depend on the library +$(obj)/demos/$(SRCARCH) $(obj)/tests/$(SRCARCH) $(obj)/tools/$(SRCARCH): \ + $(obj)/lib/$(SRCARCH) diff --git a/inmates/demos/arm/Makefile b/inmates/demos/arm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1c2549709a39fe4b5408e227845cf60c7291423 --- /dev/null +++ b/inmates/demos/arm/Makefile @@ -0,0 +1,21 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) ARM Limited, 2014 +# +# Authors: +# Jean-Philippe Brucker +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := gic-demo.bin uart-demo.bin ivshmem-demo.bin + +gic-demo-y := gic-demo.o +uart-demo-y := uart-demo.o +ivshmem-demo-y := ../ivshmem-demo.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/demos/arm/gic-demo.c b/inmates/demos/arm/gic-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..b01026156dd8294b5a23414362ed061b0ce503e3 --- /dev/null +++ b/inmates/demos/arm/gic-demo.c @@ -0,0 +1,75 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2014-2017 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define BEATS_PER_SEC 10 + +static u64 ticks_per_beat; +static volatile u64 expected_ticks; + +/* + * Enables blinking LED + * Banana Pi: register 0x1c2090c, pin 24 + * Orange Pi Zero: register 0x1c20810, pin 17 + */ +static void *led_reg; +static unsigned int led_pin; + +static void handle_IRQ(unsigned int irqn) +{ + static u64 min_delta = ~0ULL, max_delta = 0; + u64 delta; + + if (irqn != TIMER_IRQ) + return; + + delta = timer_get_ticks() - expected_ticks; + if (delta < min_delta) + min_delta = delta; + if (delta > max_delta) + max_delta = delta; + + printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns\n", + (long)timer_ticks_to_ns(delta), + (long)timer_ticks_to_ns(min_delta), + (long)timer_ticks_to_ns(max_delta)); + + if (led_reg) + mmio_write32(led_reg, mmio_read32(led_reg) ^ (1 << led_pin)); + + expected_ticks = timer_get_ticks() + ticks_per_beat; + timer_start(ticks_per_beat); +} + +void inmate_main(void) +{ + led_reg = (void *)(unsigned long)cmdline_parse_int("led-reg", 0); + if (led_reg) { + map_range(led_reg, 4, MAP_UNCACHED); + led_pin = cmdline_parse_int("led-pin", 0); + } + + printk("Initializing the GIC...\n"); + irq_init(handle_IRQ); + irq_enable(TIMER_IRQ); + + printk("Initializing the timer...\n"); + ticks_per_beat = timer_get_frequency() / BEATS_PER_SEC; + expected_ticks = timer_get_ticks() + ticks_per_beat; + timer_start(ticks_per_beat); + + halt(); +} diff --git a/inmates/demos/arm/uart-demo.c b/inmates/demos/arm/uart-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..f310fb734b3629f0c38b682c96bcd7b96b57e8ff --- /dev/null +++ b/inmates/demos/arm/uart-demo.c @@ -0,0 +1,27 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +void inmate_main(void) +{ + unsigned int i = 0, j; + /* + * The cell config can set up a mapping to access UARTx instead of UART0 + */ + while(++i) { + for (j = 0; j < 100000000; j++); + printk("Hello %d from cell!\n", i); + } + + /* lr should be 0, so a return will go back to the reset vector */ +} diff --git a/inmates/demos/arm64/Makefile b/inmates/demos/arm64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2af4f0ca454605221b1b9cb7e87563bc91e4da12 --- /dev/null +++ b/inmates/demos/arm64/Makefile @@ -0,0 +1,21 @@ +# +# Jailhouse AArch64 support +# +# Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH +# +# Authors: +# Antonios Motakis +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := gic-demo.bin uart-demo.bin ivshmem-demo.bin + +gic-demo-y := ../arm/gic-demo.o +uart-demo-y := ../arm/uart-demo.o +ivshmem-demo-y := ../ivshmem-demo.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/demos/ivshmem-demo.c b/inmates/demos/ivshmem-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..29eab4122471da4365ef71aa4be60c5ee1441833 --- /dev/null +++ b/inmates/demos/ivshmem-demo.c @@ -0,0 +1,229 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Henning Schild + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include + +#define VENDORID 0x110a +#define DEVICEID 0x4106 + +#define BAR_BASE 0xff000000 + +#define IVSHMEM_CFG_STATE_TAB_SZ 0x04 +#define IVSHMEM_CFG_RW_SECTION_SZ 0x08 +#define IVSHMEM_CFG_OUT_SECTION_SZ 0x10 +#define IVSHMEM_CFG_ADDRESS 0x18 + +#define JAILHOUSE_SHMEM_PROTO_UNDEFINED 0x0000 + +#if defined(__x86_64__) +#define DEFAULT_IRQ_BASE 32 +#elif defined(__arm__) || defined(__aarch64__) +#define DEFAULT_IRQ_BASE (comm_region->vpci_irq_base + 32) +#else +#error Not implemented! +#endif + +#define MAX_VECTORS 4 + +static int irq_counter[MAX_VECTORS]; +static struct ivshmem_dev_data dev; +static unsigned int irq_base, vectors, target; + +struct ivshm_regs { + u32 id; + u32 max_peers; + u32 int_control; + u32 doorbell; + u32 state; +}; + +struct ivshmem_dev_data { + u16 bdf; + struct ivshm_regs *registers; + u32 *state_table; + u32 state_table_sz; + u32 *rw_section; + u64 rw_section_sz; + u32 *in_sections; + u32 *out_section; + u64 out_section_sz; + u32 *msix_table; + u32 id; + int msix_cap; +}; + +static u64 pci_cfg_read64(u16 bdf, unsigned int addr) +{ + return pci_read_config(bdf, addr, 4) | + ((u64)pci_read_config(bdf, addr + 4, 4) << 32); +} + +static void print_shmem(struct ivshmem_dev_data *d) +{ + printk("state[0] = %d\n", d->state_table[0]); + printk("state[1] = %d\n", d->state_table[1]); + printk("state[2] = %d\n", d->state_table[2]); + printk("rw[0] = %d\n", d->rw_section[0]); + printk("rw[1] = %d\n", d->rw_section[1]); + printk("rw[2] = %d\n", d->rw_section[2]); + printk("in@0x0000 = %d\n", d->in_sections[0/4]); + printk("in@0x2000 = %d\n", d->in_sections[0x2000/4]); + printk("in@0x4000 = %d\n", d->in_sections[0x4000/4]); +} + +static void irq_handler(unsigned int irq) +{ + unsigned int n; + u32 value; + + if (irq < irq_base || irq >= irq_base + vectors) + return; + + n = irq - irq_base; + irq_counter[n]++; + if (dev.msix_cap > 0) + value = irq_counter[dev.id]; + else + value = irq_counter[0]; + dev.rw_section[dev.id] = value; + dev.out_section[0] = value * 10; + printk("\nIVSHMEM: got interrupt %d (#%d)\n", n, irq_counter[n]); + print_shmem(&dev); +} + +static void init_device(struct ivshmem_dev_data *d) +{ + unsigned long baseaddr, addr, size; + int vndr_cap, n; + u32 max_peers; + + vndr_cap = pci_find_cap(d->bdf, PCI_CAP_VENDOR); + if (vndr_cap < 0) { + printk("IVSHMEM ERROR: missing vendor capability\n"); + stop(); + } + + d->registers = (struct ivshm_regs *)BAR_BASE; + pci_write_config(d->bdf, PCI_CFG_BAR, (unsigned long)d->registers, 4); + printk("IVSHMEM: bar0 is at %p\n", d->registers); + + d->msix_table = (u32 *)(BAR_BASE + PAGE_SIZE); + pci_write_config(d->bdf, PCI_CFG_BAR + 4, + (unsigned long)d->msix_table, 4); + printk("IVSHMEM: bar1 is at %p\n", d->msix_table); + + pci_write_config(d->bdf, PCI_CFG_COMMAND, + (PCI_CMD_MEM | PCI_CMD_MASTER), 2); + + map_range((void *)BAR_BASE, 2 * PAGE_SIZE, MAP_UNCACHED); + + d->id = mmio_read32(&d->registers->id); + printk("IVSHMEM: ID is %d\n", d->id); + + max_peers = mmio_read32(&d->registers->max_peers); + printk("IVSHMEM: max. peers is %d\n", max_peers); + + target = d->id < max_peers ? (d->id + 1) : 0; + target = cmdline_parse_int("target", target); + + d->state_table_sz = + pci_read_config(d->bdf, vndr_cap + IVSHMEM_CFG_STATE_TAB_SZ, 4); + d->rw_section_sz = + pci_cfg_read64(d->bdf, vndr_cap + IVSHMEM_CFG_RW_SECTION_SZ); + d->out_section_sz = + pci_cfg_read64(d->bdf, vndr_cap + IVSHMEM_CFG_OUT_SECTION_SZ); + baseaddr = pci_cfg_read64(d->bdf, vndr_cap + IVSHMEM_CFG_ADDRESS); + + addr = baseaddr; + d->state_table = (u32 *)addr; + + addr += d->state_table_sz; + d->rw_section = (u32 *)addr; + + addr += d->rw_section_sz; + d->in_sections = (u32 *)addr; + + addr += d->id * d->out_section_sz; + d->out_section = (u32 *)addr; + + printk("IVSHMEM: state table is at %p\n", d->state_table); + printk("IVSHMEM: R/W section is at %p\n", d->rw_section); + printk("IVSHMEM: input sections start at %p\n", d->in_sections); + printk("IVSHMEM: output section is at %p\n", d->out_section); + + size = d->state_table_sz + d->rw_section_sz + + max_peers * d->out_section_sz; + map_range((void *)baseaddr, size, MAP_CACHED); + + d->msix_cap = pci_find_cap(d->bdf, PCI_CAP_MSIX); + vectors = d->msix_cap > 0 ? MAX_VECTORS : 1; + for (n = 0; n < vectors; n++) { + if (d->msix_cap > 0) + pci_msix_set_vector(d->bdf, irq_base + n, n); + irq_enable(irq_base + n); + } +} + +static void send_irq(struct ivshmem_dev_data *d) +{ + u32 int_no = d->msix_cap > 0 ? (d->id + 1) : 0; + + disable_irqs(); + printk("\nIVSHMEM: sending IRQ %d to peer %d\n", int_no, target); + enable_irqs(); + mmio_write32(&d->registers->doorbell, int_no | (target << 16)); +} + +void inmate_main(void) +{ + unsigned int class_rev; + int bdf; + + irq_base = cmdline_parse_int("irq_base", DEFAULT_IRQ_BASE); + + irq_init(irq_handler); + pci_init(); + + bdf = pci_find_device(VENDORID, DEVICEID, 0); + if (bdf == -1) { + printk("IVSHMEM: No PCI devices found .. nothing to do.\n"); + stop(); + } + + printk("IVSHMEM: Found device at %02x:%02x.%x\n", + bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3); + class_rev = pci_read_config(bdf, 0x8, 4); + if (class_rev != (PCI_DEV_CLASS_OTHER << 24 | + JAILHOUSE_SHMEM_PROTO_UNDEFINED << 8)) { + printk("IVSHMEM: class/revision %08x, not supported\n", + class_rev); + stop(); + } + + dev.bdf = bdf; + init_device(&dev); + printk("IVSHMEM: initialized device\n"); + + mmio_write32(&dev.registers->int_control, 1); + + mmio_write32(&dev.registers->state, dev.id + 1); + dev.rw_section[dev.id] = 0; + dev.out_section[0] = 0; + print_shmem(&dev); + + enable_irqs(); + + while (1) { + delay_us(1000*1000); + send_irq(&dev); + } +} diff --git a/inmates/demos/x86/32-bit-demo.c b/inmates/demos/x86/32-bit-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..7e47d0e066e238ad49d6110e145200d9b6c46521 --- /dev/null +++ b/inmates/demos/x86/32-bit-demo.c @@ -0,0 +1,23 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * Use with tiny-demo config e.g. + */ + +#include + +#define IA32_EFER 0xc0000080 + +void inmate_main(void) +{ + printk("This runs in 32-bit mode (EFER: %llx)\n", read_msr(IA32_EFER)); +} diff --git a/inmates/demos/x86/Makefile b/inmates/demos/x86/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..47b79869a2eae433fe2ce7d2344c41879c37db69 --- /dev/null +++ b/inmates/demos/x86/Makefile @@ -0,0 +1,31 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := tiny-demo.bin apic-demo.bin ioapic-demo.bin 32-bit-demo.bin \ + pci-demo.bin e1000-demo.bin ivshmem-demo.bin smp-demo.bin \ + cache-timings.bin + +tiny-demo-y := tiny-demo.o +apic-demo-y := apic-demo.o +ioapic-demo-y := ioapic-demo.o +pci-demo-y := pci-demo.o +e1000-demo-y := e1000-demo.o +ivshmem-demo-y := ../ivshmem-demo.o +smp-demo-y := smp-demo.o +cache-timings-y := cache-timings.o + +$(eval $(call DECLARE_32_BIT,32-bit-demo)) +32-bit-demo-y := 32-bit-demo.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/demos/x86/apic-demo.c b/inmates/demos/x86/apic-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..83ab77fd249490e9c50991a6dcbf33a85d610396 --- /dev/null +++ b/inmates/demos/x86/apic-demo.c @@ -0,0 +1,179 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define MSR_SMI_COUNT 0x34 + +#define POLLUTE_CACHE_SIZE (512 * 1024) + +#define APIC_TIMER_VECTOR 32 + +/* + * Enables blinking LED + * SIMATIC IPC127E: register 0xd0c506a8, pin 0 + */ +static void *led_reg; +static unsigned int led_pin; + +static unsigned long expected_time; +static unsigned long min = -1, max; +static bool has_smi_count; +static u32 initial_smis; + +static const unsigned int smi_count_models[] = { + 0x37, 0x4a, 0x4d, 0x5a, 0x5d, 0x5c, 0x7a, /* Silvermont */ + 0x1a, 0x1e, 0x1f, 0x2e, /* Nehalem */ + 0x2a, 0x2d, /* Sandy Bridge */ + 0x57, 0x85, /* Xeon Phi */ + 0 +}; + +static bool cpu_has_smi_count(void) +{ + unsigned int family, model, smi_count_model, n = 0; + unsigned long eax; + + asm volatile("cpuid" : "=a" (eax) : "a" (1) + : "rbx", "rcx", "rdx", "memory"); + family = ((eax & 0xf00) >> 8) | ((eax & 0xff00000) >> 16); + model = ((eax & 0xf0) >> 4) | ((eax & 0xf0000) >> 12); + if (family == 0x6) { + do { + smi_count_model = smi_count_models[n++]; + if (model == smi_count_model) + return true; + } while (smi_count_model != 0); + } + return false; +} + +static void irq_handler(unsigned int irq) +{ + unsigned long delta; + u32 smis; + + if (irq != APIC_TIMER_VECTOR) + return; + + delta = tsc_read_ns() - expected_time; + if (delta < min) + min = delta; + if (delta > max) + max = delta; + printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns", + delta, min, max); + if (has_smi_count) { + smis = (u32)read_msr(MSR_SMI_COUNT); + if (smis != initial_smis) + printk(", SMIs: %d", smis - initial_smis); + } + printk("\n"); + + if (led_reg) + mmio_write32(led_reg, mmio_read32(led_reg) ^ (1 << led_pin)); + + expected_time += 100 * NS_PER_MSEC; + apic_timer_set(expected_time - tsc_read_ns()); +} + +static void init_apic(void) +{ + unsigned long apic_freq_khz; + + irq_init(irq_handler); + + apic_freq_khz = apic_timer_init(APIC_TIMER_VECTOR); + printk("Calibrated APIC frequency: %lu kHz\n", apic_freq_khz); + + expected_time = tsc_read_ns() + NS_PER_MSEC; + apic_timer_set(NS_PER_MSEC); + + asm volatile("sti"); +} + +static void pollute_cache(char *mem) +{ + unsigned long cpu_cache_line_size, ebx; + unsigned long n; + + asm volatile("cpuid" : "=b" (ebx) : "a" (1) + : "rcx", "rdx", "memory"); + cpu_cache_line_size = (ebx & 0xff00) >> 5; + + for (n = 0; n < POLLUTE_CACHE_SIZE; n += cpu_cache_line_size) + mem[n] ^= 0xAA; +} + +void inmate_main(void) +{ + bool allow_terminate = false; + bool terminate = false; + unsigned long tsc_freq; + bool cache_pollution; + char *mem; + + comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED; + + cache_pollution = cmdline_parse_bool("pollute-cache", false); + if (cache_pollution) { + mem = alloc(PAGE_SIZE, PAGE_SIZE); + printk("Cache pollution enabled\n"); + } + + has_smi_count = cpu_has_smi_count(); + if (has_smi_count) { + initial_smis = (u32)read_msr(MSR_SMI_COUNT); + printk("Initial number of SMIs: %d\n", initial_smis); + } + + tsc_freq = tsc_init(); + printk("Calibrated TSC frequency: %lu.%03lu kHz\n", tsc_freq / 1000, + tsc_freq % 1000); + + init_apic(); + + led_reg = (void *)(unsigned long)cmdline_parse_int("led-reg", 0); + led_pin = cmdline_parse_int("led-pin", 0); + + if (led_reg) + map_range(led_reg, 4, MAP_UNCACHED); + + while (!terminate) { + cpu_relax(); + + if (cache_pollution) + pollute_cache(mem); + + switch (comm_region->msg_to_cell) { + case JAILHOUSE_MSG_SHUTDOWN_REQUEST: + if (!allow_terminate) { + printk("Rejecting first shutdown request - " + "try again!\n"); + jailhouse_send_reply_from_cell(comm_region, + JAILHOUSE_MSG_REQUEST_DENIED); + allow_terminate = true; + } else + terminate = true; + break; + case JAILHOUSE_MSG_NONE: + break; + default: + jailhouse_send_reply_from_cell(comm_region, + JAILHOUSE_MSG_UNKNOWN); + break; + } + } + + printk("Stopped APIC demo\n"); + comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN; +} diff --git a/inmates/demos/x86/cache-timings-common.c b/inmates/demos/x86/cache-timings-common.c new file mode 100644 index 0000000000000000000000000000000000000000..0edf65e689538acf4efbf5e7d17d2c33a2acd57c --- /dev/null +++ b/inmates/demos/x86/cache-timings-common.c @@ -0,0 +1,95 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2020 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define ROUNDS (10 * 1000 * 1000) + +union tscval { + struct { + u32 lo; + u32 hi; + } __attribute__((packed)); + u64 val; +} __attribute__((packed)); + +static u32 victim; + +static inline void clflush(void *addr) +{ + asm volatile("clflush %0\t\n" + "mfence\t\n" + "lfence\t\n" : "+m" (*(volatile char *)addr)); +} + +#define MEASUREMENT_OVERHEAD "nop\t\n" +#define MEASUREMENT_COMMAND "mov (%%rbx), %%ebx\t\n" +#define DECLARE_MEASUREMENT(name, flush, meas) \ + static inline u64 measure_##name(u32 *victim) \ + { \ + union tscval before, after; \ + \ + if (flush) \ + clflush(victim); \ + asm volatile("mov %4, %%rbx\t\n" \ + "lfence\t\n" \ + "rdtsc\t\n" \ + "lfence\t\n" \ + \ + meas \ + \ + "mov %%eax, %%ebx\t\n" \ + "mov %%edx, %%ecx\t\n" \ + "lfence\t\n" \ + "rdtsc\t\n" \ + "lfence\t\n" \ + "mov %%ebx, %0\t\n" \ + "mov %%ecx, %1\t\n" \ + "mov %%eax, %2\t\n" \ + "mov %%edx, %3\t\n" \ + : "=m"(before.lo), "=m" (before.hi), \ + "=m" (after.lo), "=m" (after.hi) \ + : "m" (victim) \ + : "eax", "rbx", "ecx", "edx"); \ + return after.val - before.val; \ + } + +DECLARE_MEASUREMENT(overhead, false, MEASUREMENT_OVERHEAD) +DECLARE_MEASUREMENT(cached, false, MEASUREMENT_COMMAND) +DECLARE_MEASUREMENT(uncached, true, MEASUREMENT_COMMAND) + +static inline u64 avg_measurement(u64 (*meas)(u32*), u32 *victim, + unsigned int rounds, u64 overhead) +{ + u64 cycles = 0; + unsigned int i; + + for (i = 0; i < rounds; i++) + cycles += meas(victim) - overhead; + return cycles / rounds; +} + +void inmate_main(void) +{ + u64 cycles, overhead; + + printk("Measurement rounds: %u\n", ROUNDS); + printk("Determining measurement overhead...\n"); + overhead = avg_measurement(measure_overhead, &victim, ROUNDS, 0); + printk(" -> Average measurement overhead: %llu cycles\n", overhead); + + printk("Measuring uncached memory access...\n"); + cycles = avg_measurement(measure_uncached, &victim, ROUNDS, overhead); + printk(" -> Average uncached memory access: %llu cycles\n", cycles); + + printk("Measuring cached memory access...\n"); + cycles = avg_measurement(measure_cached, &victim, ROUNDS, overhead); + printk(" -> Average cached memory access: %llu cycles\n", cycles); +} diff --git a/inmates/demos/x86/cache-timings.c b/inmates/demos/x86/cache-timings.c new file mode 100644 index 0000000000000000000000000000000000000000..1acc3ee9a84ac36caee70ace5c9be44480a64041 --- /dev/null +++ b/inmates/demos/x86/cache-timings.c @@ -0,0 +1,15 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2020 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#include "cache-timings-common.c" diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..7db0ddb393d5406e0d82ef6fdc3de02f9ad4c4b2 --- /dev/null +++ b/inmates/demos/x86/e1000-demo.c @@ -0,0 +1,392 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * Append "-device e1000,addr=19,netdev=..." to the QEMU command line for + * testing in the virtual machine. Adjust configs/x86/e1000-demo.c for real + * machines as needed. + */ + +#include + +#define E1000_REG_CTRL 0x0000 +# define E1000_CTRL_LRST (1 << 3) +# define E1000_CTRL_SLU (1 << 6) +# define E1000_CTRL_FRCSPD (1 << 11) +# define E1000_CTRL_RST (1 << 26) +#define E1000_REG_STATUS 0x0008 +# define E1000_STATUS_LU (1 << 1) +# define E1000_STATUS_SPEEDSHFT 6 +# define E1000_STATUS_SPEED (3 << E1000_STATUS_SPEEDSHFT) +#define E1000_REG_EERD 0x0014 +# define E1000_EERD_START (1 << 0) +# define E1000_EERD_DONE (1 << 4) +# define E1000_EERD_ADDR_SHIFT 8 +# define E1000_EERD_DATA_SHIFT 16 +#define E1000_REG_MDIC 0x0020 +# define E1000_MDIC_REGADD_SHFT 16 +# define E1000_MDIC_PHYADD (0x1 << 21) +# define E1000_MDIC_OP_WRITE (0x1 << 26) +# define E1000_MDIC_OP_READ (0x2 << 26) +# define E1000_MDIC_READY (0x1 << 28) +#define E1000_REG_RCTL 0x0100 +# define E1000_RCTL_EN (1 << 1) +# define E1000_RCTL_BAM (1 << 15) +# define E1000_RCTL_BSIZE_2048 (0 << 16) +# define E1000_RCTL_SECRC (1 << 26) +#define E1000_REG_TCTL 0x0400 +# define E1000_TCTL_EN (1 << 1) +# define E1000_TCTL_PSP (1 << 3) +# define E1000_TCTL_CT_DEF (0xf << 4) +# define E1000_TCTL_COLD_DEF (0x40 << 12) +#define E1000_REG_TIPG 0x0410 +# define E1000_TIPG_IPGT_DEF (10 << 0) +# define E1000_TIPG_IPGR1_DEF (10 << 10) +# define E1000_TIPG_IPGR2_DEF (10 << 20) +#define E1000_REG_RDBAL 0x2800 +#define E1000_REG_RDBAH 0x2804 +#define E1000_REG_RDLEN 0x2808 +#define E1000_REG_RDH 0x2810 +#define E1000_REG_RDT 0x2818 +#define E1000_REG_RXDCTL 0x2828 +# define E1000_RXDCTL_ENABLE (1 << 25) +#define E1000_REG_TDBAL 0x3800 +#define E1000_REG_TDBAH 0x3804 +#define E1000_REG_TDLEN 0x3808 +#define E1000_REG_TDH 0x3810 +#define E1000_REG_TDT 0x3818 +#define E1000_REG_TXDCTL 0x3828 +# define E1000_TXDCTL_ENABLE (1 << 25) +#define E1000_REG_RAL 0x5400 +#define E1000_REG_RAH 0x5404 +# define E1000_RAH_AV (1 << 31) + +#define E1000_PHY_CTRL 0 +# define E1000_PHYC_POWER_DOWN (1 << 11) + +struct eth_header { + u8 dst[6]; + u8 src[6]; + u16 type; + u8 data[]; +} __attribute__((packed)); + +#define FRAME_TYPE_ANNOUNCE 0x004a +#define FRAME_TYPE_TARGET_ROLE 0x014a +#define FRAME_TYPE_PING 0x024a +#define FRAME_TYPE_PONG 0x034a + +struct e1000_rxd { + u64 addr; + u16 len; + u16 crc; + u8 dd:1, + eop:1, + ixsm:1, + vp:1, + udpcs:1, + tcpcs:1, + ipcs:1, + pif:1; + u8 errors; + u16 vlan_tag; +} __attribute__((packed)); + +struct e1000_txd { + u64 addr; + u16 len; + u8 cso; + u8 eop:1, + ifcs:1, + ic:1, + rs:1, + rps:1, + dext:1, + vle:1, + ide:1; + u8 dd:1, + ec:1, + lc:1, + tu:1, + rsv:4; + u8 css; + u16 special; +} __attribute__((packed)); + +#define RX_DESCRIPTORS 8 +#define RX_BUFFER_SIZE 2048 +#define TX_DESCRIPTORS 8 + +static const char *speed_info[] = { "10", "100", "1000", "1000" }; + +static void *mmiobar; +static u8 buffer[RX_DESCRIPTORS * RX_BUFFER_SIZE]; +static struct e1000_rxd rx_ring[RX_DESCRIPTORS] __attribute__((aligned(128))); +static struct e1000_txd tx_ring[TX_DESCRIPTORS] __attribute__((aligned(128))); +static unsigned int rx_idx, tx_idx; +static struct eth_header tx_packet; + +static u16 phy_read(unsigned int reg) +{ + u32 val; + + mmio_write32(mmiobar + E1000_REG_MDIC, + (reg << E1000_MDIC_REGADD_SHFT) | + E1000_MDIC_PHYADD | E1000_MDIC_OP_READ); + do { + val = mmio_read32(mmiobar + E1000_REG_MDIC); + cpu_relax(); + } while (!(val & E1000_MDIC_READY)); + + return (u16)val; +} + +static void phy_write(unsigned int reg, u16 val) +{ + mmio_write32(mmiobar + E1000_REG_MDIC, + val | (reg << E1000_MDIC_REGADD_SHFT) | + E1000_MDIC_PHYADD | E1000_MDIC_OP_WRITE); + while (!(mmio_read32(mmiobar + E1000_REG_MDIC) & E1000_MDIC_READY)) + cpu_relax(); +} + +static void send_packet(void *buffer, unsigned int size) +{ + unsigned int idx = tx_idx; + + memset(&tx_ring[idx], 0, sizeof(struct e1000_txd)); + tx_ring[idx].addr = (unsigned long)buffer; + tx_ring[idx].len = size; + tx_ring[idx].rs = 1; + tx_ring[idx].ifcs = 1; + tx_ring[idx].eop = 1; + + tx_idx = (tx_idx + 1) % TX_DESCRIPTORS; + mmio_write32(mmiobar + E1000_REG_TDT, tx_idx); + + while (!tx_ring[idx].dd) + cpu_relax(); +} + +static struct eth_header *packet_received(void) +{ + if (rx_ring[rx_idx].dd) + return (struct eth_header *)rx_ring[rx_idx].addr; + + cpu_relax(); + return NULL; +} + +static void packet_reception_done(void) +{ + unsigned int idx = rx_idx; + + rx_ring[idx].dd = 0; + rx_idx = (rx_idx + 1) % RX_DESCRIPTORS; + mmio_write32(mmiobar + E1000_REG_RDT, idx); +} + +void inmate_main(void) +{ + enum { ROLE_UNDEFINED, ROLE_CONTROLLER, ROLE_TARGET } role; + unsigned long min = -1, max = 0, rtt; + struct eth_header *rx_packet; + unsigned long long start; + bool first_round = true; + unsigned int n; + u32 eerd, val; + u8 mac[6]; + u64 bar; + int bdf; + + bdf = pci_find_device(PCI_ID_ANY, PCI_ID_ANY, 0); + if (bdf < 0) { + printk("No device found!\n"); + return; + } + printk("Found %04x:%04x at %02x:%02x.%x\n", + pci_read_config(bdf, PCI_CFG_VENDOR_ID, 2), + pci_read_config(bdf, PCI_CFG_DEVICE_ID, 2), + bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3); + + bar = pci_read_config(bdf, PCI_CFG_BAR, 4); + if ((bar & 0x6) == 0x4) + bar |= (u64)pci_read_config(bdf, PCI_CFG_BAR + 4, 4) << 32; + mmiobar = (void *)(bar & ~0xfUL); + map_range(mmiobar, 128 * 1024, MAP_UNCACHED); + printk("MMIO register BAR at %p\n", mmiobar); + + pci_write_config(bdf, PCI_CFG_COMMAND, + PCI_CMD_MEM | PCI_CMD_MASTER, 2); + + mmio_write32(mmiobar + E1000_REG_CTRL, E1000_CTRL_RST); + delay_us(20000); + + val = mmio_read32(mmiobar + E1000_REG_CTRL); + val &= ~(E1000_CTRL_LRST | E1000_CTRL_FRCSPD); + val |= E1000_CTRL_SLU; + mmio_write32(mmiobar + E1000_REG_CTRL, val); + + /* power up again in case the previous user turned it off */ + phy_write(E1000_PHY_CTRL, + phy_read(E1000_PHY_CTRL) & ~E1000_PHYC_POWER_DOWN); + + printk("Waiting for link..."); + while (!(mmio_read32(mmiobar + E1000_REG_STATUS) & E1000_STATUS_LU)) + cpu_relax(); + printk(" ok\n"); + + val = mmio_read32(mmiobar + E1000_REG_STATUS) & E1000_STATUS_SPEED; + val >>= E1000_STATUS_SPEEDSHFT; + printk("Link speed: %s Mb/s\n", speed_info[val]); + + if (mmio_read32(mmiobar + E1000_REG_RAH) & E1000_RAH_AV) { + *(u32 *)mac = mmio_read32(mmiobar + E1000_REG_RAL); + *(u16 *)&mac[4] = mmio_read32(mmiobar + E1000_REG_RAH); + } else { + for (n = 0; n < 3; n++) { + mmio_write32(mmiobar + E1000_REG_EERD, + E1000_EERD_START | + (n << E1000_EERD_ADDR_SHIFT)); + do { + eerd = mmio_read32(mmiobar + E1000_REG_EERD); + cpu_relax(); + } while (!(eerd & E1000_EERD_DONE)); + mac[n * 2] = (u8)(eerd >> E1000_EERD_DATA_SHIFT); + mac[n * 2 + 1] = + (u8)(eerd >> (E1000_EERD_DATA_SHIFT + 8)); + } + } + + printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + mmio_write32(mmiobar + E1000_REG_RAL, *(u32 *)mac); + mmio_write32(mmiobar + E1000_REG_RAH, *(u16 *)&mac[4] | E1000_RAH_AV); + + for (n = 0; n < RX_DESCRIPTORS; n++) + rx_ring[n].addr = (unsigned long)&buffer[n * RX_BUFFER_SIZE]; + mmio_write32(mmiobar + E1000_REG_RDBAL, (unsigned long)&rx_ring); + mmio_write32(mmiobar + E1000_REG_RDBAH, 0); + mmio_write32(mmiobar + E1000_REG_RDLEN, sizeof(rx_ring)); + mmio_write32(mmiobar + E1000_REG_RDH, 0); + mmio_write32(mmiobar + E1000_REG_RDT, 0); + mmio_write32(mmiobar + E1000_REG_RXDCTL, + mmio_read32(mmiobar + E1000_REG_RXDCTL) | E1000_RXDCTL_ENABLE); + + val = mmio_read32(mmiobar + E1000_REG_RCTL); + val |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2048 | + E1000_RCTL_SECRC; + mmio_write32(mmiobar + E1000_REG_RCTL, val); + + mmio_write32(mmiobar + E1000_REG_RDT, RX_DESCRIPTORS - 1); + + mmio_write32(mmiobar + E1000_REG_TDBAL, (unsigned long)&tx_ring); + mmio_write32(mmiobar + E1000_REG_TDBAH, 0); + mmio_write32(mmiobar + E1000_REG_TDLEN, sizeof(tx_ring)); + mmio_write32(mmiobar + E1000_REG_TDH, 0); + mmio_write32(mmiobar + E1000_REG_TDT, 0); + mmio_write32(mmiobar + E1000_REG_TXDCTL, + mmio_read32(mmiobar + E1000_REG_TXDCTL) | E1000_TXDCTL_ENABLE); + + val = mmio_read32(mmiobar + E1000_REG_TCTL); + val |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_CT_DEF | + E1000_TCTL_COLD_DEF; + mmio_write32(mmiobar + E1000_REG_TCTL, val); + mmio_write32(mmiobar + E1000_REG_TIPG, + E1000_TIPG_IPGT_DEF | E1000_TIPG_IPGR1_DEF | + E1000_TIPG_IPGR2_DEF); + + role = ROLE_UNDEFINED; + + memcpy(tx_packet.src, mac, sizeof(tx_packet.src)); + memset(tx_packet.dst, 0xff, sizeof(tx_packet.dst)); + tx_packet.type = FRAME_TYPE_ANNOUNCE; + send_packet(&tx_packet, sizeof(tx_packet)); + + start = pm_timer_read(); + while (pm_timer_read() - start < NS_PER_MSEC && + role == ROLE_UNDEFINED) { + rx_packet = packet_received(); + if (!rx_packet) + continue; + + if (rx_packet->type == FRAME_TYPE_TARGET_ROLE) { + role = ROLE_TARGET; + memcpy(tx_packet.dst, rx_packet->src, + sizeof(tx_packet.dst)); + } + packet_reception_done(); + } + + if (role == ROLE_UNDEFINED) { + role = ROLE_CONTROLLER; + printk("Waiting for peer\n"); + while (1) { + rx_packet = packet_received(); + if (!rx_packet) + continue; + + if (rx_packet->type == FRAME_TYPE_ANNOUNCE) { + memcpy(tx_packet.dst, rx_packet->src, + sizeof(tx_packet.dst)); + packet_reception_done(); + + tx_packet.type = FRAME_TYPE_TARGET_ROLE; + send_packet(&tx_packet, sizeof(tx_packet)); + break; + } else { + packet_reception_done(); + } + } + } + + mmio_write32(mmiobar + E1000_REG_RCTL, + mmio_read32(mmiobar + E1000_REG_RCTL) & ~E1000_RCTL_BAM); + + if (role == ROLE_CONTROLLER) { + printk("Running as controller\n"); + tx_packet.type = FRAME_TYPE_PING; + while (1) { + start = pm_timer_read(); + send_packet(&tx_packet, sizeof(tx_packet)); + + do + rx_packet = packet_received(); + while (!rx_packet || + rx_packet->type != FRAME_TYPE_PONG); + packet_reception_done(); + + if (!first_round) { + rtt = pm_timer_read() - start; + if (rtt < min) + min = rtt; + if (rtt > max) + max = rtt; + printk("Received pong, RTT: %6ld ns, " + "min: %6ld ns, max: %6ld ns\n", + rtt, min, max); + } + first_round = false; + delay_us(100000); + } + } else { + printk("Running as target\n"); + tx_packet.type = FRAME_TYPE_PONG; + while (1) { + rx_packet = packet_received(); + if (!rx_packet || rx_packet->type != FRAME_TYPE_PING) + continue; + packet_reception_done(); + send_packet(&tx_packet, sizeof(tx_packet)); + } + } +} diff --git a/inmates/demos/x86/ioapic-demo.c b/inmates/demos/x86/ioapic-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..dfb33b8ae80ff829f4342bfd036bfc124aa79097 --- /dev/null +++ b/inmates/demos/x86/ioapic-demo.c @@ -0,0 +1,62 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * WARNING: This is just a demo, using a commonly available resource. IRQ 9 + * is bluntly stolen from Linux while it may still listen to this source in + * the ACPI driver. Even when destroying the cell, Linux won't regain control + * as it won't reprogram the IOAPIC. Moreover, the IRQ might be shared with + * other devices which will lose their IRQs when starting this cell. + * + * Strong recommendation: Avoid using legacy interrupt for non-root cells! + * Many of them can't be isolated easily from other other cells - if at all. + */ + +#include + +#define PM1_STATUS 0 +#define PM1_ENABLE 2 +# define PM1_TMR_EN (1 << 0) + +#define ACPI_GSI 9 + +#define IRQ_VECTOR 32 + +static unsigned int pm_base; + +static void irq_handler(unsigned int irq) +{ + u16 status; + + if (irq != IRQ_VECTOR) + return; + + status = inw(pm_base + PM1_STATUS); + + printk("ACPI IRQ received, status: %04x\n", status); + outw(status, pm_base); +} + +void inmate_main(void) +{ + irq_init(irq_handler); + + ioapic_init(); + ioapic_pin_set_vector(ACPI_GSI, TRIGGER_LEVEL_ACTIVE_HIGH, IRQ_VECTOR); + + pm_base = comm_region->pm_timer_address - 8; + outw(inw(pm_base + PM1_ENABLE) | PM1_TMR_EN, pm_base + PM1_ENABLE); + + printk("Note: ACPI IRQs are broken for Linux now.\n"); + asm volatile("sti"); + + halt(); +} diff --git a/inmates/demos/x86/pci-demo.c b/inmates/demos/x86/pci-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..3e48e0507da03ab2a5d03d218107e3f7078b02f0 --- /dev/null +++ b/inmates/demos/x86/pci-demo.c @@ -0,0 +1,83 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * Append "-device intel-hda,addr=1b.0 -device hda-output" to the QEMU command + * line for testing in the virtual machine. Adjust configs/x86/pci-demo.c for + * real machines as needed. + */ + +#include + +#define IRQ_VECTOR 32 + +#define HDA_GCTL 0x08 +#define HDA_WAKEEN 0x0c +#define HDA_STATESTS 0x0e +#define HDA_INTCTL 0x20 + +static void *hdbar; + +static void irq_handler(unsigned int irq) +{ + u16 statests; + + if (irq != IRQ_VECTOR) + return; + + statests = mmio_read16(hdbar + HDA_STATESTS); + + printk("HDA MSI received (STATESTS: %04x)\n", statests); + mmio_write16(hdbar + HDA_STATESTS, statests); +} + +void inmate_main(void) +{ + u64 bar; + int bdf; + + irq_init(irq_handler); + + bdf = pci_find_device(PCI_ID_ANY, PCI_ID_ANY, 0); + if (bdf < 0) { + printk("No device found!\n"); + return; + } + printk("Found %04x:%04x at %02x:%02x.%x\n", + pci_read_config(bdf, PCI_CFG_VENDOR_ID, 2), + pci_read_config(bdf, PCI_CFG_DEVICE_ID, 2), + bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3); + + bar = pci_read_config(bdf, PCI_CFG_BAR, 4); + if ((bar & 0x6) == 0x4) + bar |= (u64)pci_read_config(bdf, PCI_CFG_BAR + 4, 4) << 32; + hdbar = (void *)(bar & ~0xfUL); + map_range(hdbar, PAGE_SIZE, MAP_UNCACHED); + printk("HDBAR at %p\n", hdbar); + + pci_msi_set_vector(bdf, IRQ_VECTOR); + + pci_write_config(bdf, PCI_CFG_COMMAND, + PCI_CMD_MEM | PCI_CMD_MASTER, 2); + + asm volatile("sti"); + + mmio_write16(hdbar + HDA_STATESTS, mmio_read16(hdbar + HDA_STATESTS)); + + mmio_write16(hdbar + HDA_GCTL, 0); + delay_us(7000); + mmio_write16(hdbar + HDA_GCTL, 1); + + mmio_write16(hdbar + HDA_WAKEEN, 0x0f); + mmio_write32(hdbar + HDA_INTCTL, (1 << 31) | (1 << 30)); + + halt(); +} diff --git a/inmates/demos/x86/smp-demo.c b/inmates/demos/x86/smp-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..cd48332e76076807f834194343d54ad21bad2562 --- /dev/null +++ b/inmates/demos/x86/smp-demo.c @@ -0,0 +1,57 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define IPI_VECTOR 40 + +static volatile bool done; +static unsigned int main_cpu; + +static void ipi_handler(unsigned int irq) +{ + if (irq != IPI_VECTOR) + return; + + printk("Received IPI on %d\n", cpu_id()); + done = true; +} + +static void secondary_main(void) +{ + printk("Hello from CPU %d!\n", cpu_id()); + irq_send_ipi(main_cpu, IPI_VECTOR); +} + +void inmate_main(void) +{ + unsigned int n; + + main_cpu = cpu_id(); + printk("SMP demo, primary CPU: %d\n", main_cpu); + + printk("Waiting for the rest..."); + smp_wait_for_all_cpus(); + printk("\nFound %d other CPU(s)\n", smp_num_cpus - 1); + + irq_init(ipi_handler); + + asm volatile("sti"); + + for (n = 1; n < smp_num_cpus; n++) { + printk(" Starting CPU %d\n", smp_cpu_ids[n]); + done = false; + smp_start_cpu(smp_cpu_ids[n], secondary_main); + while (!done) + cpu_relax(); + } +} diff --git a/inmates/demos/x86/tiny-demo.c b/inmates/demos/x86/tiny-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..fd3b6c9b11d4d275f4225d8d6ad5222c69a17ac3 --- /dev/null +++ b/inmates/demos/x86/tiny-demo.c @@ -0,0 +1,31 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +void inmate_main(void) +{ + unsigned long long start, now; + int n; + + printk("Hello from this tiny cell!\n"); + + start = pm_timer_read(); + for (n = 0; n < 10; n++) { + do { + now = pm_timer_read(); + cpu_relax(); + } while (now - start < 1000000000ULL); + start += 1000000000ULL; + printk("PM Timer: %11llu\n", now); + } +} diff --git a/inmates/lib/alloc.c b/inmates/lib/alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..5da6828a8f41d5e834d77f0d4016b68fbde3ca4e --- /dev/null +++ b/inmates/lib/alloc.c @@ -0,0 +1,58 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * Bram Hooimeijer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +unsigned long heap_pos = (unsigned long)stack_top; + +void *alloc(unsigned long size, unsigned long align) +{ + unsigned long base = (heap_pos + align - 1) & ~(align - 1); + + heap_pos = base + size; + return (void *)base; +} + +void *zalloc(unsigned long size, unsigned long align) +{ + void *base = alloc(size, align); + memset(base, 0, size); + + return base; +} diff --git a/inmates/lib/arm-common/Makefile.lib b/inmates/lib/arm-common/Makefile.lib new file mode 100644 index 0000000000000000000000000000000000000000..b50533e46b9de09f6b6f22a58eded679b83977bb --- /dev/null +++ b/inmates/lib/arm-common/Makefile.lib @@ -0,0 +1,46 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) OTH Regensburg, 2016 +# +# Authors: +# Ralf Ramsauer +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +objs-y := ../string.o ../cmdline.o ../setup.o ../alloc.o ../uart-8250.o +objs-y += ../printk.o ../pci.o +objs-y += printk.o gic.o mem.o pci.o timing.o setup.o uart.o +objs-y += uart-xuartps.o uart-mvebu.o uart-hscif.o uart-scifa.o uart-imx.o +objs-y += uart-pl011.o uart-imx-lpuart.o uart-scif.o +objs-y += gic-v2.o gic-v3.o + +common-objs-y = $(addprefix ../arm-common/,$(objs-y)) diff --git a/inmates/lib/arm-common/gic-v2.c b/inmates/lib/arm-common/gic-v2.c new file mode 100644 index 0000000000000000000000000000000000000000..55d9606342da87549cbb2861c53418660170252b --- /dev/null +++ b/inmates/lib/arm-common/gic-v2.c @@ -0,0 +1,91 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define GICC_CTLR 0x0000 +#define GICC_PMR 0x0004 +#define GICC_IAR 0x000c +#define GICC_EOIR 0x0010 +#define GICD_CTLR 0x0000 +#define GICD_CTLR_ENABLE (1 << 0) + +#define GICC_CTLR_GRPEN1 (1 << 0) + +#define GICC_PMR_DEFAULT 0xf0 + +static void *gicc_v2_base; +static void *gicd_v2_base; + +static void gic_v2_enable(unsigned int irqn) +{ + mmio_write32(gicd_v2_base + GICD_ISENABLER + ((irqn >> 3) & ~0x3), + 1 << (irqn & 0x1f)); +} + +static int gic_v2_init(void) +{ + gicc_v2_base = (void*)(unsigned long)comm_region->gicc_base; + gicd_v2_base = (void*)(unsigned long)comm_region->gicd_base; + + map_range(gicc_v2_base, PAGE_SIZE, MAP_UNCACHED); + map_range(gicd_v2_base, PAGE_SIZE, MAP_UNCACHED); + + mmio_write32(gicc_v2_base + GICC_CTLR, GICC_CTLR_GRPEN1); + mmio_write32(gicc_v2_base + GICC_PMR, GICC_PMR_DEFAULT); + mmio_write32(gicd_v2_base + GICD_CTLR, GICD_CTLR_ENABLE); + + return 0; +} + +static void gic_v2_write_eoi(u32 irqn) +{ + mmio_write32(gicc_v2_base + GICC_EOIR, irqn); +} + +static u32 gic_v2_read_ack(void) +{ + return mmio_read32(gicc_v2_base + GICC_IAR) & 0x3ff; +} + +const struct gic gic_v2 = { + .init = gic_v2_init, + .enable = gic_v2_enable, + .write_eoi = gic_v2_write_eoi, + .read_ack = gic_v2_read_ack, +}; diff --git a/inmates/lib/arm-common/gic-v3.c b/inmates/lib/arm-common/gic-v3.c new file mode 100644 index 0000000000000000000000000000000000000000..cd202a46dd75149e39608ba78b24b34383c0a4d5 --- /dev/null +++ b/inmates/lib/arm-common/gic-v3.c @@ -0,0 +1,131 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +static void *gicd_v3_base; +static void *gicr_v3_base; + +#define GICR_TYPER 0x0008 +#define GICR_TYPER_Last (1 << 4) +#define GICR_PIDR2 0xffe8 +#define GICR_SGI_BASE 0x10000 +#define GICR_ISENABLER GICD_ISENABLER + +#define GICD_PIDR2_ARCH(pidr) (((pidr) & 0xf0) >> 4) +#define GICR_PIDR2_ARCH GICD_PIDR2_ARCH + +static void gic_v3_enable(unsigned int irqn) +{ + if (is_sgi_ppi(irqn)) + mmio_write32(gicr_v3_base + GICR_SGI_BASE + GICR_ISENABLER, + 1 << irqn); + else if (is_spi(irqn)) + mmio_write32(gicd_v3_base + GICD_ISENABLER + (irqn / 32) * 4, + 1 << (irqn % 32)); +} + +static int gic_v3_init(void) +{ + unsigned long mpidr; + void *redist_addr; + void *gicr = NULL; + u64 typer; + u32 pidr, aff; + + redist_addr = (void*)(unsigned long)comm_region->gicr_base; + gicd_v3_base = (void*)(unsigned long)comm_region->gicd_base; + + map_range(gicd_v3_base, PAGE_SIZE, MAP_UNCACHED); + map_range(redist_addr, PAGE_SIZE, MAP_UNCACHED); + + arm_read_sysreg(MPIDR, mpidr); + mpidr &= MPIDR_CPUID_MASK; + aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 | + MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | + MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | + MPIDR_AFFINITY_LEVEL(mpidr, 0)); + + /* Find redistributor */ + do { + pidr = mmio_read32(redist_addr + GICR_PIDR2); + if (GICR_PIDR2_ARCH(pidr) != 3) + break; + + typer = mmio_read32(redist_addr + GICR_TYPER); + typer |= (u64)mmio_read32(redist_addr + GICR_TYPER + 4) << 32; + if ((typer >> 32) == aff) { + gicr = redist_addr; + break; + } + + redist_addr += 0x20000; + } while (!(typer & GICR_TYPER_Last)); + + if (!gicr) + return -1; + + gicr_v3_base = gicr; + + arm_write_sysreg(ICC_CTLR_EL1, 0); + arm_write_sysreg(ICC_PMR_EL1, 0xf0); + arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN); + + return 0; +} + +static void gic_v3_write_eoi(u32 irqn) +{ + arm_write_sysreg(ICC_EOIR1_EL1, irqn); +} + +static u32 gic_v3_read_ack(void) +{ + u32 val; + + arm_read_sysreg(ICC_IAR1_EL1, val); + return val & 0xffffff; +} + +const struct gic gic_v3 = { + .init = gic_v3_init, + .enable = gic_v3_enable, + .write_eoi = gic_v3_write_eoi, + .read_ack = gic_v3_read_ack, +}; diff --git a/inmates/lib/arm-common/gic.c b/inmates/lib/arm-common/gic.c new file mode 100644 index 0000000000000000000000000000000000000000..73d37c406cfa98c68e9de408885a0b9cb2252f81 --- /dev/null +++ b/inmates/lib/arm-common/gic.c @@ -0,0 +1,80 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +extern const struct gic gic_v2; +extern const struct gic gic_v3; + +static irq_handler_t irq_handler; +static const struct gic *gic = &gic_v2; + +/* Replaces the weak reference in header.S */ +void vector_irq(void) +{ + u32 irqn; + + while (1) { + irqn = gic->read_ack(); + if (irqn == 0x3ff) + break; + + if (irq_handler) + irq_handler(irqn); + + gic->write_eoi(irqn); + } +} + +void irq_init(irq_handler_t handler) +{ + if (comm_region->gic_version == 3) + gic = &gic_v3; + + gic->init(); + + irq_handler = handler; + + gic_setup_irq_stack(); +} + +void irq_enable(unsigned int irq) +{ + gic->enable(irq); +} diff --git a/inmates/lib/arm-common/include/asm/processor.h b/inmates/lib/arm-common/include/asm/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..18de9567047d1c19fc627a6779e4c1ac4d794723 --- /dev/null +++ b/inmates/lib/arm-common/include/asm/processor.h @@ -0,0 +1,64 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef __ASSEMBLY__ + +#define dmb(domain) asm volatile("dmb " #domain ::: "memory") +#define dsb(domain) asm volatile("dsb " #domain ::: "memory") + +static inline void cpu_relax(void) +{ + asm volatile("" : : : "memory"); +} + +static inline void memory_barrier(void) +{ + dmb(ish); +} + +static inline void synchronization_barrier(void) +{ + dsb(ish); +} + +static inline void instruction_barrier(void) +{ + asm volatile("isb"); +} + +#endif /* __ASSEMBLY__ */ diff --git a/inmates/lib/arm-common/include/asm/sysregs_common.h b/inmates/lib/arm-common/include/asm/sysregs_common.h new file mode 100644 index 0000000000000000000000000000000000000000..168cb70d72d0c47275175c2ff223696fc2e01685 --- /dev/null +++ b/inmates/lib/arm-common/include/asm/sysregs_common.h @@ -0,0 +1,68 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define HUGE_PAGE_SIZE (2 * 1024 * 1024ULL) +#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1)) + +#define ICC_IAR1_EL1 SYSREG_32(0, c12, c12, 0) +#define ICC_EOIR1_EL1 SYSREG_32(0, c12, c12, 1) +#define ICC_PMR_EL1 SYSREG_32(0, c4, c6, 0) +#define ICC_CTLR_EL1 SYSREG_32(0, c12, c12, 4) +#define ICC_IGRPEN1_EL1 SYSREG_32(0, c12, c12, 7) + +#define ICC_IGRPEN1_EN 0x1 + +#define MAIR_ATTR_SHIFT(__n) ((__n) << 3) +#define MAIR_ATTR(__n, __attr) ((__attr) << MAIR_ATTR_SHIFT(__n)) +#define MAIR_ATTR_WBRWA 0xff +#define MAIR_ATTR_DEVICE 0x00 /* nGnRnE */ + +/* Common definitions for page table structure in long descriptor format */ +#define LONG_DESC_BLOCK 0x1 +#define LONG_DESC_TABLE 0x3 + +#define LATTR_CONT (1 << 12) +#define LATTR_AF (1 << 10) +#define LATTR_INNER_SHAREABLE (3 << 8) +#define LATTR_MAIR(n) (((n) & 0x3) << 2) + +#define LATTR_AP(n) (((n) & 0x3) << 6) +#define LATTR_AP_RW_EL1 LATTR_AP(0x0) + +#define PGD_INDEX(addr) ((addr) >> 30) +#define PMD_INDEX(addr) (((addr) >> 21) & 0x1ff) diff --git a/inmates/lib/arm-common/include/gic.h b/inmates/lib/arm-common/include/gic.h new file mode 100644 index 0000000000000000000000000000000000000000..bcfe15cd3ce924ec35f07d4de4bbf3d28ad22302 --- /dev/null +++ b/inmates/lib/arm-common/include/gic.h @@ -0,0 +1,64 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_INMATES_GIC_H +#define _JAILHOUSE_INMATES_GIC_H + +#include + +#define GICD_ISENABLER 0x0100 + +#define TIMER_IRQ 27 + +#define is_sgi_ppi(irqn) ((irqn) < 32) +#define is_spi(irqn) ((irqn) > 31 && (irqn) < 1020) + +#ifndef __ASSEMBLY__ + +struct gic { + int (*init)(void); + void (*enable)(unsigned int irqn); + void (*write_eoi)(u32 irqn); + u32 (*read_ack)(void); +}; + +#endif /* !__ASSEMBLY__ */ + +#include + +#endif diff --git a/inmates/lib/arm-common/include/inmate.h b/inmates/lib/arm-common/include/inmate.h new file mode 100644 index 0000000000000000000000000000000000000000..ab5681d697e418f2cc29135c29eb72e13523542a --- /dev/null +++ b/inmates/lib/arm-common/include/inmate.h @@ -0,0 +1,110 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_INMATE_H +#define _JAILHOUSE_INMATE_H + +#define COMM_REGION_BASE 0x80000000 +#define PAGE_SIZE (4 * 1024ULL) + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +static inline u8 mmio_read8(void *address) +{ + return *(volatile u8 *)address; +} + +static inline void mmio_write8(void *address, u8 value) +{ + *(volatile u8 *)address = value; +} + +static inline u16 mmio_read16(void *address) +{ + return *(volatile u16 *)address; +} + +static inline void mmio_write16(void *address, u16 value) +{ + *(volatile u16 *)address = value; +} + +static inline u32 mmio_read32(void *address) +{ + return *(volatile u32 *)address; +} + +static inline void mmio_write32(void *address, u32 value) +{ + *(volatile u32 *)address = value; +} + +static inline u64 mmio_read64(void *address) +{ + return *(volatile u64 *)address; +} + +static inline void __attribute__((noreturn)) halt(void) +{ + while (1) + asm volatile("wfi" : : : "memory"); +} + +unsigned long timer_get_frequency(void); +u64 timer_get_ticks(void); +u64 timer_ticks_to_ns(u64 ticks); +void timer_start(u64 timeout); + +void arch_mmu_enable(void); + +#include +#include + +#include + +#endif /* !_JAILHOUSE_INMATE_H */ diff --git a/inmates/lib/arm-common/mem.c b/inmates/lib/arm-common/mem.c new file mode 100644 index 0000000000000000000000000000000000000000..5064b00207abf93aa61d8d62916a28cd4c50ea5e --- /dev/null +++ b/inmates/lib/arm-common/mem.c @@ -0,0 +1,122 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +static u64 __attribute__((aligned(4096))) + page_directory[JAILHOUSE_INMATE_MEM_PAGE_DIR_LEN]; + +void map_range(void *start, unsigned long size, enum map_type map_type) +{ + u64 vaddr, pmd_entry; + unsigned pgd_index; + u64 *pmd; + + vaddr = (unsigned long)start; + + size += (vaddr & ~HUGE_PAGE_MASK) + HUGE_PAGE_SIZE - 1; + size &= HUGE_PAGE_MASK; + + while (size) { + pgd_index = PGD_INDEX(vaddr); + if (!(page_directory[pgd_index] & LONG_DESC_TABLE)) { + pmd = zalloc(PAGE_SIZE, PAGE_SIZE); + /* ensure the page table walker will see the zeroes */ + synchronization_barrier(); + + page_directory[pgd_index] = + (unsigned long)pmd | LONG_DESC_TABLE; + } else { + pmd = (u64*)(unsigned long) + (page_directory[pgd_index] & ~LONG_DESC_TABLE); + } + + pmd_entry = vaddr & HUGE_PAGE_MASK; + pmd_entry |= LATTR_AF | LATTR_INNER_SHAREABLE | \ + LATTR_AP_RW_EL1 | LONG_DESC_BLOCK; + if (map_type == MAP_CACHED) + pmd_entry |= LATTR_MAIR(0); + else + pmd_entry |= LATTR_MAIR(1); + + pmd[PMD_INDEX(vaddr)] = pmd_entry; + + size -= HUGE_PAGE_SIZE; + vaddr += HUGE_PAGE_SIZE; + } + + /* + * As long es we only add entries and do not modify entries, a + * synchronization barrier is enough to propagate changes. Otherwise we + * need to flush the TLB. + */ + synchronization_barrier(); +} + +void arch_mmu_enable(void) +{ + unsigned long mair, sctlr; + + map_range((void*)CONFIG_INMATE_BASE, 0x10000, MAP_CACHED); + map_range((void*)COMM_REGION_BASE, PAGE_SIZE, MAP_CACHED); + + /* + * ARMv7: Use attributes 0 and 1 in MAIR0 + * ARMv8: Use attributes 0 and 1 in MAIR + * + * Attributes 0: inner/outer: normal memory, outer write-back + * non-transient + * Attributes 1: device memory + */ + mair = MAIR_ATTR(1, MAIR_ATTR_DEVICE) | MAIR_ATTR(0, MAIR_ATTR_WBRWA); + arm_write_sysreg(MAIR, mair); + + arm_write_sysreg(TRANSL_CONT_REG, TRANSL_CONT_REG_SETTINGS); + + arm_write_sysreg(TTBR0, page_directory); + /* This barrier ensures that TTBR0 is set before enabling the MMU. */ + instruction_barrier(); + + arm_read_sysreg(SCTLR, sctlr); + sctlr |= SCTLR_MMU_CACHES; + arm_write_sysreg(SCTLR, sctlr); + /* This barrier ensures that the MMU is actually on */ + instruction_barrier(); + /* MMU is enabled from now on */ +} diff --git a/inmates/lib/arm-common/pci.c b/inmates/lib/arm-common/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..f47d7a76ec8fa8d16a9843426cd7d1b64e4342ea --- /dev/null +++ b/inmates/lib/arm-common/pci.c @@ -0,0 +1,93 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +void pci_init(void) +{ + void *mmcfg = (void *)(unsigned long)comm_region->pci_mmconfig_base; + + if (mmcfg) + map_range(mmcfg, 0x100000, MAP_UNCACHED); +} + +static void *pci_get_device_mmcfg_base(u16 bdf) +{ + void *mmcfg = (void *)(unsigned long)comm_region->pci_mmconfig_base; + + return mmcfg + ((unsigned long)bdf << 12); +} + +u32 pci_read_config(u16 bdf, unsigned int addr, unsigned int size) +{ + void *cfgaddr = pci_get_device_mmcfg_base(bdf) + addr; + + switch (size) { + case 1: + return mmio_read8(cfgaddr); + case 2: + return mmio_read16(cfgaddr); + case 4: + return mmio_read32(cfgaddr); + default: + return -1; + } +} + +void pci_write_config(u16 bdf, unsigned int addr, u32 value, unsigned int size) +{ + void *cfgaddr = pci_get_device_mmcfg_base(bdf) + addr; + + switch (size) { + case 1: + mmio_write8(cfgaddr, value); + break; + case 2: + mmio_write16(cfgaddr, value); + break; + case 4: + mmio_write32(cfgaddr, value); + break; + } +} + +void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index) +{ + /* dummy for now, should never be called */ + *(int *)0xdeaddead = 0; +} diff --git a/inmates/lib/arm-common/printk.c b/inmates/lib/arm-common/printk.c new file mode 100644 index 0000000000000000000000000000000000000000..9833bbf93531192576eddac4abfe858a2556aea9 --- /dev/null +++ b/inmates/lib/arm-common/printk.c @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +static void reg_out_mmio8(struct uart_chip *chip, unsigned int reg, u32 value) +{ + mmio_write8(chip->base + reg, value); +} + +static u32 reg_in_mmio8(struct uart_chip *chip, unsigned int reg) +{ + return mmio_read8(chip->base + reg); +} + +void arch_console_init(struct uart_chip *chip) +{ + struct jailhouse_console *console = &comm_region->console; + unsigned int gate_nr; + bool gate_inverted; + void *clock_reg; + u32 clock_gates; + + gate_nr = cmdline_parse_int("con-gate-nr", console->gate_nr); + gate_inverted = cmdline_parse_bool("con-gate-inverted", + CON_HAS_INVERTED_GATE(console->flags)); + clock_reg = (void *)(unsigned long) + cmdline_parse_int("con-clock-reg", console->clock_reg); + + if (cmdline_parse_bool("con-regdist-1", + CON_USES_REGDIST_1(console->flags))) { + chip->reg_out = reg_out_mmio8; + chip->reg_in = reg_in_mmio8; + } + + if (chip->base) + map_range(chip->base, PAGE_SIZE, MAP_UNCACHED); + + if (clock_reg) { + map_range(clock_reg, PAGE_SIZE, MAP_UNCACHED); + clock_gates = mmio_read32(clock_reg); + if (gate_inverted) + clock_gates &= ~(1 << gate_nr); + else + clock_gates |= (1 << gate_nr); + mmio_write32(clock_reg, clock_gates); + } +} diff --git a/inmates/lib/arm-common/setup.c b/inmates/lib/arm-common/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..422c9487b0a500275a60c31a060678361f950fab --- /dev/null +++ b/inmates/lib/arm-common/setup.c @@ -0,0 +1,44 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +void arch_init_early(void) +{ + arch_mmu_enable(); +} diff --git a/inmates/lib/arm-common/timing.c b/inmates/lib/arm-common/timing.c new file mode 100644 index 0000000000000000000000000000000000000000..b8e8c04c446ab677bc152b84c3c45d62b87b9a5a --- /dev/null +++ b/inmates/lib/arm-common/timing.c @@ -0,0 +1,90 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +unsigned long timer_get_frequency(void) +{ + unsigned long freq; + + arm_read_sysreg(CNTFRQ_EL0, freq); + return freq; +} + +u64 timer_get_ticks(void) +{ + u64 pct64; + + arm_read_sysreg(CNTPCT_EL0, pct64); + return pct64; +} + +static unsigned long emul_division(u64 val, u64 div) +{ + unsigned long cnt = 0; + + while (val > div) { + val -= div; + cnt++; + } + return cnt; +} + +u64 timer_ticks_to_ns(u64 ticks) +{ + return emul_division(ticks * 1000, + timer_get_frequency() / 1000 / 1000); +} + +void timer_start(u64 timeout) +{ + arm_write_sysreg(CNTV_TVAL_EL0, timeout); + arm_write_sysreg(CNTV_CTL_EL0, 1); +} + +void delay_us(unsigned long microsecs) +{ + unsigned long long timeout = timer_get_ticks() + + microsecs * (timer_get_frequency() / 1000 / 1000); + + while ((long long)(timeout - timer_get_ticks()) > 0) + cpu_relax(); +} diff --git a/inmates/lib/arm-common/uart-hscif.c b/inmates/lib/arm-common/uart-hscif.c new file mode 100644 index 0000000000000000000000000000000000000000..be834d3a4e32057ead95a612bd0950bfdf2657e8 --- /dev/null +++ b/inmates/lib/arm-common/uart-hscif.c @@ -0,0 +1,83 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) emtrion GmbH, 2017 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define HSCIF_HSBRR 0x04 +#define HSCIF_HSSCR 0x08 +#define HSCIF_HSFTDR 0x0C +#define HSCIF_HSFSR 0x10 +#define HSCIF_HSTTRGR 0x58 + +#define HSCIF_HSSCR_RE 0x0010 +#define HSCIF_HSSCR_TE 0x0020 + +#define HSCIF_HSFSR_TDFE 0x0020 +#define HSCIF_HSFSR_TEND 0x0040 + +#define HSCIF_FIFO_SIZE 128 + +static void uart_hscif_init(struct uart_chip *chip) +{ + u16 hsscr; + + if (chip->divider) { + hsscr = mmio_read16(chip->base + HSCIF_HSSCR); + mmio_write16(chip->base + HSCIF_HSSCR, + hsscr & ~(HSCIF_HSSCR_TE | HSCIF_HSSCR_RE)); + mmio_write8(chip->base + HSCIF_HSBRR, chip->divider); + mmio_write16(chip->base + HSCIF_HSTTRGR, HSCIF_FIFO_SIZE / 2); + mmio_write16(chip->base + HSCIF_HSSCR, hsscr | HSCIF_HSSCR_TE); + } +} + +static bool uart_hscif_is_busy(struct uart_chip *chip) +{ + return !(mmio_read16(chip->base + HSCIF_HSFSR) & HSCIF_HSFSR_TDFE); +} + +static void uart_hscif_write(struct uart_chip *chip, char c) +{ + mmio_write8(chip->base + HSCIF_HSFTDR, c); + mmio_write16(chip->base + HSCIF_HSFSR, + mmio_read16(chip->base + HSCIF_HSFSR) & + ~(HSCIF_HSFSR_TDFE | HSCIF_HSFSR_TEND)); +} + +DEFINE_UART(hscif, "HSCIF", JAILHOUSE_CON_TYPE_HSCIF); diff --git a/inmates/lib/arm-common/uart-imx-lpuart.c b/inmates/lib/arm-common/uart-imx-lpuart.c new file mode 100644 index 0000000000000000000000000000000000000000..4e5d43ef12310027e5508bb2cfe67394dac833a8 --- /dev/null +++ b/inmates/lib/arm-common/uart-imx-lpuart.c @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UART_DATA 0x1c +#define UART_STAT 0x14 +#define STAT_TDRE (1 << 23) + +static void uart_imx_lpuart_init(struct uart_chip *chip) +{ +} + +static bool uart_imx_lpuart_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->base + UART_STAT) & STAT_TDRE); +} + +static void uart_imx_lpuart_write(struct uart_chip *chip, char c) +{ + mmio_write32(chip->base + UART_DATA, c); +} + +DEFINE_UART(imx_lpuart, "IMX-LPUART", JAILHOUSE_CON_TYPE_IMX_LPUART); diff --git a/inmates/lib/arm-common/uart-imx.c b/inmates/lib/arm-common/uart-imx.c new file mode 100644 index 0000000000000000000000000000000000000000..8df165f08105ea73714d870d3da0d19dd9d7abcb --- /dev/null +++ b/inmates/lib/arm-common/uart-imx.c @@ -0,0 +1,63 @@ +/* + * Copyright 2017 NXP + * + * Authors: + * Peng Fan + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UTS 0xb4 +#define UTXD 0x40 +#define UCR1 0x80 +#define UCR1_UARTEN (1<<0) +#define UTS_TXEMPTY (1 << 6) + +static void uart_imx_init(struct uart_chip *chip) +{ + /* Initialization currently done by Linux. */ +} + +static bool uart_imx_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->base + UTS) & UTS_TXEMPTY); +} + +static void uart_imx_write(struct uart_chip *chip, char c) +{ + if (!(mmio_read32(chip->base + UCR1) & UCR1_UARTEN)) + return; + mmio_write32(chip->base + UTXD, c); +} + +DEFINE_UART(imx, "IMX", JAILHOUSE_CON_TYPE_IMX); diff --git a/inmates/lib/arm-common/uart-mvebu.c b/inmates/lib/arm-common/uart-mvebu.c new file mode 100644 index 0000000000000000000000000000000000000000..25d8b8592ab44b8578ea891b15e7be9fd5e905e8 --- /dev/null +++ b/inmates/lib/arm-common/uart-mvebu.c @@ -0,0 +1,60 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UART_TSH 0x4 +#define UART_STAT 0xc +#define UART_STAT_TX_FULL (1 << 11) + +static void uart_mvebu_init(struct uart_chip *chip) +{ +} + +static bool uart_mvebu_is_busy(struct uart_chip *chip) +{ + return !!(mmio_read32(chip->base + UART_STAT) & UART_STAT_TX_FULL); +} + +static void uart_mvebu_write(struct uart_chip *chip, char c) +{ + mmio_write32(chip->base + UART_TSH, c); +} + +DEFINE_UART(mvebu, "MVEBU", JAILHOUSE_CON_TYPE_MVEBU); diff --git a/inmates/lib/arm-common/uart-pl011.c b/inmates/lib/arm-common/uart-pl011.c new file mode 100644 index 0000000000000000000000000000000000000000..aff8fa31f971c0a79db37d8e168ad2bedbb2cbb4 --- /dev/null +++ b/inmates/lib/arm-common/uart-pl011.c @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UARTDR 0x00 +#define UARTFR 0x18 +#define UARTIBRD 0x24 +#define UARTLCR_H 0x2c +#define UARTCR 0x30 + +#define UARTFR_TXFF (1 << 5) +#define UARTFR_BUSY (1 << 3) + +#define UARTCR_Out2 (1 << 13) +#define UARTCR_Out1 (1 << 12) +#define UARTCR_RXE (1 << 9) +#define UARTCR_TXE (1 << 8) +#define UARTCR_EN (1 << 0) + +#define UARTLCR_H_WLEN (3 << 5) + +static void uart_pl011_init(struct uart_chip *chip) +{ + if (chip->divider) { + mmio_write16(chip->base + UARTCR, 0); + while (mmio_read8(chip->base + UARTFR) & UARTFR_BUSY) + cpu_relax(); + mmio_write16(chip->base + UARTIBRD, chip->divider); + mmio_write8(chip->base + UARTLCR_H, UARTLCR_H_WLEN); + mmio_write16(chip->base + UARTCR, UARTCR_EN | UARTCR_TXE | + UARTCR_Out1 | UARTCR_Out2); + } +} + +static bool uart_pl011_is_busy(struct uart_chip *chip) +{ + /* FIFO full or busy */ + return (mmio_read32(chip->base + UARTFR) & + (UARTFR_TXFF | UARTFR_BUSY)) != 0; +} + +static void uart_pl011_write(struct uart_chip *chip, char c) +{ + mmio_write32(chip->base + UARTDR, c); +} + +DEFINE_UART(pl011, "PL011", JAILHOUSE_CON_TYPE_PL011); diff --git a/inmates/lib/arm-common/uart-scif.c b/inmates/lib/arm-common/uart-scif.c new file mode 100644 index 0000000000000000000000000000000000000000..aa15c6f980a43b2a0ba29aac3350968363382ea9 --- /dev/null +++ b/inmates/lib/arm-common/uart-scif.c @@ -0,0 +1,65 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (C) 2022 Renesas Electronics Corp. + * + * Authors: + * Lad Prabhakar + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define SCIF_SCFTDR 0x0c /* Transmit FIFO data register */ +#define SCIF_SCFSR 0x10 /* Serial status register */ +#define SCIF_SCFSR_TDFE 0x20 +#define SCIF_SCFSR_TEND 0x40 + +static void uart_scif_init(struct uart_chip *chip) +{ +} + +static bool uart_scif_is_busy(struct uart_chip *chip) +{ + return (!((SCIF_SCFSR_TDFE | SCIF_SCFSR_TEND) & + mmio_read16(chip->base + SCIF_SCFSR))); +} + +static void uart_scif_write(struct uart_chip *chip, char c) +{ + mmio_write8(chip->base + SCIF_SCFTDR, c); + mmio_write16(chip->base + SCIF_SCFSR, + mmio_read16(chip->base + SCIF_SCFSR) & + ~(SCIF_SCFSR_TDFE | SCIF_SCFSR_TEND)); +} + +DEFINE_UART(scif, "SCIF", JAILHOUSE_CON_TYPE_SCIF); diff --git a/inmates/lib/arm-common/uart-scifa.c b/inmates/lib/arm-common/uart-scifa.c new file mode 100644 index 0000000000000000000000000000000000000000..54dcbab4d93dd6b04ac5faddcc5dc134da52344b --- /dev/null +++ b/inmates/lib/arm-common/uart-scifa.c @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) emtrion GmbH, 2018 + * + * Authors: + * Ruediger Fichter + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define SCIFA_SCABRR 0x04 +#define SCIFA_SCASCR 0x08 +#define SCIFA_SCASSR 0x14 +#define SCIFA_SCAFCR 0x18 +#define SCIFA_SCAFTDR 0x20 + +#define SCIFA_SCASCR_RE 0x0010 +#define SCIFA_SCASCR_TE 0x0020 + +#define SCIFA_SCASSR_TDFE 0x0020 +#define SCIFA_SCASSR_TEND 0x0040 + +#define SCIFA_FIFO_SIZE 64 +#define SCIFA_TTRG_32BYTES 0 + +static void uart_scifa_init(struct uart_chip *chip) +{ + u16 scascr; + + if (chip->divider) { + scascr = mmio_read16(chip->base + SCIFA_SCASCR); + mmio_write16(chip->base + SCIFA_SCASCR, + scascr & ~(SCIFA_SCASCR_TE | SCIFA_SCASCR_RE)); + mmio_write8(chip->base + SCIFA_SCABRR, chip->divider); + mmio_write16(chip->base + SCIFA_SCAFCR, SCIFA_TTRG_32BYTES); + mmio_write16(chip->base + SCIFA_SCASCR, scascr | SCIFA_SCASCR_TE); + } +} + +static bool uart_scifa_is_busy(struct uart_chip *chip) +{ + return !(mmio_read16(chip->base + SCIFA_SCASSR) & SCIFA_SCASSR_TDFE); +} + +static void uart_scifa_write(struct uart_chip *chip, char c) +{ + mmio_write8(chip->base + SCIFA_SCAFTDR, c); + mmio_write16(chip->base + SCIFA_SCASSR, + mmio_read16(chip->base + SCIFA_SCASSR) & + ~(SCIFA_SCASSR_TDFE | SCIFA_SCASSR_TEND)); +} + +DEFINE_UART(scifa, "SCIFA", JAILHOUSE_CON_TYPE_SCIFA); diff --git a/inmates/lib/arm-common/uart-xuartps.c b/inmates/lib/arm-common/uart-xuartps.c new file mode 100644 index 0000000000000000000000000000000000000000..6f1290836c568583d24cea91e6ea37e369be03b6 --- /dev/null +++ b/inmates/lib/arm-common/uart-xuartps.c @@ -0,0 +1,60 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UART_SR 0x2c +#define UART_SR_TXEMPTY 0x8 +#define UART_FIFO 0x30 + +static void uart_xuartps_init(struct uart_chip *chip) +{ +} + +static bool uart_xuartps_is_busy(struct uart_chip *chip) +{ + return !(mmio_read32(chip->base + UART_SR) & UART_SR_TXEMPTY); +} + +static void uart_xuartps_write(struct uart_chip *chip, char c) +{ + mmio_write32(chip->base + UART_FIFO, c); +} + +DEFINE_UART(xuartps, "XUARTPS", JAILHOUSE_CON_TYPE_XUARTPS); diff --git a/inmates/lib/arm-common/uart.c b/inmates/lib/arm-common/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..c03909a81620748895858ab6a78d8e1aa1405d4a --- /dev/null +++ b/inmates/lib/arm-common/uart.c @@ -0,0 +1,63 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +DECLARE_UART(8250); +DECLARE_UART(hscif); +DECLARE_UART(imx); +DECLARE_UART(imx_lpuart); +DECLARE_UART(mvebu); +DECLARE_UART(pl011); +DECLARE_UART(scif); +DECLARE_UART(scifa); +DECLARE_UART(xuartps); + +struct uart_chip *uart_array[] = { + &UART_OPS_NAME(8250), + &UART_OPS_NAME(hscif), + &UART_OPS_NAME(imx), + &UART_OPS_NAME(imx_lpuart), + &UART_OPS_NAME(mvebu), + &UART_OPS_NAME(pl011), + &UART_OPS_NAME(scif), + &UART_OPS_NAME(scifa), + &UART_OPS_NAME(xuartps), + NULL +}; diff --git a/inmates/lib/arm/Makefile b/inmates/lib/arm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d0d00d0d48248b528819b09ce033176ea8cd6dd0 --- /dev/null +++ b/inmates/lib/arm/Makefile @@ -0,0 +1,45 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015, 2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(INMATES_LIB)/Makefile.lib +include $(INMATES_LIB)/../arm-common/Makefile.lib + +always-y := lib.a inmate.lds + +lib-y := $(common-objs-y) +lib-y += header.o diff --git a/inmates/lib/arm/Makefile.lib b/inmates/lib/arm/Makefile.lib new file mode 100644 index 0000000000000000000000000000000000000000..5df2632d0e5ac0ddbd035577191466e7cef9eebe --- /dev/null +++ b/inmates/lib/arm/Makefile.lib @@ -0,0 +1,65 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) ARM Limited, 2014 +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jean-Philippe Brucker +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +LINUXINCLUDE += -I$(INMATES_LIB)/include +LINUXINCLUDE += -I$(INMATES_LIB)/../arm-common/include + +define DECLARE_TARGETS = + _TARGETS = $(1) + always-y := $$(_TARGETS) + # $(NAME-y) NAME-linked.o NAME.bin + targets += $$(foreach t,$$(_TARGETS:.bin=-y),$$($$t)) \ + $$(_TARGETS:.bin=-linked.o) $$(_TARGETS) +endef + +# prevent deleting intermediate files which would cause rebuilds +.SECONDARY: $(addprefix $(obj)/,$(targets)) + +.SECONDEXPANSION: +$(obj)/%-linked.o: $(INMATES_LIB)/inmate.lds $$(addprefix $$(obj)/,$$($$*-y)) \ + $(INMATES_LIB)/lib.a FORCE + $(call if_changed,ld) + +$(obj)/%.bin: $(obj)/%-linked.o FORCE + $(call if_changed,objcopy) diff --git a/inmates/lib/arm/header.S b/inmates/lib/arm/header.S new file mode 100644 index 0000000000000000000000000000000000000000..be1d23a8b95fd7808a6d6806db1f4f9110a42a3f --- /dev/null +++ b/inmates/lib/arm/header.S @@ -0,0 +1,90 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + + .arm + + .section ".boot", "ax" + .align 5 +vectors: + b __reset_entry + b vector_undef + b vector_svc + b vector_pabt + b vector_dabt + b vector_unused + b vector_irq + b vector_fiq + +.macro vector, name + .weak vector_\name + vector_\name: + b . +.endm + vector undef + vector svc + vector pabt + vector dabt + vector unused + vector irq + vector fiq + + .globl __reset_entry +__reset_entry: + ldr r0, =vectors + arm_write_sysreg(VBAR, r0) + + mov r0, #0 + ldr r1, =bss_start + ldr r2, =bss_dwords + cmp r2, #0 + beq 2f + +1: str r0, [r1] + add r1, #4 + subs r2, #1 + bne 1b + +2: ldr sp, =stack_top + + b c_entry + + .ltorg diff --git a/inmates/lib/arm/include/arch/gic.h b/inmates/lib/arm/include/arch/gic.h new file mode 100644 index 0000000000000000000000000000000000000000..0f36edff69849cfe45dd37001f2bdb4f63fe5e2c --- /dev/null +++ b/inmates/lib/arm/include/arch/gic.h @@ -0,0 +1,52 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef __ASSEMBLY__ + +static inline void gic_setup_irq_stack(void) +{ + static __attribute__((aligned(PAGE_SIZE))) u8 irq_stack[PAGE_SIZE]; + + asm volatile ( + ".arch_extension virt\n\t" + "msr SP_irq, %0\n\t" + "cpsie i\n\t" + : : "r" (irq_stack + sizeof(irq_stack))); +} + +#endif /* !__ASSEMBLY__ */ diff --git a/inmates/lib/arm/include/arch/inmate.h b/inmates/lib/arm/include/arch/inmate.h new file mode 100644 index 0000000000000000000000000000000000000000..da70ba71516694b21e923c7af7fc02444e05ac5f --- /dev/null +++ b/inmates/lib/arm/include/arch/inmate.h @@ -0,0 +1,55 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +/* + * 4 L1 translation table entries for arm 32 bit architecture + * indexed from bits [31:30] of virtual address. + */ +#define JAILHOUSE_INMATE_MEM_PAGE_DIR_LEN 4 + +void __attribute__((interrupt("IRQ"), used)) vector_irq(void); + +static inline void enable_irqs(void) +{ + asm volatile("cpsie if"); /* enable IRQs and FIQs */ +} + +static inline void disable_irqs(void) +{ + asm volatile("cpsid if"); /* disable IRQs and FIQs */ +} diff --git a/inmates/lib/arm/include/asm/sysregs.h b/inmates/lib/arm/include/asm/sysregs.h new file mode 100644 index 0000000000000000000000000000000000000000..ae61155dbc1db48eacbc84199216eab5b09c0406 --- /dev/null +++ b/inmates/lib/arm/include/asm/sysregs.h @@ -0,0 +1,119 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +/* The following definitions are inspired by + * hypervisor/arch/arm/include/asm/sysregs.h */ + +#define VBAR SYSREG_32(0, c12, c0, 0) +#define CNTFRQ_EL0 SYSREG_32(0, c14, c0, 0) +#define CNTV_TVAL_EL0 SYSREG_32(0, c14, c3, 0) +#define CNTV_CTL_EL0 SYSREG_32(0, c14, c3, 1) +#define CNTPCT_EL0 SYSREG_64(0, c14) + +#define SCTLR SYSREG_32(0, c1, c0, 0) +#define SCTLR_RR (1 << 14) +#define SCTLR_I (1 << 12) +#define SCTLR_C (1 << 2) +#define SCTLR_M (1 << 0) + +/* Enable MMU, round-robin replacement, data+instruction caches */ +#define SCTLR_MMU_CACHES (SCTLR_RR | SCTLR_I | SCTLR_C | SCTLR_M) + +#define TTBR0 SYSREG_32(0, c2, c0, 0) +#define TTBCR SYSREG_32(0, c2, c0, 2) +#define TTBCR_IRGN0_WB_WA (1 << 8) +#define TTBCR_ORGN0_WB_WA (1 << 10) +#define TTBCR_SH0_INNER_SHAREABLE (3 << 12) +#define TTBCR_EAE (1 << 31) + +/* + * Enable extended address enable and set inner/outer caches to write-back + * write-allocate cacheable and shareability attribute to inner shareable + */ +#define TRANSL_CONT_REG TTBCR +#define TRANSL_CONT_REG_SETTINGS \ + TTBCR_EAE | TTBCR_IRGN0_WB_WA | TTBCR_ORGN0_WB_WA | \ + TTBCR_SH0_INNER_SHAREABLE + +#define MAIR0 SYSREG_32(0, c10, c2, 0) +#define MAIR1 SYSREG_32(0, c10, c2, 1) + +#define MAIR MAIR0 + +#define MPIDR SYSREG_32(0, c0, c0, 5) + +#define MPIDR_CPUID_MASK 0x00ffffff + +#define MPIDR_LEVEL_BITS 8 +#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) +#define MPIDR_LEVEL_SHIFT(level) (MPIDR_LEVEL_BITS * (level)) + +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ + (((mpidr) >> (MPIDR_LEVEL_BITS * (level))) & MPIDR_LEVEL_MASK) + +#define SYSREG_32(...) 32, __VA_ARGS__ +#define SYSREG_64(...) 64, __VA_ARGS__ + +#define _arm_write_sysreg(size, ...) arm_write_sysreg_ ## size(__VA_ARGS__) +#define arm_write_sysreg(...) _arm_write_sysreg(__VA_ARGS__) + +#define _arm_read_sysreg(size, ...) arm_read_sysreg_ ## size(__VA_ARGS__) +#define arm_read_sysreg(...) _arm_read_sysreg(__VA_ARGS__) + +#include + +#ifndef __ASSEMBLY__ +asm(".arch_extension virt\n"); + +#define arm_write_sysreg_32(op1, crn, crm, op2, val) \ + asm volatile ("mcr p15, "#op1", %0, "#crn", "#crm", "#op2"\n" \ + : : "r" ((u32)(val))) + +#define arm_read_sysreg_32(op1, crn, crm, op2, val) \ + asm volatile ("mrc p15, "#op1", %0, "#crn", "#crm", "#op2"\n" \ + : "=r" ((u32)(val))) +#define arm_read_sysreg_64(op1, crm, val) \ + asm volatile ("mrrc p15, "#op1", %Q0, %R0, "#crm"\n" \ + : "=r" ((u64)(val))) + +#else /* __ASSEMBLY__ */ + +#define arm_write_sysreg_32(op1, crn, crm, op2, reg) \ + mcr p15, op1, reg, crn, crm, op2 + +#endif /* __ASSEMBLY__ */ diff --git a/inmates/lib/arm/inmate.lds.S b/inmates/lib/arm/inmate.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..48652c24e7550ae59440e37d55cafb52f2f2c468 --- /dev/null +++ b/inmates/lib/arm/inmate.lds.S @@ -0,0 +1,78 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +SECTIONS { + . = CONFIG_INMATE_BASE; + .boot : { *(.boot) } + + . = CONFIG_INMATE_BASE + 0x1000; + .cmdline : { + *(.cmdline) + BYTE(0); /* empty string in case no buffer is provided */ + } + + . = ALIGN(4); + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + bss_start = .; + *(.bss) + . = ALIGN(4); + } + bss_dwords = SIZEOF(.bss) / 4; + + . = ALIGN(4096); + . += 0x1000; + stack_top = .; +} + +ENTRY(__reset_entry) diff --git a/inmates/lib/arm64/Makefile b/inmates/lib/arm64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b6b83b38e3d9485dd94c53f55a03f13379f5a1b --- /dev/null +++ b/inmates/lib/arm64/Makefile @@ -0,0 +1,45 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(INMATES_LIB)/Makefile.lib +include $(INMATES_LIB)/../arm-common/Makefile.lib + +always-y := lib.a inmate.lds + +lib-y := $(common-objs-y) +lib-y += header.o diff --git a/inmates/lib/arm64/Makefile.lib b/inmates/lib/arm64/Makefile.lib new file mode 100644 index 0000000000000000000000000000000000000000..5df2632d0e5ac0ddbd035577191466e7cef9eebe --- /dev/null +++ b/inmates/lib/arm64/Makefile.lib @@ -0,0 +1,65 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) ARM Limited, 2014 +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jean-Philippe Brucker +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +LINUXINCLUDE += -I$(INMATES_LIB)/include +LINUXINCLUDE += -I$(INMATES_LIB)/../arm-common/include + +define DECLARE_TARGETS = + _TARGETS = $(1) + always-y := $$(_TARGETS) + # $(NAME-y) NAME-linked.o NAME.bin + targets += $$(foreach t,$$(_TARGETS:.bin=-y),$$($$t)) \ + $$(_TARGETS:.bin=-linked.o) $$(_TARGETS) +endef + +# prevent deleting intermediate files which would cause rebuilds +.SECONDARY: $(addprefix $(obj)/,$(targets)) + +.SECONDEXPANSION: +$(obj)/%-linked.o: $(INMATES_LIB)/inmate.lds $$(addprefix $$(obj)/,$$($$*-y)) \ + $(INMATES_LIB)/lib.a FORCE + $(call if_changed,ld) + +$(obj)/%.bin: $(obj)/%-linked.o FORCE + $(call if_changed,objcopy) diff --git a/inmates/lib/arm64/header.S b/inmates/lib/arm64/header.S new file mode 100644 index 0000000000000000000000000000000000000000..79f306b123a8594ee54ce44764244de43a2dcc96 --- /dev/null +++ b/inmates/lib/arm64/header.S @@ -0,0 +1,129 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +.macro ventry label + .align 7 + b \label +.endm + + .section ".boot", "ax" + .globl __reset_entry +__reset_entry: + ldr x0, =vectors + msr vbar_el1, x0 + + ldr x0, =stack_top + mov sp, x0 + + mov x0, #(3 << 20) + msr cpacr_el1, x0 + + msr daif, xzr + + isb + + b c_entry + +handle_irq: + sub sp, sp, #(16 * 16) + stp x0, x1, [sp, #(0 * 16)] + stp x2, x3, [sp, #(1 * 16)] + stp x4, x5, [sp, #(2 * 16)] + stp x6, x7, [sp, #(3 * 16)] + stp x8, x9, [sp, #(4 * 16)] + stp x10, x11, [sp, #(5 * 16)] + stp x12, x13, [sp, #(6 * 16)] + stp x14, x15, [sp, #(7 * 16)] + stp x16, x17, [sp, #(8 * 16)] + stp x18, x19, [sp, #(9 * 16)] + stp x20, x21, [sp, #(10 * 16)] + stp x22, x23, [sp, #(11 * 16)] + stp x24, x25, [sp, #(12 * 16)] + stp x26, x27, [sp, #(13 * 16)] + stp x28, x29, [sp, #(14 * 16)] + str x30, [sp, #(15 * 16)] + + bl vector_irq + + ldp x0, x1, [sp, #(0 * 16)] + ldp x2, x3, [sp, #(1 * 16)] + ldp x4, x5, [sp, #(2 * 16)] + ldp x6, x7, [sp, #(3 * 16)] + ldp x8, x9, [sp, #(4 * 16)] + ldp x10, x11, [sp, #(5 * 16)] + ldp x12, x13, [sp, #(6 * 16)] + ldp x14, x15, [sp, #(7 * 16)] + ldp x16, x17, [sp, #(8 * 16)] + ldp x18, x19, [sp, #(9 * 16)] + ldp x20, x21, [sp, #(10 * 16)] + ldp x22, x23, [sp, #(11 * 16)] + ldp x24, x25, [sp, #(12 * 16)] + ldp x26, x27, [sp, #(13 * 16)] + ldp x28, x29, [sp, #(14 * 16)] + ldr x30, [sp, #(15 * 16)] + add sp, sp, #(16 * 16) + + eret + +.weak vector_irq + b . + + .globl vectors + .align 11 +vectors: + ventry . + ventry . + ventry . + ventry . + + ventry . + ventry handle_irq + ventry . + ventry . + + ventry . + ventry handle_irq + ventry . + ventry . + + ventry . + ventry . + ventry . + ventry . + + .ltorg diff --git a/inmates/lib/arm64/include/arch/gic.h b/inmates/lib/arm64/include/arch/gic.h new file mode 100644 index 0000000000000000000000000000000000000000..80720664a1b11fe899cc7797e83ddcfd61b9cfb6 --- /dev/null +++ b/inmates/lib/arm64/include/arch/gic.h @@ -0,0 +1,39 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define gic_setup_irq_stack() diff --git a/inmates/lib/arm64/include/arch/inmate.h b/inmates/lib/arm64/include/arch/inmate.h new file mode 100644 index 0000000000000000000000000000000000000000..a85b98f585ffd094f1638dc275cad5dd2db523db --- /dev/null +++ b/inmates/lib/arm64/include/arch/inmate.h @@ -0,0 +1,55 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * + * Authors: + * Jean-Philippe Brucker + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +/* + * 512 L1 translation table entries for arm64 bit architecture + * indexed from bits [38:30] of virtual address. + */ +#define JAILHOUSE_INMATE_MEM_PAGE_DIR_LEN 512 + +void __attribute__((used)) vector_irq(void); + +static inline void enable_irqs(void) +{ + asm volatile("msr daifclr, #3"); /* enable IRQs and FIQs */ +} + +static inline void disable_irqs(void) +{ + asm volatile("msr daifset, #3"); /* disable IRQs and FIQs */ +} diff --git a/inmates/lib/arm64/include/asm/sysregs.h b/inmates/lib/arm64/include/asm/sysregs.h new file mode 100644 index 0000000000000000000000000000000000000000..fe6cb45bb814e7dda21b4505fa65cc2622ba0cf2 --- /dev/null +++ b/inmates/lib/arm64/include/asm/sysregs.h @@ -0,0 +1,101 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2017 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +/* The following definitions are inspired by + * hypervisor/arch/arm64/include/asm/sysregs.h */ + +#ifndef __ASSEMBLY__ + +#include + +#define SCTLR_EL1_I (1 << 12) +#define SCTLR_EL1_C (1 << 2) +#define SCTLR_EL1_M (1 << 0) + +#define SCTLR SCTLR_EL1 + +/* Enable MMU, data+instruction caches */ +#define SCTLR_MMU_CACHES (SCTLR_EL1_I | SCTLR_EL1_C | SCTLR_EL1_M) + +#define TCR_EL1_T0SZ_25 25 +#define TCR_EL1_IRGN0_WBWAC (0x1 << 8) +#define TCR_EL1_ORGN0_WBWAC (0x1 << 10) +#define TCR_EL1_SH0_IS (0x3 << 12) +#define TCR_EL1_TG0_4K (0x0 << 14) +#define TCR_EL1_IPC_256TB (0x5UL << 32) + +/* + * IPA size 48bit (256TiB), 4KiB granularity, and set inner/outer caches to + * write-back write-allocate cacheable and shareability attribute to inner + * shareable + */ +#define TRANSL_CONT_REG TCR_EL1 +#define TRANSL_CONT_REG_SETTINGS \ + TCR_EL1_IPC_256TB | TCR_EL1_TG0_4K | TCR_EL1_SH0_IS | \ + TCR_EL1_ORGN0_WBWAC | TCR_EL1_IRGN0_WBWAC | TCR_EL1_T0SZ_25 + +#define MAIR MAIR_EL1 + +#define TTBR0 TTBR0_EL1 + +#define MPIDR MPIDR_EL1 + +#define MPIDR_CPUID_MASK 0xff00ffffffUL + +#define MPIDR_LEVEL_BITS_SHIFT 3 +#define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT) +#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) + +#define MPIDR_LEVEL_SHIFT(level) \ + (((1 << (level)) >> 1) << MPIDR_LEVEL_BITS_SHIFT) + +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ + (((mpidr) >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK) + +#define SYSREG_32(op1, crn, crm, op2) s3_##op1 ##_##crn ##_##crm ##_##op2 + +#define arm_write_sysreg(sysreg, val) \ + asm volatile ("msr "__stringify(sysreg)", %0\n" \ + : : "r" ((u64)(val))) + +#define arm_read_sysreg(sysreg, val) \ + asm volatile ("mrs %0, "__stringify(sysreg)"\n" : "=r" ((val))) + +#include + +#endif /* __ASSEMBLY__ */ diff --git a/inmates/lib/arm64/inmate.lds.S b/inmates/lib/arm64/inmate.lds.S new file mode 100644 index 0000000000000000000000000000000000000000..d01115106c75edf186331c70a7911dd6efc2cafc --- /dev/null +++ b/inmates/lib/arm64/inmate.lds.S @@ -0,0 +1,74 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Antonios Motakis + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +SECTIONS { + . = CONFIG_INMATE_BASE; + .boot : { *(.boot) } + + . = CONFIG_INMATE_BASE + 0x1000; + .cmdline : { + *(.cmdline) + BYTE(0); /* empty string in case no buffer is provided */ + } + + bss_start = .; + .bss : { + *(.bss) + } + + . = ALIGN(4); + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + . = ALIGN(4096); + . = . + 0x1000; + stack_top = .; +} + +ENTRY(__reset_entry) diff --git a/inmates/lib/cmdline.c b/inmates/lib/cmdline.c new file mode 100644 index 0000000000000000000000000000000000000000..94a79d7f9a8cdedf17365eddf140952354cdc8cd --- /dev/null +++ b/inmates/lib/cmdline.c @@ -0,0 +1,149 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define CMDLINE_BUFFER_SIZE 256 +CMDLINE_BUFFER(CMDLINE_BUFFER_SIZE) __attribute__((weak)); + +static bool get_param(const char *param, char *value_buffer, + unsigned long buffer_size) +{ + unsigned long param_len = strlen(param); + const char *p = cmdline; + + while (1) { + /* read over leading blanks */ + while (*p == ' ') + p++; + + if (strncmp(p, param, param_len) == 0) { + p += param_len; + + *value_buffer = 0; + /* extract parameter value */ + if (*p == '=') { + p++; + while (buffer_size > 1) { + if (*p == ' ' || *p == 0) + break; + *value_buffer++ = *p++; + buffer_size--; + } + if (buffer_size > 0) + *value_buffer = 0; + } + return true; + } + + /* search for end of this parameter */ + while (*p != ' ') { + if (*p == 0) + return false; + p++; + } + } +} + +const char *cmdline_parse_str(const char *param, char *value_buffer, + unsigned long buffer_size, + const char *default_value) +{ + if (get_param(param, value_buffer, buffer_size)) + return value_buffer; + else + return default_value; +} + +long long cmdline_parse_int(const char *param, long long default_value) +{ + char value_buffer[32]; + char *p = value_buffer; + bool negative = false; + long long value = 0; + + if (!get_param(param, value_buffer, sizeof(value_buffer))) + return default_value; + + if (strncmp(p, "0x", 2) == 0) { + p += 2; + do { + if (*p >= '0' && *p <= '9') + value = (value << 4) + *p - '0'; + else if (*p >= 'A' && *p <= 'F') + value = (value << 4) + *p - 'A' + 10; + else if (*p >= 'a' && *p <= 'f') + value = (value << 4) + *p - 'a' + 10; + else + return default_value; + p++; + } while (*p != 0); + } else { + if (*p == '-' || *p == '+') + negative = (*p++ == '-'); + + do { + if (*p >= '0' && *p <= '9') + value = (value * 10) + *p - '0'; + else + return default_value; + p++; + } while (*p != 0); + } + + return negative ? -value : value; +} + +bool cmdline_parse_bool(const char *param, bool default_value) +{ + char value_buffer[8]; + + /* return the default value if the parameter is not provided */ + if (!get_param(param, value_buffer, sizeof(value_buffer))) + return default_value; + + if (!strncasecmp(value_buffer, "true", 4) || + !strncmp(value_buffer, "1", 1) || strlen(value_buffer) == 0) + return true; + + if (!strncasecmp(value_buffer, "false", 5) || + !strncmp(value_buffer, "0", 1)) + return false; + + return default_value; +} diff --git a/inmates/lib/include/inmate_common.h b/inmates/lib/include/inmate_common.h new file mode 100644 index 0000000000000000000000000000000000000000..1c20a0afcd0b15f986e47ab7cefedc6841d35374 --- /dev/null +++ b/inmates/lib/include/inmate_common.h @@ -0,0 +1,150 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef CONFIG_INMATE_BASE +#define CONFIG_INMATE_BASE 0x0 +#endif + +#define NULL ((void *)0) + +#define NS_PER_USEC 1000ULL +#define NS_PER_MSEC 1000000ULL +#define NS_PER_SEC 1000000000ULL + +#define PCI_CFG_VENDOR_ID 0x000 +#define PCI_CFG_DEVICE_ID 0x002 +#define PCI_CFG_COMMAND 0x004 +# define PCI_CMD_IO (1 << 0) +# define PCI_CMD_MEM (1 << 1) +# define PCI_CMD_MASTER (1 << 2) +# define PCI_CMD_INTX_OFF (1 << 10) +#define PCI_CFG_STATUS 0x006 +# define PCI_STS_INT (1 << 3) +# define PCI_STS_CAPS (1 << 4) +#define PCI_CFG_BAR 0x010 +# define PCI_BAR_64BIT 0x4 +#define PCI_CFG_CAP_PTR 0x034 + +#define PCI_ID_ANY 0xffff + +#define PCI_DEV_CLASS_OTHER 0xff + +#define PCI_CAP_MSI 0x05 +#define PCI_CAP_VENDOR 0x09 +#define PCI_CAP_MSIX 0x11 + +#define MSIX_CTRL_ENABLE 0x8000 +#define MSIX_CTRL_FMASK 0x4000 + +#ifndef __ASSEMBLY__ +typedef s8 __s8; +typedef u8 __u8; + +typedef s16 __s16; +typedef u16 __u16; + +typedef s32 __s32; +typedef u32 __u32; + +typedef s64 __s64; +typedef u64 __u64; + +typedef enum { true = 1, false = 0 } bool; + +#include + +#define comm_region ((struct jailhouse_comm_region *)COMM_REGION_BASE) + +static inline void __attribute__((noreturn)) stop(void) +{ + disable_irqs(); + halt(); +} + +void arch_init_early(void); + +void __attribute__((format(printf, 1, 2))) printk(const char *fmt, ...); + +extern unsigned long heap_pos; + +void *alloc(unsigned long size, unsigned long align); +void *zalloc(unsigned long size, unsigned long align); + +void *memset(void *s, int c, unsigned long n); +void *memcpy(void *d, const void *s, unsigned long n); +int memcmp(const void *s1, const void *s2, unsigned long n); +unsigned long strlen(const char *s); +int strncmp(const char *s1, const char *s2, unsigned long n); +int strcmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, unsigned long n); + +const char *cmdline_parse_str(const char *param, char *value_buffer, + unsigned long buffer_size, + const char *default_value); +long long cmdline_parse_int(const char *param, long long default_value); +bool cmdline_parse_bool(const char *param, bool default_value); + +enum map_type { MAP_CACHED, MAP_UNCACHED }; + +void map_range(void *start, unsigned long size, enum map_type map_type); + +typedef void(*irq_handler_t)(unsigned int); + +void irq_init(irq_handler_t handler); +void irq_enable(unsigned int irq); + +void pci_init(void); +u32 pci_read_config(u16 bdf, unsigned int addr, unsigned int size); +void pci_write_config(u16 bdf, unsigned int addr, u32 value, + unsigned int size); +int pci_find_device(u16 vendor, u16 device, u16 start_bdf); +int pci_find_cap(u16 bdf, u16 cap); +void pci_msi_set_vector(u16 bdf, unsigned int vector); +void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index); + +void delay_us(unsigned long microsecs); + +#define CMDLINE_BUFFER(size) \ + const char cmdline[size] __attribute__((section(".cmdline"))) + +extern const char cmdline[]; +extern const char stack_top[]; + +void inmate_main(void); + +#endif /* !__ASSEMBLY__ */ diff --git a/inmates/lib/include/stdarg.h b/inmates/lib/include/stdarg.h new file mode 100644 index 0000000000000000000000000000000000000000..21e588502c34da8fd538435d6e62f6decbed8817 --- /dev/null +++ b/inmates/lib/include/stdarg.h @@ -0,0 +1,43 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2022 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +typedef __builtin_va_list va_list; + +#define va_start(ap, last) __builtin_va_start(ap, last) +#define va_arg(ap, type) __builtin_va_arg(ap, type) +#define va_end(ap) __builtin_va_end(ap) diff --git a/inmates/lib/include/string.h b/inmates/lib/include/string.h new file mode 100644 index 0000000000000000000000000000000000000000..29f5e2dbe9fa19e17bfc50e27327ef307344bd00 --- /dev/null +++ b/inmates/lib/include/string.h @@ -0,0 +1,40 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define __stringify_1(x...) #x +#define __stringify(x...) __stringify_1(x) diff --git a/inmates/lib/include/test.h b/inmates/lib/include/test.h new file mode 100644 index 0000000000000000000000000000000000000000..49ce152d3e6b04015591f79485beff12e0f21958 --- /dev/null +++ b/inmates/lib/include/test.h @@ -0,0 +1,18 @@ +/* + * + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#define EXPECT_EQUAL(a, b) __evaluate(a, b, __LINE__) + +extern bool all_passed; + +void __evaluate(u64 a, u64 b, int line); diff --git a/inmates/lib/include/uart.h b/inmates/lib/include/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..c76e9d268fdb393180c87169df24a12bb31311ec --- /dev/null +++ b/inmates/lib/include/uart.h @@ -0,0 +1,76 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2016-2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +struct uart_chip { + const char *name; + const __u16 type; + + void *base; + unsigned int divider; + + void (*reg_out)(struct uart_chip *chip, unsigned int reg, u32 value); + u32 (*reg_in)(struct uart_chip *chip, unsigned int reg); + + void (*init)(struct uart_chip*); + bool (*is_busy)(struct uart_chip*); + void (*write)(struct uart_chip*, char c); +}; + +extern struct uart_chip *uart_array[]; + +#define UART_OPS_NAME(__name) \ + uart_##__name##_ops + +#define DECLARE_UART(__name) \ + extern struct uart_chip UART_OPS_NAME(__name) + +#define DEFINE_UART_REG(__name, __description, __type, __reg_out, __reg_in) \ + struct uart_chip UART_OPS_NAME(__name) = { \ + .name = __description, \ + .type = __type, \ + .init = uart_##__name##_init, \ + .is_busy = uart_##__name##_is_busy, \ + .write = uart_##__name##_write, \ + .reg_out = __reg_out, \ + .reg_in = __reg_in, \ + } + +#define DEFINE_UART(__name, __description, __type) \ + DEFINE_UART_REG(__name, __description, __type, NULL, NULL) + +void arch_console_init(struct uart_chip *chip); diff --git a/inmates/lib/pci.c b/inmates/lib/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..a8d77c2cdd56244256a5b8f7c300670dcd97dbae --- /dev/null +++ b/inmates/lib/pci.c @@ -0,0 +1,71 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +int pci_find_device(u16 vendor, u16 device, u16 start_bdf) +{ + unsigned int bdf; + u16 id; + + for (bdf = start_bdf; bdf < 0x10000; bdf++) { + id = pci_read_config(bdf, PCI_CFG_VENDOR_ID, 2); + if (id == PCI_ID_ANY || (vendor != PCI_ID_ANY && vendor != id)) + continue; + if (device == PCI_ID_ANY || + pci_read_config(bdf, PCI_CFG_DEVICE_ID, 2) == device) + return bdf; + } + return -1; +} + +int pci_find_cap(u16 bdf, u16 cap) +{ + u8 pos = PCI_CFG_CAP_PTR - 1; + + if (!(pci_read_config(bdf, PCI_CFG_STATUS, 2) & PCI_STS_CAPS)) + return -1; + + while (1) { + pos = pci_read_config(bdf, pos + 1, 1); + if (pos == 0) + return -1; + if (pci_read_config(bdf, pos, 1) == cap) + return pos; + } +} diff --git a/inmates/lib/printk.c b/inmates/lib/printk.c new file mode 100644 index 0000000000000000000000000000000000000000..712a9b44ec9e2bd947764f5b7364c4fba38dac89 --- /dev/null +++ b/inmates/lib/printk.c @@ -0,0 +1,340 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) OTH Regensburg, 2018 + * Copyright (c) Siemens AG, 2013-2020 + * + * Authors: + * Jean-Philippe Brucker + * Ralf Ramsauer + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include +#include + +#define UART_IDLE_LOOPS 100 + +static struct uart_chip *chip; +static bool virtual_console; + +static void console_write_char(char c) +{ + if (chip) { + while (chip->is_busy(chip)) + cpu_relax(); + chip->write(chip, c); + } + + if (virtual_console) + jailhouse_call_arg1(JAILHOUSE_HC_DEBUG_CONSOLE_PUTC, c); +} + +static void console_write(const char *msg) +{ + char c; + + if (!chip && !virtual_console) + return; + + while (1) { + c = *msg++; + if (!c) + break; + + if (c == '\n') + console_write_char('\r'); + + console_write_char(c); + } +} + +static void console_init(void) +{ + struct jailhouse_console *console = &comm_region->console; + unsigned int n; + struct uart_chip **c; + const char *type; + char buf[32]; + + if (JAILHOUSE_COMM_HAS_DBG_PUTC_PERMITTED(comm_region->flags)) + virtual_console = cmdline_parse_bool("con-virtual", + JAILHOUSE_COMM_HAS_DBG_PUTC_ACTIVE(comm_region->flags)); + + type = cmdline_parse_str("con-type", buf, sizeof(buf), ""); + for (c = uart_array; *c; c++) + if (!strcmp(type, (*c)->name) || + (!*type && console->type == (*c)->type)) { + chip = *c; + break; + } + + if (!chip) + return; + + chip->base = (void *)(unsigned long) + cmdline_parse_int("con-base", console->address); + chip->divider = cmdline_parse_int("con-divider", console->divider); + + /* Do architecture specific initialisation, e.g., setting PIO accessors + * for x86 or enable clocks for ARM */ + arch_console_init(chip); + + chip->init(chip); + + if (chip->divider == 0) { + /* + * We share the UART with the hypervisor. Make sure all + * its outputs are done before starting. + */ + do { + for (n = 0; n < UART_IDLE_LOOPS; n++) + if (chip->is_busy(chip)) + break; + } while (n < UART_IDLE_LOOPS); + } +} + +#if BITS_PER_LONG < 64 + +static unsigned long long div_u64_u64(unsigned long long dividend, + unsigned long long divisor) +{ + unsigned long long result = 0; + unsigned long long tmp_res, tmp_div; + + while (dividend >= divisor) { + tmp_div = divisor << 1; + tmp_res = 1; + while (dividend >= tmp_div) { + tmp_res <<= 1; + if (tmp_div & (1ULL << 63)) + break; + tmp_div <<= 1; + } + dividend -= divisor * tmp_res; + result += tmp_res; + } + return result; +} + +#else /* BITS_PER_LONG >= 64 */ + +static inline unsigned long long div_u64_u64(unsigned long long dividend, + unsigned long long divisor) +{ + return dividend / divisor; +} + +#endif /* BITS_PER_LONG >= 64 */ + +static char *uint2str(unsigned long long value, char *buf) +{ + unsigned long long digit, divisor = 10000000000000000000ULL; + int first_digit = 1; + + while (divisor > 0) { + digit = div_u64_u64(value, divisor); + value -= digit * divisor; + if (!first_digit || digit > 0 || divisor == 1) { + *buf++ = '0' + digit; + first_digit = 0; + } + divisor = div_u64_u64(divisor, 10); + } + + return buf; +} + +static char *int2str(long long value, char *buf) +{ + if (value < 0) { + *buf++ = '-'; + value = -value; + } + return uint2str(value, buf); +} + +static char *hex2str(unsigned long long value, char *buf, + unsigned long long leading_zero_mask) +{ + static const char hexdigit[] = "0123456789abcdef"; + unsigned long long digit, divisor = 0x1000000000000000ULL; + int first_digit = 1; + + while (divisor > 0) { + digit = div_u64_u64(value, divisor); + value -= digit * divisor; + if (!first_digit || digit > 0 || divisor == 1 || + divisor & leading_zero_mask) { + *buf++ = hexdigit[digit]; + first_digit = 0; + } + divisor >>= 4; + } + + return buf; +} + +static char *align(char *p1, char *p0, unsigned int width, char fill) +{ + unsigned int n; + + /* Note: p1 > p0 here */ + if ((unsigned int)(p1 - p0) >= width) + return p1; + + for (n = 1; p1 - n >= p0; n++) + *(p0 + width - n) = *(p1 - n); + memset(p0, fill, width - (p1 - p0)); + return p0 + width; +} + +static void __vprintk(const char *fmt, va_list ap) +{ + char buf[128]; + char *p, *p0; + char c, fill; + unsigned long long v; + unsigned int width; + enum {SZ_NORMAL, SZ_LONG, SZ_LONGLONG} length; + + p = buf; + + while (1) { + c = *fmt++; + if (c == 0) { + break; + } else if (c == '%') { + *p = 0; + console_write(buf); + p = buf; + + c = *fmt++; + + width = 0; + p0 = p; + fill = (c == '0') ? '0' : ' '; + while (c >= '0' && c <= '9') { + width = width * 10 + c - '0'; + c = *fmt++; + if (width >= sizeof(buf) - 1) + width = 0; + } + + length = SZ_NORMAL; + if (c == 'l') { + length = SZ_LONG; + c = *fmt++; + if (c == 'l') { + length = SZ_LONGLONG; + c = *fmt++; + } + } + + switch (c) { + case 'c': + *p++ = (unsigned char)va_arg(ap, int); + break; + case 'd': + if (length == SZ_LONGLONG) + v = va_arg(ap, long long); + else if (length == SZ_LONG) + v = va_arg(ap, long); + else + v = va_arg(ap, int); + p = int2str(v, p); + p = align(p, p0, width, fill); + break; + case 'p': + *p++ = '0'; + *p++ = 'x'; + v = va_arg(ap, unsigned long); + p = hex2str(v, p, (unsigned long)-1); + break; + case 's': + console_write(va_arg(ap, const char *)); + break; + case 'u': + case 'x': + if (length == SZ_LONGLONG) + v = va_arg(ap, unsigned long long); + else if (length == SZ_LONG) + v = va_arg(ap, unsigned long); + else + v = va_arg(ap, unsigned int); + if (c == 'u') + p = uint2str(v, p); + else + p = hex2str(v, p, 0); + p = align(p, p0, width, fill); + break; + case '%': + *p++ = c; + break; + default: + *p++ = '%'; + *p++ = c; + break; + } + } else { + *p++ = c; + } + if (p >= &buf[sizeof(buf) - 1]) { + *p = 0; + console_write(buf); + p = buf; + } + } + + *p = 0; + console_write(buf); +} + +void printk(const char *fmt, ...) +{ + static bool inited = false; + va_list ap; + + if (!inited) { + console_init(); + inited = true; + } + + va_start(ap, fmt); + + __vprintk(fmt, ap); + + va_end(ap); +} diff --git a/inmates/lib/setup.c b/inmates/lib/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..4d007322256a3730e935a6c37e549d897f882328 --- /dev/null +++ b/inmates/lib/setup.c @@ -0,0 +1,56 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ +#include + +void __attribute__((noreturn)) c_entry(void); + +void __attribute__((noreturn)) c_entry(void) +{ + arch_init_early(); + + /* check if the ABI version of the communication region matches */ + if (comm_region->revision != COMM_REGION_ABI_REVISION || + memcmp(comm_region->signature, COMM_REGION_MAGIC, + sizeof(comm_region->signature))) { + comm_region->cell_state = JAILHOUSE_CELL_FAILED_COMM_REV; + } else { + inmate_main(); + } + + stop(); +} diff --git a/inmates/lib/string.c b/inmates/lib/string.c new file mode 100644 index 0000000000000000000000000000000000000000..d3ba5abcd8009827eb1d9829179d0ff0ed3da4ee --- /dev/null +++ b/inmates/lib/string.c @@ -0,0 +1,121 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +static inline int tolower(int c) +{ + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; +} + +void *memcpy(void *dest, const void *src, unsigned long n) +{ + const u8 *s = src; + u8 *d = dest; + + while (n-- > 0) + *d++ = *s++; + return dest; +} + +void *memset(void *s, int c, unsigned long n) +{ + u8 *p = s; + + while (n-- > 0) + *p++ = c; + return s; +} + +int memcmp(const void *s1, const void *s2, unsigned long n) +{ + const unsigned char *_s1 = s1, *_s2 = s2; + + while (n-- > 0) + if (*_s1++ != *_s2++) + return _s1[-1] < _s2[-1] ? -1 : 1; + return 0; +} + +unsigned long strlen(const char *s1) +{ + unsigned long len = 0; + + while (*s1++) + len++; + + return len; +} + +int strncmp(const char *s1, const char *s2, unsigned long n) +{ + int diff; + + while (n-- > 0) { + diff = *s1 - *s2; + if (diff) + return diff; + if (*s1 == 0) + break; + s1++; + s2++; + } + return 0; +} + +int strcmp(const char *s1, const char *s2) +{ + return strncmp(s1, s2, -1); +} + +int strncasecmp(const char *s1, const char *s2, unsigned long n) +{ + int diff; + + while (n-- > 0) { + diff = tolower(*s1) - tolower(*s2); + if (diff) + return diff; + if (*s1 == 0) + break; + s1++; + s2++; + } + + return 0; +} diff --git a/inmates/lib/test.c b/inmates/lib/test.c new file mode 100644 index 0000000000000000000000000000000000000000..808e2b4fd90ef232079b19f3126c0d84e9baebf4 --- /dev/null +++ b/inmates/lib/test.c @@ -0,0 +1,28 @@ +/* + * + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +bool all_passed = true; + +void __evaluate(u64 a, u64 b, int line) +{ + bool passed = (a == b); + + printk("Test at line #%d %s\n", line, passed ? "passed" : "FAILED"); + if (!passed) { + printk(" %llx != %llx\n", (u64)a, (u64)b); + all_passed = false; + } +} diff --git a/inmates/lib/uart-8250.c b/inmates/lib/uart-8250.c new file mode 100644 index 0000000000000000000000000000000000000000..5492e065b420a47c4ceaa10bc234e7e83a8dd9f1 --- /dev/null +++ b/inmates/lib/uart-8250.c @@ -0,0 +1,87 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) ARM Limited, 2014 + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jean-Philippe Brucker + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +#define UART_TX 0x0 +#define UART_DLL 0x0 +#define UART_DLM 0x1 +#define UART_LCR 0x3 +#define UART_LCR_8N1 0x03 +#define UART_LCR_DLAB 0x80 +#define UART_LSR 0x5 +#define UART_LSR_THRE 0x20 +#define UART_MDR1 0x8 + +static void reg_out_mmio32(struct uart_chip *chip, unsigned int reg, u32 value) +{ + mmio_write32(chip->base + reg * 4, value); +} + +static u32 reg_in_mmio32(struct uart_chip *chip, unsigned int reg) +{ + return mmio_read32(chip->base + reg * 4); +} + +static void uart_8250_init(struct uart_chip *chip) +{ + if (chip->divider) { + chip->reg_out(chip, UART_LCR, UART_LCR_DLAB); + chip->reg_out(chip, UART_DLL, chip->divider); + chip->reg_out(chip, UART_DLM, 0); + chip->reg_out(chip, UART_LCR, UART_LCR_8N1); + if (CON_HAS_MDR_QUIRK(comm_region->console.flags)) + chip->reg_out(chip, UART_MDR1, 0); + } +} + +static bool uart_8250_is_busy(struct uart_chip *chip) +{ + return !(chip->reg_in(chip, UART_LSR) & UART_LSR_THRE); +} + +static void uart_8250_write(struct uart_chip *chip, char c) +{ + chip->reg_out(chip, UART_TX, c); +} + +DEFINE_UART_REG(8250, "8250", JAILHOUSE_CON_TYPE_8250, + reg_out_mmio32, reg_in_mmio32); diff --git a/inmates/lib/x86/Makefile b/inmates/lib/x86/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..06a84ecf3cb3f14f87dfb2a55cdf56e9e81c749a --- /dev/null +++ b/inmates/lib/x86/Makefile @@ -0,0 +1,71 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015, 2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(INMATES_LIB)/Makefile.lib + +always-y := lib.a lib32.a + +TARGETS := cpu-features.o excp.o header-common.o irq.o ioapic.o printk.o +TARGETS += setup.o uart.o +TARGETS += ../alloc.o ../pci.o ../string.o ../cmdline.o ../setup.o ../test.o +TARGETS += ../uart-8250.o ../printk.o +TARGETS_32_ONLY := header-32.o +TARGETS_64_ONLY := mem.o pci.o smp.o timing.o header-64.o + +lib-y := $(TARGETS) $(TARGETS_64_ONLY) +lib32-y := $(TARGETS:.o=-32.o) $(TARGETS_32_ONLY) + +quiet_cmd_link_archive32 = AR $@ +cmd_link_archive32 = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(filter-out FORCE,$^) + +$(obj)/lib32.a: $(addprefix $(obj)/,$(lib32-y)) FORCE + $(call if_changed,link_archive32) + +targets += $(lib32-y) + +# Code of this object is called before SSE/AVX extensions are available. Ensure +# that the compiler won't generate unsupported instructions for this file. +CFLAGS_cpu-features.o += -mno-sse + +$(obj)/%-32.o: c_flags += -m32 +$(obj)/%-32.o: $(src)/%.c FORCE + $(call if_changed_rule,cc_o_c) + +$(obj)/%-32.o: a_flags += -m32 +$(obj)/%-32.o: $(src)/%.S FORCE + $(call if_changed_rule,as_o_S) diff --git a/inmates/lib/x86/Makefile.lib b/inmates/lib/x86/Makefile.lib new file mode 100644 index 0000000000000000000000000000000000000000..b5748565680147e6c5a00bb5b88959e0fde8c9f5 --- /dev/null +++ b/inmates/lib/x86/Makefile.lib @@ -0,0 +1,71 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# Alternatively, you can use or redistribute this file under the following +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 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 HOLDER 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. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +KBUILD_CFLAGS += -m64 -mno-red-zone +LINUXINCLUDE += -I$(INMATES_LIB)/include + +define DECLARE_TARGETS = + _TARGETS = $(1) + always-y := $$(_TARGETS) + # $(NAME-y) NAME-linked.o NAME.bin + targets += $$(foreach t,$$(_TARGETS:.bin=-y),$$($$t)) \ + $$(_TARGETS:.bin=-linked.o) $$(_TARGETS) +endef + +# prevent deleting intermediate files which would cause rebuilds +.SECONDARY: $(addprefix $(obj)/,$(targets)) + +# obj/NAME-linked.o: ... obj/$(NAME-y) lib/lib[32].a +.SECONDEXPANSION: +$(obj)/%-linked.o: $(INMATES_LIB)/inmate.lds $$(addprefix $$(obj)/,$$($$*-y)) \ + $(INMATES_LIB)/$$(if $$($$*_32),lib32.a,lib.a) FORCE + $(call if_changed,ld) + +$(obj)/%.bin: $(obj)/%-linked.o FORCE + $(call if_changed,objcopy) + +# 32-bit (i386) support +define DECLARE_32_BIT = + CFLAGS_$(1).o := -m32 -msse + LDFLAGS_$(1)-linked.o := /dev/null -m elf_i386 -T + $(1)_32 := y +endef diff --git a/inmates/lib/x86/cpu-features.c b/inmates/lib/x86/cpu-features.c new file mode 100644 index 0000000000000000000000000000000000000000..fccf692aadfcbca721df0aacf96f63d4bfaa13aa --- /dev/null +++ b/inmates/lib/x86/cpu-features.c @@ -0,0 +1,98 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +/* Must only be called from assembler header */ +void arch_init_features(void); + +struct x86_cpu_features x86_cpu_features; + +/* + * Every booting CPU will call this function before it enters its final C + * entry. We make the assumption that all CPUs have the same feature set. So we + * don't need any locks when writing to x86_cpu_features. + */ +void __attribute__((section(".boot"))) arch_init_features(void) +{ + u64 features; + + features = cpuid_edx(X86_CPUID_FEATURES, 0); + /* Check availability of FPU */ + x86_cpu_features.fpu = !!(features & X86_FEATURE_FPU); + + /* Discover and enable FXSR */ + if (features & X86_FEATURE_FXSR) { + write_cr4(read_cr4() | X86_CR4_OSFXSR); + x86_cpu_features.fxsr = true; + } + + /* Check availability of SSE */ + x86_cpu_features.sse = !!(features & X86_FEATURE_SSE); + x86_cpu_features.sse2 = !!(features & X86_FEATURE_SSE2); + + /* ECX hides the rest */ + features = cpuid_ecx(X86_CPUID_FEATURES, 0); + x86_cpu_features.sse3 = !!(features & X86_FEATURE_SSE3); + x86_cpu_features.sse4_1 = !!(features & X86_FEATURE_SSE4_1); + x86_cpu_features.sse4_2 = !!(features & X86_FEATURE_SSE4_2); + x86_cpu_features.pclmulqdq = !!(features & X86_FEATURE_PCLMULQDQ); + + if (features & X86_FEATURE_XSAVE) { + /* Enable XSAVE related instructions */ + write_cr4(read_cr4() | X86_CR4_OSXSAVE); + x86_cpu_features.xsave = true; + + /* + * Intel SDM 13.2: A bit can be set in XCR0 if and only if the + * corresponding bit is set in this bitmap. Every processor + * that supports the XSAVE feature set will set EAX[0] (x87 + * state) and EAX[1] (SSE state). + * + * We can always set SSE + FP, but only set AVX if available. + */ + + features = cpuid_edax(X86_CPUID_XSTATE, 0); + write_xcr0(read_xcr0() | (features & X86_XCR0_AVX) | \ + X86_XCR0_SSE | X86_XCR0_X87); + x86_cpu_features.avx = !!(features & X86_XCR0_AVX); + } + + /* hand control back to the header */ +} diff --git a/inmates/lib/x86/excp.c b/inmates/lib/x86/excp.c new file mode 100644 index 0000000000000000000000000000000000000000..88c48389ecc73e5d0ad111e57b95697dbfdd8357 --- /dev/null +++ b/inmates/lib/x86/excp.c @@ -0,0 +1,169 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2019 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +struct stack_frame { + unsigned long bp, si, dx, bx, ax; +#ifdef __x86_64__ + unsigned long r8, r9, r10, r11, r12, r13, r14, r15; + unsigned long cx, di; +#else + unsigned long di, cx; +#endif + unsigned long error_code, ip, cs, flags; +#ifdef __x86_64__ + unsigned long sp, ss; +#endif +}; + +extern u8 excp_entry[]; + +void excp_reporting_init(void) +{ + unsigned int vector; + u64 entry; + + for (vector = 0; vector < 21; vector++) { + entry = (unsigned long)excp_entry + vector * 16; + + idt[vector * 2] = (entry & 0xffff) | (INMATE_CS64 << 16) | + ((0x8e00 | (entry & 0xffff0000)) << 32); + idt[vector * 2 + 1] = entry >> 32; + } +} + +static void __attribute__((used)) +exception_handler(unsigned int vector, struct stack_frame *frame) +{ + /* + * Set the state first, in case enter an endless loop while reporting. + */ + comm_region->cell_state = JAILHOUSE_CELL_FAILED; + + printk("--- EXCEPTION %d ---\n", vector); + if (vector >= 10 && vector <= 14) + printk(" Error code: 0x%08lx\n", frame->error_code); + printk(" CS: 0x%04lx IP: %p flags: 0x%08lx\n", + frame->cs, (void *)frame->ip, frame->flags); + printk(" SP: %p BP: %p\n", frame + 1, (void *)frame->bp); + printk(" AX: %p BX: %p CX: %p\n", + (void *)frame->ax, (void *)frame->bx, (void *)frame->bx); + printk(" DX: %p SI: %p DI: %p\n", + (void *)frame->dx, (void *)frame->si, (void *)frame->di); +#ifdef __x86_64__ + printk(" R8: %p R9: %p R10: %p\n", + (void *)frame->r8, (void *)frame->r9, (void *)frame->r10); + printk(" R11: %p R12: %p R13: %p\n", + (void *)frame->r11, (void *)frame->r12, (void *)frame->r13); + printk(" R14: %p R15: %p\n", + (void *)frame->r14, (void *)frame->r15); +#endif + + stop(); +} + +asm( +".macro excp_prologue vector\n\t" + "push $0\n\t" + "excp_error_prologue vector\n\t" +".endm\n" + +".macro excp_error_prologue vector\n\t" +#ifdef __x86_64__ + "push %rdi\n\t" + "mov $vector,%rdi\n\t" +#else + "push %ecx\n\t" + "mov $vector,%ecx\n\t" +#endif + "jmp excp_common\n" + ".balign 16\n\t" +".endm\n\t" + + ".global excp_entry\n\t" + ".balign 16\n" +"excp_entry:\n" +"vector=0\n" +".rept 8\n" + "excp_prologue vector\n\t" + "vector=vector+1\n\t" +".endr\n" + "excp_error_prologue 8 \n\t" + "excp_prologue 9\n\t" +"vector=10\n" +".rept 5\n" + "excp_error_prologue vector\n\t" + "vector=vector+1\n\t" +".endr\n" + "excp_prologue 15\n\t" + "excp_prologue 16\n\t" + "excp_error_prologue 17\n\t" + "excp_prologue 18\n\t" + "excp_prologue 19\n\t" + "excp_prologue 20\n\t" + +"excp_common:\n\t" +#ifdef __x86_64__ + "push %rcx\n\t" + "push %r15\n\t" + "push %r14\n\t" + "push %r13\n\t" + "push %r12\n\t" + "push %r11\n\t" + "push %r10\n\t" + "push %r9\n\t" + "push %r8\n\t" + "push %rax\n\t" + "push %rbx\n\t" + "push %rdx\n\t" + "push %rsi\n\t" + "push %rbp\n\t" + "mov %rsp,%rsi\n\t" +#else + "push %edi\n\t" + "push %eax\n\t" + "push %ebx\n\t" + "push %edx\n\t" + "push %esi\n\t" + "push %ebp\n\t" + "mov %esp,%edx\n\t" +#endif + + "jmp exception_handler\n\t" +); diff --git a/inmates/lib/x86/header-32.S b/inmates/lib/x86/header-32.S new file mode 100644 index 0000000000000000000000000000000000000000..911f430f803367a3122d31a5007dc2e6a4247fd4 --- /dev/null +++ b/inmates/lib/x86/header-32.S @@ -0,0 +1,147 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + + .code32 + .section ".boot", "ax" + .globl start32 +start32: + mov %cr4,%eax + or $X86_CR4_PSE,%eax + mov %eax,%cr4 + + mov $pd,%eax + mov %eax,%cr3 + + mov $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE),%eax + mov %eax,%cr0 + + movl $MSR_MTRR_DEF_TYPE,%ecx + rdmsr + or $MTRR_ENABLE,%eax + wrmsr + + mov $INMATE_DS32,%eax + mov %eax,%ds + mov %eax,%es + mov %eax,%ss + + xor %ebx,%ebx + xchg ap_entry,%ebx + or %ebx,%ebx + jnz call_entry + + mov $1,%edi + lock xadd %edi,cpu_number + + cmp $SMP_MAX_CPUS,%edi + jae stop + + mov $X86_CPUID_FEATURES, %eax + cpuid + shr $24,%ebx + mov %bl,smp_cpu_ids(%edi) + + lock incl smp_num_cpus + + cmp $0,%edi + jne stop + + xor %eax,%eax + mov $bss_start,%edi + mov $bss_dwords,%ecx + rep stosl + + mov $c_entry,%ebx + +call_entry: + xor %esp, %esp + xchg stack, %esp + + call arch_init_features + + call *%ebx + +stop: cli + hlt + jmp stop + + + .pushsection ".data" + + .globl ap_entry +ap_entry: + .long 0 + + .globl smp_num_cpus +smp_num_cpus: + .long 0 + + .globl smp_cpu_ids +smp_cpu_ids: + .fill SMP_MAX_CPUS, 1, 0 + + .popsection + +cpu_number: + .long 0 + + .align(16) + .global loader_gdt +loader_gdt: + .quad 0 + .quad 0x00cf9b000000ffff + .quad 0x00af9b000000ffff + .quad 0x00cf93000000ffff + + .globl gdt_ptr +gdt_ptr: + .short gdt_ptr - loader_gdt - 1 + .long loader_gdt + + + .section ".rodata" + + .align(4096) + .global loader_pdpt +pd: + /* ID map 4M@0x0 */ + .long 0x0 + (PAGE_FLAG_PS | PAGE_DEFAULT_FLAGS) + .align(4096) diff --git a/inmates/lib/x86/header-64.S b/inmates/lib/x86/header-64.S new file mode 100644 index 0000000000000000000000000000000000000000..a71c018f3e2e466f06d47e675d96e5eb3af56320 --- /dev/null +++ b/inmates/lib/x86/header-64.S @@ -0,0 +1,156 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + + .code32 + .section ".boot", "ax" + .globl start32 +start32: + mov %cr4,%eax + or $X86_CR4_PAE,%eax + mov %eax,%cr4 + + mov $pml4,%eax + mov %eax,%cr3 + + movl $MSR_MTRR_DEF_TYPE,%ecx + rdmsr + or $MTRR_ENABLE,%eax + wrmsr + + movl $MSR_EFER,%ecx + rdmsr + or $EFER_LME,%eax + wrmsr + + mov $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE),%eax + mov %eax,%cr0 + + ljmpl $INMATE_CS64,$start64 + + .code64 +start64: + xor %rbx,%rbx + xchg ap_entry,%rbx + or %rbx,%rbx + jnz call_entry + + mov $1,%edi + lock xadd %edi,cpu_number + + cmp $SMP_MAX_CPUS,%edi + jae stop + + mov $X86_CPUID_FEATURES, %eax + cpuid + shr $24,%ebx + mov %bl,smp_cpu_ids(%edi) + + lock incl smp_num_cpus + + cmp $0,%edi + jne stop + + xor %rax,%rax + mov $bss_start,%rdi + mov $bss_qwords,%rcx + rep stosq + + mov $c_entry,%rbx + +call_entry: + xor %rsp, %rsp + xchg stack, %rsp + + call arch_init_features + + callq *%rbx + +stop: cli + hlt + jmp stop + + + .pushsection ".data" + + .globl ap_entry +ap_entry: + .quad 0 + + .globl smp_num_cpus +smp_num_cpus: + .long 0 + + .globl smp_cpu_ids +smp_cpu_ids: + .fill SMP_MAX_CPUS, 1, 0 + + .popsection + +cpu_number: + .long 0 + + .align(16) +gdt: + .quad 0 + .quad 0x00c09b000000ffff + .quad 0x00af9b000000ffff + + .globl gdt_ptr +gdt_ptr: + .short gdt_ptr - gdt - 1 + .long gdt + + + .section ".rodata" + + .align(4096) +pml4: + .quad pdpt + PAGE_DEFAULT_FLAGS + + .align(4096) +pdpt: + .quad pd + PAGE_DEFAULT_FLAGS + + .align(4096) +pd: + /* ID map 2M@0x0 */ + .quad 0x0 + (PAGE_FLAG_PS | PAGE_DEFAULT_FLAGS) + .align(4096) diff --git a/inmates/lib/x86/header-common.S b/inmates/lib/x86/header-common.S new file mode 100644 index 0000000000000000000000000000000000000000..d40d8d5e5bd8c68cf37f91ccc5dd2f695538cb2b --- /dev/null +++ b/inmates/lib/x86/header-common.S @@ -0,0 +1,56 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + + .code16 + .section ".boot.entry", "ax" + + .globl __reset_entry +__reset_entry: + lgdtl %cs:gdt_ptr + + mov %cr0, %eax + or $X86_CR0_PE, %al + mov %eax, %cr0 + + ljmpl $INMATE_CS32, $start32 + + .code32 + .section ".boot", "ax" diff --git a/inmates/lib/x86/include/asm/regs.h b/inmates/lib/x86/include/asm/regs.h new file mode 100644 index 0000000000000000000000000000000000000000..16a0665ef84ff4a6326603398eeb44a5333bcbc8 --- /dev/null +++ b/inmates/lib/x86/include/asm/regs.h @@ -0,0 +1,170 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#define X86_CR0_PE 0x00000001 +#define X86_CR0_WP 0x00010000 +#define X86_CR0_PG 0x80000000 + +#define X86_CR4_PAE 0x00000020 +#define X86_CR4_PSE 0x00000010 +#define X86_CR4_OSFXSR 0x00000200 +#define X86_CR4_OSXSAVE 0x00040000 + +#define X86_XCR0_X87 (1 << 0) +#define X86_XCR0_SSE (1 << 1) +#define X86_XCR0_AVX (1 << 2) + +#define PAGE_FLAG_PRESENT 0x01 +#define PAGE_FLAG_RW 0x02 +#define PAGE_FLAG_PS 0x80 +#define PAGE_FLAG_PCD 0x10 + +#define PAGE_DEFAULT_FLAGS (PAGE_FLAG_PRESENT | PAGE_FLAG_RW) + +#define MSR_EFER 0xc0000080 +#define EFER_LME 0x00000100 + +#define X86_CPUID_FEATURES 0x00000001 /* Processor Info and Feature Bits */ +/* Feature bits in EDX */ +# define X86_FEATURE_FPU (1 << 0) /* The processor contains an x87 FPU. */ +# define X86_FEATURE_FXSR (1 << 24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ +# define X86_FEATURE_SSE (1 << 25) /* The processor supports SSE */ +# define X86_FEATURE_SSE2 (1 << 26) /* The processor supports SSE2 */ +/* Feature bits in ECX */ +# define X86_FEATURE_SSE3 (1 << 0) /* The processor supports SSE3 */ +# define X86_FEATURE_PCLMULQDQ (1 << 1) /* The processor supports PCLMULQDQ */ +# define X86_FEATURE_SSE4_1 (1 << 19) /* The processor supports SSE4.1 */ +# define X86_FEATURE_SSE4_2 (1 << 20) /* The processor supports SSE4.2 */ +# define X86_FEATURE_XSAVE (1 << 26) /* XSAVE/..., CR4.OSXSAVE */ + +#define X86_CPUID_XSTATE 0x0000000d /* Extended state features */ + +#define MSR_MTRR_DEF_TYPE 0x000002ff +#define MTRR_ENABLE 0x00000800 + +#ifndef __ASSEMBLY__ + +#include + +struct x86_cpu_features { + bool avx:1; + bool sse:1; + bool sse2:1; + bool sse3:1; + bool sse4_1:1; + bool sse4_2:1; + bool fpu:1; + bool xsave:1; + bool fxsr:1; + bool pclmulqdq:1; +}; + +extern struct x86_cpu_features x86_cpu_features; + +#define READ_CR(n) \ +static inline unsigned long read_cr##n(void) \ +{ \ + unsigned long cr; \ + asm volatile("mov %%cr" __stringify(n) ", %0" \ + : "=r" (cr)); \ + \ + return cr; \ +} + +READ_CR(3) +READ_CR(4) + +static inline void write_cr4(unsigned long val) +{ + asm volatile("mov %0, %%cr4" : : "r" (val)); +} + +static inline u64 read_xcr0(void) +{ + register u32 eax, edx; + + asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); + + return ((u64)(edx) << 32) + ((u64)(eax)); +} + +static inline void write_xcr0(u64 xcr0) +{ + unsigned int eax = xcr0; + unsigned int edx = xcr0 >> 32; + + asm volatile("xsetbv" : : "a" (eax), "d" (edx), "c" (0)); +} + +static inline void cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (*eax), "2" (*ecx) + : "memory"); +} + +static inline u64 cpuid_edax(unsigned int op, unsigned int sub) +{ + unsigned int eax, ebx, ecx, edx; + + eax = op; + ecx = sub; + cpuid(&eax, &ebx, &ecx, &edx); + return ((u64)edx << 32) + (u64)eax; +} + +#define CPUID_REG(reg) \ +static inline unsigned int cpuid_##reg(unsigned int op, unsigned int sub) \ +{ \ + unsigned int eax, ebx, ecx, edx; \ + \ + eax = op; \ + ecx = sub; \ + cpuid(&eax, &ebx, &ecx, &edx); \ + return reg; \ +} + +CPUID_REG(eax) +CPUID_REG(ebx) +CPUID_REG(ecx) +CPUID_REG(edx) + +#endif /* __ASSEMBLY__ */ diff --git a/inmates/lib/x86/include/inmate.h b/inmates/lib/x86/include/inmate.h new file mode 100644 index 0000000000000000000000000000000000000000..28ae59459e1c7d33644e31f163004a04b724aed3 --- /dev/null +++ b/inmates/lib/x86/include/inmate.h @@ -0,0 +1,238 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#ifndef _JAILHOUSE_INMATE_H +#define _JAILHOUSE_INMATE_H + +#define COMM_REGION_BASE 0x100000 + +#define INMATE_CS32 0x8 +#define INMATE_CS64 0x10 +#define INMATE_DS32 0x18 + +#define PAGE_SIZE (4 * 1024ULL) +#ifdef __x86_64__ +#define BITS_PER_LONG 64 +#define HUGE_PAGE_SIZE (2 * 1024 * 1024ULL) +#else +#define BITS_PER_LONG 32 +#define HUGE_PAGE_SIZE (4 * 1024 * 1024ULL) +#endif +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1)) + +#define X2APIC_ID 0x802 +#define X2APIC_ICR 0x830 + +#define APIC_LVL_ASSERT (1 << 14) + +#define SMP_MAX_CPUS 255 + +#ifndef __ASSEMBLY__ +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +static inline void enable_irqs(void) +{ + asm volatile("sti"); +} + +static inline void disable_irqs(void) +{ + asm volatile("cli"); +} + +static inline void cpu_relax(void) +{ + asm volatile("rep; nop" : : : "memory"); +} + +static inline void __attribute__((noreturn)) halt(void) +{ + while (1) + asm volatile ("hlt" : : : "memory"); +} + +static inline void outb(u8 v, u16 port) +{ + asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); +} + +static inline void outw(u16 v, u16 port) +{ + asm volatile("outw %0,%1" : : "a" (v), "dN" (port)); +} + +static inline void outl(u32 v, u16 port) +{ + asm volatile("outl %0,%1" : : "a" (v), "dN" (port)); +} + +static inline u8 inb(u16 port) +{ + u8 v; + asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline u16 inw(u16 port) +{ + u16 v; + asm volatile("inw %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline u32 inl(u16 port) +{ + u32 v; + asm volatile("inl %1,%0" : "=a" (v) : "dN" (port)); + return v; +} + +static inline u8 mmio_read8(void *address) +{ + return *(volatile u8 *)address; +} + +static inline u16 mmio_read16(void *address) +{ + return *(volatile u16 *)address; +} + +static inline u32 mmio_read32(void *address) +{ + u32 value; + + /* assembly-encoded to match the hypervisor MMIO parser support */ + asm volatile("movl (%1),%0" : "=r" (value) : "r" (address)); + return value; +} + +static inline u64 mmio_read64(void *address) +{ + return *(volatile u64 *)address; +} + +static inline void mmio_write8(void *address, u8 value) +{ + *(volatile u8 *)address = value; +} + +static inline void mmio_write16(void *address, u16 value) +{ + *(volatile u16 *)address = value; +} + +static inline void mmio_write32(void *address, u32 value) +{ + /* assembly-encoded to match the hypervisor MMIO parser support */ + asm volatile("movl %0,(%1)" : : "r" (value), "r" (address)); +} + +static inline void mmio_write64(void *address, u64 value) +{ + *(volatile u64 *)address = value; +} + +static inline u64 read_msr(unsigned int msr) +{ + u32 low, high; + + asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); + return low | ((u64)high << 32); +} + +static inline void write_msr(unsigned int msr, u64 val) +{ + asm volatile("wrmsr" + : /* no output */ + : "c" (msr), "a" ((u32)val), "d" ((u32)(val >> 32)) + : "memory"); +} + +static inline unsigned int cpu_id(void) +{ + return read_msr(X2APIC_ID); +} + +#define MAX_INTERRUPT_VECTORS 32 + +extern unsigned long idt[]; +extern void *stack; + +void excp_reporting_init(void); + +void irq_send_ipi(unsigned int cpu_id, unsigned int vector); + +enum ioapic_trigger_mode { + TRIGGER_EDGE = 0, + TRIGGER_LEVEL_ACTIVE_HIGH = 1 << 15, + TRIGGER_LEVEL_ACTIVE_LOW = (1 << 15) | (1 << 13), +}; + +void ioapic_init(void); +void ioapic_pin_set_vector(unsigned int pin, + enum ioapic_trigger_mode trigger_mode, + unsigned int vector); + +unsigned long long pm_timer_read(void); + +unsigned long tsc_read_ns(void); +unsigned long tsc_init(void); + +unsigned long apic_timer_init(unsigned int vector); +void apic_timer_set(unsigned long long timeout_ns); + +extern volatile u32 smp_num_cpus; +extern u8 smp_cpu_ids[SMP_MAX_CPUS]; +void smp_wait_for_all_cpus(void); +void smp_start_cpu(unsigned int cpu_id, void (*entry)(void)); +#endif + +#include + +#endif /* !_JAILHOUSE_INMATE_H */ diff --git a/inmates/lib/x86/inmate.lds b/inmates/lib/x86/inmate.lds new file mode 100644 index 0000000000000000000000000000000000000000..a1ca242f0053e3941c9c75139c7288defbc419cd --- /dev/null +++ b/inmates/lib/x86/inmate.lds @@ -0,0 +1,84 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2017 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +SECTIONS +{ + . = 0; + .boot : { + *(.boot.entry) + *(.boot) + } + + . = 0x1000; + .cmdline : { + *(.cmdline) + BYTE(0); /* empty string in case no buffer is provided */ + } + + .text : { + *(.text) + } + + . = ALIGN(16); + .rodata : { + *(.rodata) + } + + . = ALIGN(16); + .data : { + *(.data) + } + + .bss : { + bss_start = .; + *(.bss) + . = ALIGN(8); + } + bss_dwords = SIZEOF(.bss) / 4; + bss_qwords = SIZEOF(.bss) / 8; + + . = ALIGN(4096); + . += 0x1000; + stack_top = .; + + /DISCARD/ : { + *(.eh_frame*) + } +} + +ENTRY(__reset_entry) diff --git a/inmates/lib/x86/ioapic.c b/inmates/lib/x86/ioapic.c new file mode 100644 index 0000000000000000000000000000000000000000..3f1624ae3491bddc9ee9bed0a1caeb7689c5eacd --- /dev/null +++ b/inmates/lib/x86/ioapic.c @@ -0,0 +1,62 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define IOAPIC_BASE ((void *)0xfec00000) +#define IOAPIC_REG_INDEX 0x00 +#define IOAPIC_REG_DATA 0x10 +#define IOAPIC_REDIR_TBL_START 0x10 + +void ioapic_init(void) +{ + map_range(IOAPIC_BASE, PAGE_SIZE, MAP_UNCACHED); +} + +void ioapic_pin_set_vector(unsigned int pin, + enum ioapic_trigger_mode trigger_mode, + unsigned int vector) +{ + mmio_write32(IOAPIC_BASE + IOAPIC_REG_INDEX, + IOAPIC_REDIR_TBL_START + pin * 2 + 1); + mmio_write32(IOAPIC_BASE + IOAPIC_REG_DATA, cpu_id() << (56 - 32)); + + mmio_write32(IOAPIC_BASE + IOAPIC_REG_INDEX, + IOAPIC_REDIR_TBL_START + pin * 2); + mmio_write32(IOAPIC_BASE + IOAPIC_REG_DATA, trigger_mode | vector); +} diff --git a/inmates/lib/x86/irq.c b/inmates/lib/x86/irq.c new file mode 100644 index 0000000000000000000000000000000000000000..6b0c2b57b4ec1d2448268f8ca57655d5b8ef54c4 --- /dev/null +++ b/inmates/lib/x86/irq.c @@ -0,0 +1,149 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define X2APIC_SPIV 0x80f + +#define APIC_EOI_ACK 0 + +extern u8 irq_entry[]; + +static irq_handler_t __attribute__((used)) irq_handler; + +void irq_init(irq_handler_t handler) +{ + unsigned int vector; + u64 entry; + + write_msr(X2APIC_SPIV, 0x1ff); + + irq_handler = handler; + + for (vector = 32; vector < 32 + MAX_INTERRUPT_VECTORS; vector++) { + entry = (unsigned long)irq_entry + (vector - 32) * 16; + idt[vector * 2] = (entry & 0xffff) | (INMATE_CS64 << 16) | + ((0x8e00 | (entry & 0xffff0000)) << 32); + idt[vector * 2 + 1] = entry >> 32; + } +} + +asm( +".macro eoi\n\t" + /* write 0 as ack to x2APIC EOI register (0x80b) */ + "xor %eax,%eax\n\t" + "xor %edx,%edx\n\t" + "mov $0x80b,%ecx\n\t" + "wrmsr\n" +".endm\n" + +".macro irq_prologue irq\n\t" +#ifdef __x86_64__ + "push %rdi\n\t" + "mov $irq,%rdi\n\t" +#else + "push %ecx\n\t" + "mov $irq,%ecx\n\t" +#endif + "jmp irq_common\n" + ".balign 16\n" +".endm\n\t" + + ".global irq_entry\n\t" + ".balign 16\n" +"irq_entry:\n" +"irq=32\n" +".rept 32\n" + "irq_prologue irq\n\t" + "irq=irq+1\n\t" +".endr\n" + +"irq_common:\n\t" +#ifdef __x86_64__ + "push %rax\n\t" + "push %rcx\n\t" + "push %rdx\n\t" + "push %rsi\n\t" + "push %r8\n\t" + "push %r9\n\t" + "push %r10\n\t" + "push %r11\n\t" + + "call *irq_handler\n\t" + + "eoi\n\t" + + "pop %r11\n\t" + "pop %r10\n\t" + "pop %r9\n\t" + "pop %r8\n\t" + "pop %rsi\n\t" + "pop %rdx\n\t" + "pop %rcx\n\t" + "pop %rax\n\t" + "pop %rdi\n\t" + + "iretq" +#else + "push %eax\n\t" + "push %edx\n\t" + "push %esi\n\t" + "push %edi\n\t" + + "call *irq_handler\n\t" + + "eoi\n\t" + + "pop %edi\n\t" + "pop %esi\n\t" + "pop %edx\n\t" + "pop %eax\n\t" + "pop %ecx\n\t" + + "iret" +#endif +); + +void irq_enable(unsigned int irq) +{ +} + +void irq_send_ipi(unsigned int cpu_id, unsigned int vector) +{ + write_msr(X2APIC_ICR, ((u64)cpu_id << 32) | APIC_LVL_ASSERT | vector); +} diff --git a/inmates/lib/x86/mem.c b/inmates/lib/x86/mem.c new file mode 100644 index 0000000000000000000000000000000000000000..764bdb4b629187909f2aa55ecebbdc9a62750546 --- /dev/null +++ b/inmates/lib/x86/mem.c @@ -0,0 +1,82 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +void map_range(void *start, unsigned long size, enum map_type map_type) +{ + unsigned long pt_addr, *pt_entry, *pt; + unsigned long vaddr = (unsigned long)start; + + pt_addr = read_cr3(); + + size += (vaddr & ~HUGE_PAGE_MASK) + HUGE_PAGE_SIZE - 1; + size &= HUGE_PAGE_MASK; + while (size > 0) { +#ifdef __x86_64__ + pt_addr &= PAGE_MASK; + pt = (unsigned long *)pt_addr; + + pt_entry = &pt[(vaddr >> 39) & 0x1ff]; + if (*pt_entry & PAGE_FLAG_PRESENT) { + pt = (unsigned long *)(*pt_entry & PAGE_MASK); + } else { + pt = zalloc(PAGE_SIZE, PAGE_SIZE); + *pt_entry = (unsigned long)pt | PAGE_DEFAULT_FLAGS; + } + + pt_entry = &pt[(vaddr >> 30) & 0x1ff]; + if (*pt_entry & PAGE_FLAG_PRESENT) { + pt = (unsigned long *)(*pt_entry & PAGE_MASK); + } else { + pt = zalloc(PAGE_SIZE, PAGE_SIZE); + *pt_entry = (unsigned long)pt | PAGE_DEFAULT_FLAGS; + } + + pt_entry = &pt[(vaddr >> 21) & 0x1ff]; + *pt_entry = (vaddr & HUGE_PAGE_MASK) | + (map_type == MAP_UNCACHED ? PAGE_FLAG_PCD : 0) | + PAGE_FLAG_PS | PAGE_DEFAULT_FLAGS; +#else +#error not yet implemented +#endif + size -= HUGE_PAGE_SIZE; + vaddr += HUGE_PAGE_SIZE; + } +} diff --git a/inmates/lib/x86/pci.c b/inmates/lib/x86/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..a04e2db652cff6982b087cd8e3da4874b9e3298f --- /dev/null +++ b/inmates/lib/x86/pci.c @@ -0,0 +1,141 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define PCI_REG_ADDR_PORT 0xcf8 +#define PCI_REG_DATA_PORT 0xcfc + +#define PCI_CONE (1 << 31) + +void pci_init(void) +{ +} + +u32 pci_read_config(u16 bdf, unsigned int addr, unsigned int size) +{ + outl(PCI_CONE | ((u32)bdf << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT); + switch (size) { + case 1: + return inb(PCI_REG_DATA_PORT + (addr & 0x3)); + case 2: + return inw(PCI_REG_DATA_PORT + (addr & 0x3)); + case 4: + return inl(PCI_REG_DATA_PORT); + default: + return -1; + } +} + +void pci_write_config(u16 bdf, unsigned int addr, u32 value, unsigned int size) +{ + outl(PCI_CONE | ((u32)bdf << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT); + switch (size) { + case 1: + outb(value, PCI_REG_DATA_PORT + (addr & 0x3)); + break; + case 2: + outw(value, PCI_REG_DATA_PORT + (addr & 0x3)); + break; + case 4: + outl(value, PCI_REG_DATA_PORT); + break; + } +} + +void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index) +{ + int cap = pci_find_cap(bdf, PCI_CAP_MSIX); + unsigned int bar; + u64 msix_table = 0; + u32 addr; + u16 ctrl; + u32 table; + + if (cap < 0) + return; + ctrl = pci_read_config(bdf, cap + 2, 2); + /* bounds check */ + if (index > (ctrl & 0x3ff)) + return; + table = pci_read_config(bdf, cap + 4, 4); + bar = (table & 7) * 4 + PCI_CFG_BAR; + addr = pci_read_config(bdf, bar, 4); + + if ((addr & 6) == PCI_BAR_64BIT) { + msix_table = pci_read_config(bdf, bar + 4, 4); + msix_table <<= 32; + } + msix_table |= addr & ~0xf; + msix_table += table & ~7; + + /* enable and mask */ + ctrl |= (MSIX_CTRL_ENABLE | MSIX_CTRL_FMASK); + pci_write_config(bdf, cap + 2, ctrl, 2); + + msix_table += 16 * index; + mmio_write32((u32 *)msix_table, 0xfee00000 | cpu_id() << 12); + mmio_write32((u32 *)(msix_table + 4), 0); + mmio_write32((u32 *)(msix_table + 8), vector); + mmio_write32((u32 *)(msix_table + 12), 0); + + /* enable and unmask */ + ctrl &= ~MSIX_CTRL_FMASK; + pci_write_config(bdf, cap + 2, ctrl, 2); +} + +void pci_msi_set_vector(u16 bdf, unsigned int vector) +{ + int cap = pci_find_cap(bdf, PCI_CAP_MSI); + u16 ctl, data; + + if (cap < 0) + return; + + pci_write_config(bdf, cap + 0x04, 0xfee00000 | (cpu_id() << 12), 4); + + ctl = pci_read_config(bdf, cap + 0x02, 2); + if (ctl & (1 << 7)) { + pci_write_config(bdf, cap + 0x08, 0, 4); + data = cap + 0x0c; + } else + data = cap + 0x08; + pci_write_config(bdf, data, vector, 2); + + pci_write_config(bdf, cap + 0x02, 0x0001, 2); +} diff --git a/inmates/lib/x86/printk.c b/inmates/lib/x86/printk.c new file mode 100644 index 0000000000000000000000000000000000000000..bae6b42f0c6ffdeece43713787ef5cc60c9eba4a --- /dev/null +++ b/inmates/lib/x86/printk.c @@ -0,0 +1,80 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +static void reg_out_mmio8(struct uart_chip *chip, unsigned int reg, u32 value) +{ + mmio_write8(chip->base + reg, value); +} + +static u32 reg_in_mmio8(struct uart_chip *chip, unsigned int reg) +{ + return mmio_read8(chip->base + reg); +} + +static void reg_out_pio(struct uart_chip *chip, unsigned int reg, u32 value) +{ + outb(value, (unsigned long)chip->base + reg); +} + +static u32 reg_in_pio(struct uart_chip *chip, unsigned int reg) +{ + return inb((unsigned long)chip->base + reg); +} + +void arch_console_init(struct uart_chip *chip) +{ + struct jailhouse_console *console = &comm_region->console; + + if (cmdline_parse_bool("con-is-mmio", CON_IS_MMIO(console->flags))) { +#ifdef __x86_64__ + map_range((void *)chip->base, 0x1000, MAP_UNCACHED); +#endif + + if (cmdline_parse_bool("con-regdist-1", + CON_USES_REGDIST_1(console->flags))) { + chip->reg_out = reg_out_mmio8; + chip->reg_in = reg_in_mmio8; + } + } else { + chip->reg_out = reg_out_pio; + chip->reg_in = reg_in_pio; + } +} diff --git a/inmates/lib/x86/setup.c b/inmates/lib/x86/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..807db99ea17ceaedcdb08b1feeaa3b3e0163b6a7 --- /dev/null +++ b/inmates/lib/x86/setup.c @@ -0,0 +1,75 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018-2019 + * Copyright (c) Valentine Sinitsyn, 2014 + * + * Authors: + * Ralf Ramsauer + * Valentine Sinitsyn + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define AUTHENTIC_AMD(n) (((const u32 *)"AuthenticAMD")[n]) + +void *stack = (void*)stack_top; + +struct desc_table_reg { + u16 limit; + unsigned long base; +} __attribute__((packed)); + +bool jailhouse_use_vmcall = true; + +unsigned long idt[(32 + MAX_INTERRUPT_VECTORS) * 2]; + +void arch_init_early(void) +{ + struct desc_table_reg dtr; + u32 eax, ebx, ecx, edx; + + asm volatile("cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (0) + : "memory" + ); + + if (ebx == AUTHENTIC_AMD(0) && + edx == AUTHENTIC_AMD(1) && + ecx == AUTHENTIC_AMD(2)) + jailhouse_use_vmcall = false; + + dtr.limit = sizeof(idt) - 1; + dtr.base = (unsigned long)&idt; + asm volatile("lidt %0" : : "m" (dtr)); +} diff --git a/inmates/lib/x86/smp.c b/inmates/lib/x86/smp.c new file mode 100644 index 0000000000000000000000000000000000000000..625ddaf0bd3082f9e0caab5e8af27ddb58b9af62 --- /dev/null +++ b/inmates/lib/x86/smp.c @@ -0,0 +1,67 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define APIC_DM_INIT (5 << 8) +#define APIC_DM_SIPI (6 << 8) + +extern void (* volatile ap_entry)(void); + +void smp_wait_for_all_cpus(void) +{ + while (smp_num_cpus < comm_region->num_cpus) + cpu_relax(); +} + +void smp_start_cpu(unsigned int cpu_id, void (*entry)(void)) +{ + u64 base_val = ((u64)cpu_id << 32) | APIC_LVL_ASSERT; + + ap_entry = entry; + stack = zalloc(PAGE_SIZE, PAGE_SIZE) + PAGE_SIZE; + + write_msr(X2APIC_ICR, base_val | APIC_DM_INIT); + delay_us(10000); + write_msr(X2APIC_ICR, base_val | APIC_DM_SIPI); + delay_us(200); + write_msr(X2APIC_ICR, base_val | APIC_DM_SIPI); + + while (ap_entry && stack) + cpu_relax(); +} diff --git a/inmates/lib/x86/timing.c b/inmates/lib/x86/timing.c new file mode 100644 index 0000000000000000000000000000000000000000..ccdc10e2afab75b323a32a2d920d6a326f5a041f --- /dev/null +++ b/inmates/lib/x86/timing.c @@ -0,0 +1,150 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include + +#define PM_TIMER_HZ 3579545 +#define PM_TIMER_OVERFLOW ((0x1000000 * NS_PER_SEC) / PM_TIMER_HZ) + +#define IA32_TSC_DEADLINE 0x6e0 + +#define X2APIC_LVTT 0x832 +# define LVTT_TSC_DEADLINE (1 << 18) +#define X2APIC_TMICT 0x838 +#define X2APIC_TMCCT 0x839 +#define X2APIC_TDCR 0x83e + +static unsigned long apic_tick_freq; +static unsigned long long pm_timer_last[SMP_MAX_CPUS]; +static unsigned long pm_timer_overflows[SMP_MAX_CPUS]; +static unsigned long tsc_freq, tsc_overflow; +static unsigned long tsc_last[SMP_MAX_CPUS]; +static unsigned long tsc_overflows[SMP_MAX_CPUS]; +static bool tsc_deadline; + +static u64 rdtsc(void) +{ +#ifdef __x86_64__ + u32 lo, hi; + + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return (u64)lo | (((u64)hi) << 32); +#else + u64 v; + + asm volatile("rdtsc" : "=A" (v)); + return v; +#endif +} + +unsigned long tsc_read_ns(void) +{ + unsigned int cpu = cpu_id(); + unsigned long tmr; + + tmr = ((rdtsc() & 0xffffffffLL) * NS_PER_SEC) / tsc_freq; + if (tmr < tsc_last[cpu]) + tsc_overflows[cpu] += tsc_overflow; + tsc_last[cpu] = tmr; + return tmr + tsc_overflows[cpu]; +} + +unsigned long tsc_init(void) +{ + tsc_freq = comm_region->tsc_khz * 1000L; + tsc_overflow = (0x100000000L * NS_PER_SEC) / tsc_freq; + + return tsc_freq; +} + +unsigned long long pm_timer_read(void) +{ + unsigned int cpu = cpu_id(); + unsigned long long tmr; + + tmr = ((unsigned long long)(inl(comm_region->pm_timer_address) + & 0x00ffffff) * NS_PER_SEC) / PM_TIMER_HZ; + if (tmr < pm_timer_last[cpu]) + pm_timer_overflows[cpu] += PM_TIMER_OVERFLOW; + pm_timer_last[cpu] = tmr; + return tmr + pm_timer_overflows[cpu]; +} + +void delay_us(unsigned long microsecs) +{ + unsigned long long timeout = pm_timer_read() + microsecs * NS_PER_USEC; + + while ((long long)(timeout - pm_timer_read()) > 0) + cpu_relax(); +} + +unsigned long apic_timer_init(unsigned int vector) +{ + unsigned long apic_freq; + unsigned long ecx; + + asm volatile("cpuid" : "=c" (ecx) : "a" (1) + : "rbx", "rdx", "memory"); + tsc_deadline = !!(ecx & (1 << 24)); + + if (tsc_deadline) { + vector |= LVTT_TSC_DEADLINE; + apic_tick_freq = tsc_init(); + apic_freq = apic_tick_freq / 1000; + } else { + apic_tick_freq = comm_region->apic_khz * 1000 / 16; + apic_freq = comm_region->apic_khz; + } + + write_msr(X2APIC_LVTT, vector); + + /* Required when using TSC deadline mode. */ + asm volatile("mfence" : : : "memory"); + + return apic_freq; +} + +void apic_timer_set(unsigned long long timeout_ns) +{ + unsigned long long ticks = timeout_ns * apic_tick_freq / NS_PER_SEC; + + if (tsc_deadline) + write_msr(IA32_TSC_DEADLINE, rdtsc() + ticks); + else + write_msr(X2APIC_TMICT, ticks); +} diff --git a/inmates/lib/x86/uart.c b/inmates/lib/x86/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..33f64b79fc83181eeffb3f18c861198dfc9616d4 --- /dev/null +++ b/inmates/lib/x86/uart.c @@ -0,0 +1,47 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2018 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + */ + +#include +#include + +DECLARE_UART(8250); + +struct uart_chip *uart_array[] = { + &UART_OPS_NAME(8250), + NULL +}; diff --git a/inmates/tests/arm/Makefile b/inmates/tests/arm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7ae637a7bf93ff76f5ef0a69c4b4b4049c05822e --- /dev/null +++ b/inmates/tests/arm/Makefile @@ -0,0 +1 @@ +# nothing to do for now diff --git a/inmates/tests/arm64/Makefile b/inmates/tests/arm64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7ae637a7bf93ff76f5ef0a69c4b4b4049c05822e --- /dev/null +++ b/inmates/tests/arm64/Makefile @@ -0,0 +1 @@ +# nothing to do for now diff --git a/inmates/tests/x86/Makefile b/inmates/tests/x86/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6c8dc0e7ab2958c217ad045330232c580108db31 --- /dev/null +++ b/inmates/tests/x86/Makefile @@ -0,0 +1,30 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2018 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := mmio-access.bin mmio-access-32.bin sse-demo.bin sse-demo-32.bin + +mmio-access-y := mmio-access.o + +$(eval $(call DECLARE_32_BIT,mmio-access-32)) +mmio-access-32-y := mmio-access-32.o + +sse-demo-y := sse-demo.o + +$(eval $(call DECLARE_32_BIT,sse-demo-32)) +sse-demo-32-y := sse-demo-32.o + +$(obj)/sse-demo-32.o: $(src)/sse-demo.c FORCE + $(call if_changed_rule,cc_o_c) + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/tests/x86/mmio-access-32.c b/inmates/tests/x86/mmio-access-32.c new file mode 100644 index 0000000000000000000000000000000000000000..c8a56dcf491a1099ebb91ad057fea1ae83efcde1 --- /dev/null +++ b/inmates/tests/x86/mmio-access-32.c @@ -0,0 +1,157 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +void inmate_main(void) +{ + volatile u32 *comm_page_reg = (void *)(COMM_REGION_BASE + 0xff8); + void *mmio_reg = (void *)(COMM_REGION_BASE + 0x1ff8); + u32 pattern, reg32; + + printk("\n"); + + /* --- Read Tests --- */ + + pattern = 0x11223344; + mmio_write32(mmio_reg, pattern); + EXPECT_EQUAL(*comm_page_reg, pattern); + + /* MOV_FROM_MEM (8b), 16-bit data, 32-bit address, OP size prefix */ + asm volatile("mov (%%eax), %%ax" : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL((u16)reg32, (u16)pattern); + + /* MOV_FROM_MEM (8b), 32-bit data, 32-bit address */ + asm volatile("movl (%%ebx), %%eax" + : "=a" (reg32) : "a" (0), "b" (mmio_reg)); + EXPECT_EQUAL(reg32, pattern); + + /* MOV_FROM_MEM (8a), 8-bit data */ + asm volatile("movb (%%eax), %%al" + : "=a" (reg32) : "a" (mmio_reg)); + /* %al should contain 0x44, while higher bits still hold the rest of + * mmio_reg. Test this. */ + EXPECT_EQUAL(reg32, + ((unsigned long)mmio_reg & ~0xffUL) | (pattern & 0xff)); + + /* MOV_FROM_MEM (8a), 8-bit data, 32-bit address, OP size prefix */ + asm volatile("data16 mov (%%eax), %%al" + : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL(reg32, + ((unsigned long)mmio_reg & ~0xffUL) | (pattern & 0xff)); + + /* MOVZXB (0f b6), 8-bit data, 32-bit address, zero extend bits 8-31 */ + asm volatile("movzxb (%%eax), %%eax" + : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL(reg32, pattern & 0xff); + + /* MOVZXB (66 0f b6), 8-bit data, 32-bit address, zero extend bits 8-15, + * operand size prefix */ + asm volatile("movzxb (%%eax), %%ax" + : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL(reg32, + ((unsigned long)mmio_reg & ~0xffff) | (pattern & 0xff)); + + /* MOVZXW (0f b7), 16-bit data, 32-bit address, zero extend bits + * 16-31 */ + asm volatile("movzxw (%%eax), %%eax" + : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL(reg32, pattern & 0xffff); + + /* MOVZXW (66 0f b7), 16-bit data, 32-bit address, preserve bits 16-31. + * Practically working, but not specified by the manual (it's + * effectively a 16->16 move). */ + asm volatile(".byte 0x66, 0x0f, 0xb7, 0x00" + : "=a" (reg32) : "a" (mmio_reg)); + EXPECT_EQUAL(reg32, ((unsigned long)mmio_reg & ~0xffff) | + (pattern & 0xffff)); + + /* MEM_TO_AX (a1), 32-bit data, 32-bit address */ + asm volatile("mov (0x101ff8), %%eax" + : "=a" (reg32) : "a" (0)); + EXPECT_EQUAL(reg32, pattern); + + printk("MMIO read test %s\n\n", all_passed ? "passed" : "FAILED"); + + /* --- Write Tests --- */ + + all_passed = true; + pattern = 0x8899aabb; + mmio_write32(mmio_reg, ~pattern); + EXPECT_EQUAL(*comm_page_reg, ~pattern); + + /* MOV_TO_MEM (89), 32-bit data, mod=0, reg=0, rm=4, SIB.base=5 (disp32) */ + asm volatile("movl %%eax, (0x101ff8)" + : : "a" (pattern)); + EXPECT_EQUAL(*comm_page_reg, pattern); + + /* MOV_TO_MEM (88), 8-bit data */ + asm volatile("movb %%al, (%%ebx)" + : : "a" (0x42), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffUL) | 0x42); + + /* MOV_TO_MEM (88), 8-bit data, OP size prefix */ + asm volatile("data16 mov %%al, (%%ebx)" : : "a" (0x23), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffUL) | 0x23); + + /* MOV_TO_MEM (89), 16-bit data, OP size prefix */ + asm volatile("mov %%ax, (%%ebx)" : : "a" (0x2342), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffffUL) | 0x2342); + + /* IMMEDIATE_TO_MEM (c7), 32-bit data, mod=0, reg=0, rm=3 */ + asm volatile("movl %0, (%%ebx)" + : : "i" (0x12345678), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* IMMEDIATE_TO_MEM (c7), 32-bit data, mod=1 (disp8), reg=0, rm=3 */ + asm volatile("movl %0, 0x10(%%ebx)" + : : "i" (0x11223344), "b" (mmio_reg - 0x10)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344); + + /* IMMEDIATE_TO_MEM (c7), 32-bit data, mod=2 (disp32), reg=0, rm=3 */ + asm volatile("movl %0, 0x10000000(%%ebx)" + : : "i" (0xccddeeff), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0xccddeeff); + + /* MOVB_TO_MEM (88), mod=0, reg=0, rm=3 */ + asm volatile("mov %%al, (%%ebx)" + : : "a" (0x99), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0xccddee99); + + /* MOV_TO_MEM (89), 32-bit data, mod=1 (disp8), reg=0, rm=3 */ + asm volatile("movl %%eax, 0x10(%%ebx)" + : : "a" (0x12345678), "b" (mmio_reg - 0x10)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* MOV_TO_MEM (89), 32-bit data, mod=2 (disp32), reg=0, rm=3 */ + asm volatile("movl %%eax, 0x10000000(%%ebx)" + : : "a" (0x12345678), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* MOV_TO_MEM (89), 32-bit data, 32-bit address */ + asm volatile("movl %%eax, 0x10000000(%%ebx)" + : : "a" (0x87654321), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x87654321); + + /* MOV_TO_MEM (89), 32-bit data, mod=0, reg=0, rm=4 (SIB) */ + asm volatile("movl %%eax, (%%ebx,%%ecx)" + : : "a" (0x12345678), "b" (mmio_reg), "c" (0)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* MOV_TO_MEM (89), 32-bit data, mod=2 (disp32), reg=0, rm=4 (SIB) */ + asm volatile("movl %%eax, 0x10000000(%%ebx,%%ecx)" + : : "a" (0x87654321), "b" (mmio_reg - 0x10000000), "c" (0)); + EXPECT_EQUAL(*comm_page_reg, 0x87654321); + + printk("MMIO write test %s\n", all_passed ? "passed" : "FAILED"); +} diff --git a/inmates/tests/x86/mmio-access.c b/inmates/tests/x86/mmio-access.c new file mode 100644 index 0000000000000000000000000000000000000000..ea07fd325a87f738f7496417e275a0cddd520156 --- /dev/null +++ b/inmates/tests/x86/mmio-access.c @@ -0,0 +1,308 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +extern u8 __reset_entry[]; /* assumed to be at 0 */ + +/* + * mmio-access tests different memory access strategies that are intercepted by + * the hypervisor. Therefore, it maps a second page right behind the + * comm_region. Access to 0xff8-0xfff within that page will be intercepted by + * the hypervisor. The hypervisor will redirect the access to the comm_region. + * By reading back those values from the comm_region, we can verify that the + * access was successful. + */ +void inmate_main(void) +{ + volatile u64 *comm_page_reg = (void *)(COMM_REGION_BASE + 0xff8); + void *mmio_reg = (void *)(COMM_REGION_BASE + 0x1ff8); + u64 pattern, reg64; + + printk("\n"); + + /* --- Read Tests --- */ + + pattern = 0x1122334455667788; + mmio_write64(mmio_reg, pattern); + EXPECT_EQUAL(*comm_page_reg, pattern); + + /* MOV_FROM_MEM (8b), 16-bit data, Ox66 OP size prefix */ + asm volatile("mov (%%rax), %%ax" : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL((u16)reg64, (u16)pattern); + + /* MOV_FROM_MEM (8b), 64-bit data, mod=0, reg=0, rm=3 */ + asm volatile("movq (%%rbx), %%rax" + : "=a" (reg64) : "a" (0), "b" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern); + + /* MOV_FROM_MEM (8b), 32-bit data */ + asm volatile("movl (%%rbx), %%eax" + : "=a" (reg64) : "a" (0), "b" (mmio_reg)); + EXPECT_EQUAL(reg64, (u32)pattern); + + /* MOV_FROM_MEM (8b), 32-bit data, 32-bit address */ + asm volatile("movl (%%ebx), %%eax" + : "=a" (reg64) : "a" (0), "b" (mmio_reg)); + EXPECT_EQUAL(reg64, (u32)pattern); + + /* MOV_FROM_MEM (8a), 8-bit data */ + asm volatile("movb (%%rax), %%al" + : "=a" (reg64) : "a" (mmio_reg)); + /* %al should contain 0x88, while high bits should still hold the rest + * of mmio_reg */ + EXPECT_EQUAL(reg64, + ((unsigned long)mmio_reg & ~0xffUL) | (pattern & 0xff)); + + /* MOV_FROM_MEM (8a), 8-bit data, 0x66 OP size prefix (ignored) */ + asm volatile("data16 mov (%%rax), %%al" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, + ((unsigned long)mmio_reg & ~0xffUL) | (pattern & 0xff)); + + /* MOVZX test cases */ + + /* + * First three tests: MOVZXB (0f b6) with 64-bit address, varying + * register width (rax, eax, ax) + */ + + /* MOVZXB (48 0f b6), 8-bit data, 64-bit address, clear bits 8-63 */ + asm volatile("movzxb (%%rax), %%rax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xff); + + /* MOVZXB (0f b6), 8-bit data, 64-bit address, clear bits 8-63 + * Exposes the same behaviour as 48 0f b6. */ + asm volatile("movzxb (%%rax), %%eax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xff); + + /* MOVZXB (66 0f b6), 8-bit data, clear bits 8-15, preserve 16-63, + * operand size prefix */ + asm volatile("movzxb (%%rax), %%ax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, + ((unsigned long)mmio_reg & ~0xffffUL) | (pattern & 0xff)); + + /* + * Second three tests: MOVZXB (0f b6) with 32-bit address, varying + * register width (rax, eax, ax). + * + * These pattern will cover cases, where we have, e.g., both operand + * prefixes (address size override prefix and operand size override + * prefix), and a REX + adress size override prefix. + */ + + /* MOVZXB (67 48 0f b6), 8-bit data, clear bits 8-63, 32-bit address, + * REX_W, AD SZ override prefix */ + asm volatile("movzxb (%%eax), %%rax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xff); + + /* MOVZXB (67 0f b6), 8-bit data, clear bits 8-63, 32-bit address, + * AD SZ override prefix. Exposes the same behaviour as 67 48 0f b6. */ + asm volatile("movzxb (%%eax), %%eax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xff); + + /* MOVZXB (67 66 0f b6), 8-bit data, clear bits 8-15, preserve 16-63, + * 32-bit address, AD SZ override prefix, OP SZ override prefix */ + asm volatile("movzxb (%%eax), %%ax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, + ((unsigned long)mmio_reg & ~0xffffUL) | (pattern & 0xff)); + + /* + * Three tests for: MOVZXW (0f b7) with 64-bit address, varying + * register width (rax, eax, ax). + */ + + /* MOVZXW (48 0f b7), 16-bit data, clear bits 16-63, 64-bit address */ + asm volatile("movzxw (%%rax), %%rax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xffff); + + /* MOVZXW (0f b7), 16-bit data, clear bits 16-63, 64-bit address. + * Exposes the same behaviour as 48 0f b7. */ + asm volatile("movzxw (%%rax), %%eax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xffff); + + /* MOVZXW (66 0f b7), 16-bit data, preserve bits 16-63, OP SZ prefix. + * Practically working, but not specified by the manual (it's + * effectively a 16->16 move). */ + asm volatile(".byte 0x66, 0x0f, 0xb7, 0x00" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, ((unsigned long)mmio_reg & ~0xffffUL) | + (pattern & 0xffff)); + + /* + * Last but not least: MOVZXW (0f b7) with 32-bit address, varying + * register width (rax, eax, ax). + */ + + /* MOVZXW (67 48 0f b7), 16-bit data, clear bits 16-63, 32-bit address, + * AD SZ prefix, REX_W */ + asm volatile("movzxw (%%eax), %%rax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xffff); + + /* MOVZXW (67 0f b7), 16-bit data, clear bits 16-63, 32-bit address, + * AD SZ prefix. Exposes same behaviour as 67 48 0f b7. */ + asm volatile("movzxw (%%eax), %%eax" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, pattern & 0xffff); + + /* MOVZXW (67 66 0f b7), 16-bit data, preserve bits 16-63, 32-bit address, + * AD SZ prefix, OP SZ prefix. See also 66 0f b7: not an official + * instruction */ + asm volatile(".byte 0x67, 0x66, 0x0f, 0xb7, 0x00" + : "=a" (reg64) : "a" (mmio_reg)); + EXPECT_EQUAL(reg64, ((unsigned long)mmio_reg & ~0xffffUL) | + (pattern & 0xffff)); + + /* MEM_TO_AX (a1), 64-bit data, 64-bit address */ + asm volatile("movabs (0x101ff8), %%rax" + : "=a" (reg64) : "a" (0)); + EXPECT_EQUAL(reg64, pattern); + + /* MEM_TO_AX (a1), 32-bit data, 64-bit address */ + asm volatile("movabs (0x101ff8), %%eax" + : "=a" (reg64) : "a" (0)); + EXPECT_EQUAL(reg64, (u32)pattern); + + reg64 = 0ULL; + /* MEM_TO_AX (a1), 64-bit data, 32-bit address, AD SZ override prefix */ + asm volatile("addr32 mov 0x101ff8, %%rax" + : "=a" (reg64) : "a" (0)); + EXPECT_EQUAL(reg64, pattern); + + printk("MMIO read test %s\n\n", all_passed ? "passed" : "FAILED"); + + /* --- Write Tests --- */ + + all_passed = true; + pattern = 0x8899aabbccddeeff; + mmio_write64(mmio_reg, ~pattern); + EXPECT_EQUAL(*comm_page_reg, ~pattern); + + /* MOV_TO_MEM (89), 64-bit data, mod=0, reg=0, rm=4, SIB.base=5 (disp32) */ + asm volatile("movq %%rax, (0x101ff8)" + : : "a" (pattern)); + EXPECT_EQUAL(*comm_page_reg, pattern); + + pattern = ~pattern; + /* MOV_TO_MEM (89), 64-bit data, mod=0, reg=0, rm=5 (rip+disp32) */ + asm volatile("movq %%rax, __reset_entry+0x101ff8(%%rip)" + : : "a" (pattern)); + EXPECT_EQUAL(*comm_page_reg, pattern); + + /* MOV_TO_MEM (88), 8-bit data */ + asm volatile("movb %%al, (%%rbx)" + : : "a" (0x42), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffUL) | 0x42); + + /* MOV_TO_MEM (88), 8-bit data, OP size prefix */ + asm volatile("data16 mov %%al, (%%rbx)" : : "a" (0x23), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffUL) | 0x23); + + /* MOV_TO_MEM (89), 16-bit data, OP size prefix */ + asm volatile("mov %%ax, (%%rbx)" : : "a" (0x2342), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, (pattern & ~0xffffUL) | 0x2342); + + /* IMMEDIATE_TO_MEM (c7), 64-bit data, mod=0, reg=0, rm=3 */ + asm volatile("movq %0, (%%rbx)" + : : "i" (0x12345678), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* IMMEDIATE_TO_MEM (c7), 64-bit data, mod=0, reg=0, rm=3, sign-extend */ + asm volatile("movq %0, (%%rbx)" + : : "i" (0xccddeeff), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0xffffffffccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data */ + asm volatile("movl %0, (%%rbx)" + : : "i" (0xccddeeff), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data, 32-bit address */ + asm volatile("movl %0, (%%ebx)" + : : "i" (0xccddeeff), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data, mod=1 (disp8), reg=0, rm=3 */ + asm volatile("movl %0, 0x10(%%rbx)" + : : "i" (0xccddeeff), "b" (mmio_reg - 0x10)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data, 32-bit address */ + asm volatile("movl %0, 0x10(%%ebx)" + : : "i" (0xccddeeff), "b" (mmio_reg - 0x10)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data, mod=2 (disp32), reg=0, rm=3 */ + asm volatile("movl %0, 0x10000000(%%rbx)" + : : "i" (0xccddeeff), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* IMMEDIATE_TO_MEM (c7), 32-bit data, 32-bit address */ + asm volatile("movl %0, 0x10000000(%%ebx)" + : : "i" (0xccddeeff), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddeeff); + + /* MOVB_TO_MEM (88), mod=0, reg=0, rm=3 */ + asm volatile("mov %%al, (%%rbx)" + : : "a" (0x99), "b" (mmio_reg)); + EXPECT_EQUAL(*comm_page_reg, 0x11223344ccddee99); + + /* MOV_TO_MEM (89), 64-bit data, mod=1 (disp8), reg=0, rm=3 */ + asm volatile("movq %%rax, 0x10(%%rbx)" + : : "a" (0x12345678), "b" (mmio_reg - 0x10)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* MOV_TO_MEM (89), 64-bit data, mod=2 (disp32), reg=0, rm=3 */ + asm volatile("movq %%rax, 0x10000000(%%rbx)" + : : "a" (0x12345678), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + mmio_write64(mmio_reg, 0x1122334455667788); + /* MOV_TO_MEM (89), 64-bit data, 32-bit address */ + asm volatile("movq %%rax, 0x10000000(%%ebx)" + : : "a" (0x8765432112345678), "b" (mmio_reg - 0x10000000)); + EXPECT_EQUAL(*comm_page_reg, 0x8765432112345678); + + /* MOV_TO_MEM (89), 64-bit data, mod=0, reg=0, rm=4 (SIB) */ + asm volatile("movq %%rax, (%%rbx,%%rcx)" + : : "a" (0x12345678), "b" (mmio_reg), "c" (0)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + /* MOV_TO_MEM (89), 64-bit data, mod=2 (disp32), reg=0, rm=4 (SIB) */ + asm volatile("movq %%rax, 0x10000000(%%rbx,%%rcx)" + : : "a" (0x12345678), "b" (mmio_reg - 0x10000000), "c" (0)); + EXPECT_EQUAL(*comm_page_reg, 0x12345678); + + pattern = 0xdeadbeef; + /* AX_TO_MEM (a3), 32-bit data, 32-bit address */ + asm volatile(".byte 0x67, 0x48, 0xa3, 0xf8, 0x1f, 0x10, 0x00" + : : "a" (pattern)); + EXPECT_EQUAL(mmio_read32(mmio_reg), (u32)pattern); + + printk("MMIO write test %s\n", all_passed ? "passed" : "FAILED"); +} diff --git a/inmates/tests/x86/sse-demo.c b/inmates/tests/x86/sse-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..6b0801ca2bafdd2e09e38667400fc5dcb72c5246 --- /dev/null +++ b/inmates/tests/x86/sse-demo.c @@ -0,0 +1,89 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2019 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include + +typedef u64 xmm_t __attribute__((vector_size(16))); + +void inmate_main(void) +{ + xmm_t x_a, x_b, x_result; + float f_addend, f_result; + double d_a, d_b, d_result; + + printk("CPU supports\n" + " FPU: %u FXSR: %u XSAVE: %u\n" + " SSE: %u SSE2: %u SSE3: %u\n" + " SSE4_1: %u SSE4_2: %u AVX: %u\n" + " PCLMULQDQ: %u\n\n", + x86_cpu_features.fpu, x86_cpu_features.fxsr, + x86_cpu_features.xsave, x86_cpu_features.sse, + x86_cpu_features.sse2, x86_cpu_features.sse3, + x86_cpu_features.sse4_1, x86_cpu_features.sse4_2, + x86_cpu_features.avx, x86_cpu_features.pclmulqdq); + + if (x86_cpu_features.fpu) { + f_addend = 123.45; + f_result = 543.55; + + printk("Testing SSE...\n"); + asm volatile("addps %1, %0\t\n" + : "+x" (f_result) : "x" (f_addend)); + /* Test raw result */ + EXPECT_EQUAL(*(u32*)&f_result, 0x4426c000); + } + + + d_a = 123.45; + d_b = 543.55; + + if (x86_cpu_features.sse2) { + printk("Testing SSE2...\n"); + d_result = d_b; + asm volatile("addsd %1, %0\t\n" + : "+x" (d_result) : "m" (d_a)); + EXPECT_EQUAL(d_result, 667); + } + + if (x86_cpu_features.avx) { + d_result = 0; + printk("Testing AVX...\n"); + asm volatile("vaddsd %2, %1, %0\t\n" + : "=x" (d_result) : "x" (d_a), "m" (d_b)); + EXPECT_EQUAL(d_result, 667); + } + + x_a[0] = 0x00017004200ab0cd; + x_a[1] = 0xc000b802f6b31753; + x_b[0] = 0xa0005c0252074a9a; + x_b[1] = 0x50002e0207b1643c; + + if (x86_cpu_features.pclmulqdq && x86_cpu_features.avx) { + printk("Testing AVX PCLMULQDQ...\n"); + asm volatile("vpclmulqdq %3, %2, %1, %0\t\n" + : "=x" (x_result) : "x" (x_a), "x" (x_b), "i" (0)); + + EXPECT_EQUAL(x_result[0], 0x5ff61cc8b1043fa2); + EXPECT_EQUAL(x_result[1], 0x00009602d147dc12); + } + + if (x86_cpu_features.pclmulqdq) { + printk("Testing PCLMULQDQ...\n"); + asm volatile("pclmulqdq %2, %1, %0\t\n" + : "+x" (x_a) : "x" (x_b), "i" (0)); + + EXPECT_EQUAL(x_a[0], 0x5ff61cc8b1043fa2); + EXPECT_EQUAL(x_a[1], 0x00009602d147dc12); + } +} diff --git a/inmates/tools/arm/Makefile b/inmates/tools/arm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a722777f61c7c68dd03b239bbb52b37fd2d173c --- /dev/null +++ b/inmates/tools/arm/Makefile @@ -0,0 +1,19 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2015 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := linux-loader.bin + +linux-loader-y := linux-loader.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/tools/arm/linux-loader.c b/inmates/tools/arm/linux-loader.c new file mode 100644 index 0000000000000000000000000000000000000000..6da4296c167a014f8745d551bda322d93fef663d --- /dev/null +++ b/inmates/tools/arm/linux-loader.c @@ -0,0 +1,53 @@ +/* + * Jailhouse ARM support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * Copyright (c) Siemens AG, 2016 + * + * Authors: + * Dmitry Voytik + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +void inmate_main(void) +{ + void register (*entry)(unsigned long, unsigned long, unsigned long); + unsigned long register dtb, sctlr; + + entry = (void *)(unsigned long)cmdline_parse_int("kernel", 0); + dtb = cmdline_parse_int("dtb", 0); + + /* + * Linux wants the MMU and D-caches to be disabled. + * As we didn't write anything relevant to the caches so far, we can + * get away without flushing. + */ + arm_read_sysreg(SCTLR, sctlr); + sctlr &= ~(SCTLR_C | SCTLR_M); + + /* + * This is a pendant for + * arm_write_sysreg(SCTLR, sctlr); + * instruction_barrier(); + * entry(0, -1, dtb); + * + * After disabling the MMU, we must not touch the stack because we don't + * flush+inval dcaches, and the compiler might use the stack between + * calling entry. Assembly ensures that everything relevant is kept in + * registers. + */ + asm volatile( + "mov r0, #0\n\t" + "mov r1, #-1\n\t" + "mov r2, %0\n\t" + "mcr p15, 0, %1, c1, c0, 0\n\t" + "isb\n\t" + "bx %2\n\t" /* entry(0, -1, dtb) */ + : : "r" (dtb), "r" (sctlr), "r" (entry) : "r0", "r1", "r2"); +} diff --git a/inmates/tools/arm64/Makefile b/inmates/tools/arm64/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a722777f61c7c68dd03b239bbb52b37fd2d173c --- /dev/null +++ b/inmates/tools/arm64/Makefile @@ -0,0 +1,19 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2015 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := linux-loader.bin + +linux-loader-y := linux-loader.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/tools/arm64/linux-loader.c b/inmates/tools/arm64/linux-loader.c new file mode 100644 index 0000000000000000000000000000000000000000..b7c942351128ac85385314555356bec7f88fac88 --- /dev/null +++ b/inmates/tools/arm64/linux-loader.c @@ -0,0 +1,53 @@ +/* + * Jailhouse AArch64 support + * + * Copyright (C) 2015 Huawei Technologies Duesseldorf GmbH + * + * Authors: + * Dmitry Voytik + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +void inmate_main(void) +{ + unsigned long dtb, sctlr; + void (*entry)(u64 dtb, u64 x1, u64 x2, u64 x3); + + entry = (void *)cmdline_parse_int("kernel", 0); + dtb = cmdline_parse_int("dtb", 0); + + /* + * Linux wants the MMU to be disabled + * As we didn't write anything relevant to the caches so far, we can + * get away without flushing. + */ + arm_read_sysreg(SCTLR_EL1, sctlr); + sctlr &= ~SCTLR_EL1_M; + + /* + * This is a pendant for + * arm_write_sysreg(SCTLR_EL1, sctlr); + * instruction_barrier(); + * entry(dtb, 0, 0, 0); + * + * After disabling the MMU, we must not touch the stack because we don't + * flush+inval dcaches, and the compiler might use the stack between + * calling entry. Assembly ensures that everything relevant is kept in + * registers. + */ + asm volatile( + "mov x0, %0\n\t" + "mov x1, #0\n\t" + "mov x2, #0\n\t" + "mov x3, #0\n\t" + "msr sctlr_el1, %1\n\t" + "isb\n\t" + "br %2" /* entry(dtb, 0, 0, 0) */ + : : "r" (dtb), "r" (sctlr), "r" (entry) + : "x0", "x1", "x2", "x3"); +} diff --git a/inmates/tools/x86/Makefile b/inmates/tools/x86/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a722777f61c7c68dd03b239bbb52b37fd2d173c --- /dev/null +++ b/inmates/tools/x86/Makefile @@ -0,0 +1,19 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2015 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(INMATES_LIB)/Makefile.lib + +INMATES := linux-loader.bin + +linux-loader-y := linux-loader.o + +$(eval $(call DECLARE_TARGETS,$(INMATES))) diff --git a/inmates/tools/x86/linux-loader.c b/inmates/tools/x86/linux-loader.c new file mode 100644 index 0000000000000000000000000000000000000000..5a42e96246ac823adbe7dec42b6b858cefc4f075 --- /dev/null +++ b/inmates/tools/x86/linux-loader.c @@ -0,0 +1,69 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2015 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +struct boot_params { + u8 padding1[0x230]; + u32 kernel_alignment; + u8 padding2[0x250 - 0x230 - 4]; + u64 setup_data; + u8 padding3[8]; + u32 init_size; +} __attribute__((packed)); + +struct setup_data { + u64 next; + u32 type; + u32 length; + u16 version; + u16 compatible_version; + u16 pm_timer_address; + u16 num_cpus; + u64 pci_mmconfig_base; + u32 tsc_khz; + u32 apic_khz; + u8 standard_ioapic; + u8 cpu_ids[SMP_MAX_CPUS]; + /* Flags bits 0-3: has access to platform UART n */ + u32 flags; +} __attribute__((packed)); + +/* We use the cmdline section for zero page and setup data. */ +static union { + struct boot_params params; + char __reservation[PAGE_SIZE * 3]; +} boot __attribute__((section(".cmdline"))); + +void inmate_main(void) +{ + void (*entry)(int, struct boot_params *); + struct setup_data *setup_data; + void *kernel; + + kernel = (void *)(unsigned long)boot.params.kernel_alignment; + + map_range(kernel, boot.params.init_size, MAP_CACHED); + + setup_data = (struct setup_data *)boot.params.setup_data; + setup_data->pm_timer_address = comm_region->pm_timer_address; + setup_data->pci_mmconfig_base = comm_region->pci_mmconfig_base; + setup_data->tsc_khz = comm_region->tsc_khz; + setup_data->apic_khz = comm_region->apic_khz; + setup_data->num_cpus = comm_region->num_cpus; + + smp_wait_for_all_cpus(); + memcpy(setup_data->cpu_ids, smp_cpu_ids, SMP_MAX_CPUS); + + entry = kernel + 0x200; + entry(0, &boot.params); +} diff --git a/pyjailhouse/__init__.py b/pyjailhouse/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pyjailhouse/cell.py b/pyjailhouse/cell.py new file mode 100644 index 0000000000000000000000000000000000000000..afe7ca8a30973d9582bf363a359754e5bb5aff44 --- /dev/null +++ b/pyjailhouse/cell.py @@ -0,0 +1,49 @@ + +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015-2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +import ctypes +import errno +import fcntl +import struct + + +class JailhouseCell: + JAILHOUSE_CELL_CREATE = 0x40100002 + JAILHOUSE_CELL_LOAD = 0x40300003 + JAILHOUSE_CELL_START = 0x40280004 + + JAILHOUSE_CELL_ID_UNUSED = -1 + + def __init__(self, config): + self.name = config.name.encode() + + self.dev = open('/dev/jailhouse') + + cbuf = ctypes.create_string_buffer(config.data) + create = struct.pack('QI4x', ctypes.addressof(cbuf), len(config.data)) + try: + fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_CREATE, create) + except IOError as e: + if e.errno != errno.EEXIST: + raise e + + def load(self, image, address): + cbuf = ctypes.create_string_buffer(bytes(image)) + + load = struct.pack('i4x32sI4xQQQ8x', + JailhouseCell.JAILHOUSE_CELL_ID_UNUSED, self.name, + 1, ctypes.addressof(cbuf), len(image), address) + fcntl.ioctl(self.dev, self.JAILHOUSE_CELL_LOAD, load) + + def start(self): + start = struct.pack('i4x32s', JailhouseCell.JAILHOUSE_CELL_ID_UNUSED, + self.name) + fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_START, start) diff --git a/pyjailhouse/config_parser.py b/pyjailhouse/config_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..7a7f48a3e9a04fe7eb55d529965a55c187f3ea86 --- /dev/null +++ b/pyjailhouse/config_parser.py @@ -0,0 +1,297 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015-2020 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# This script should help to create a basic jailhouse configuration file. +# It needs to be executed on the target machine, where it will gather +# information about the system. For more advanced scenarios you will have +# to change the generated C-code. + +import struct + +from .extendedenum import ExtendedEnum + +# Keep the whole file in sync with include/jailhouse/cell-config.h. +_CONFIG_REVISION = 13 + + +def flag_str(enum_class, value, separator=' | '): + flags = [] + while value: + mask = 1 << (value.bit_length() - 1) + flags.insert(0, str(enum_class(mask))) + value &= ~mask + return separator.join(flags) + + +class JAILHOUSE_MEM(ExtendedEnum, int): + _ids = { + 'READ': 0x00001, + 'WRITE': 0x00002, + 'EXECUTE': 0x00004, + 'DMA': 0x00008, + 'IO': 0x00010, + 'COMM_REGION': 0x00020, + 'LOADABLE': 0x00040, + 'ROOTSHARED': 0x00080, + 'NO_HUGEPAGES': 0x00100, + 'IO_UNALIGNED': 0x08000, + 'IO_8': 0x10000, + 'IO_16': 0x20000, + 'IO_32': 0x40000, + 'IO_64': 0x80000, + } + + +class MemRegion: + _REGION_FORMAT = 'QQQQ' + SIZE = struct.calcsize(_REGION_FORMAT) + + def __init__(self, region_struct): + (self.phys_start, + self.virt_start, + self.size, + self.flags) = \ + struct.unpack_from(MemRegion._REGION_FORMAT, region_struct) + + def __str__(self): + return (" phys_start: 0x%016x\n" % self.phys_start) + \ + (" virt_start: 0x%016x\n" % self.virt_start) + \ + (" size: 0x%016x\n" % self.size) + \ + (" flags: " + flag_str(JAILHOUSE_MEM, self.flags)) + + def is_ram(self): + return ((self.flags & (JAILHOUSE_MEM.READ | + JAILHOUSE_MEM.WRITE | + JAILHOUSE_MEM.EXECUTE | + JAILHOUSE_MEM.DMA | + JAILHOUSE_MEM.IO | + JAILHOUSE_MEM.COMM_REGION | + JAILHOUSE_MEM.ROOTSHARED)) == + (JAILHOUSE_MEM.READ | + JAILHOUSE_MEM.WRITE | + JAILHOUSE_MEM.EXECUTE | + JAILHOUSE_MEM.DMA)) + + def is_comm_region(self): + return (self.flags & JAILHOUSE_MEM.COMM_REGION) != 0 + + def phys_address_in_region(self, address): + return address >= self.phys_start and \ + address < (self.phys_start + self.size) + + def phys_overlaps(self, region): + if self.size == 0 or region.size == 0: + return False + return region.phys_address_in_region(self.phys_start) or \ + self.phys_address_in_region(region.phys_start) + + def virt_address_in_region(self, address): + return address >= self.virt_start and \ + address < (self.virt_start + self.size) + + def virt_overlaps(self, region): + if self.size == 0 or region.size == 0: + return False + return region.virt_address_in_region(self.virt_start) or \ + self.virt_address_in_region(region.virt_start) + + +class CacheRegion: + _REGION_FORMAT = 'IIBxH' + SIZE = struct.calcsize(_REGION_FORMAT) + + +class Irqchip: + _IRQCHIP_FORMAT = 'QIIQQ' + SIZE = struct.calcsize(_IRQCHIP_FORMAT) + + def __init__(self, irqchip_struct): + (self.address, + self.id, + self.pin_base, + self.pin_bitmap_lo, + self.pin_bitmap_hi) = \ + struct.unpack_from(self._IRQCHIP_FORMAT, irqchip_struct) + + def is_standard(self): + return self.address == 0xfec00000 + + +class PIORegion: + _REGION_FORMAT = 'HH' + SIZE = struct.calcsize(_REGION_FORMAT) + + def __init__(self, pio_struct): + (self.base, self.length) = struct.unpack_from(self._REGION_FORMAT, + pio_struct) + + +class CellConfig: + _HEADER_FORMAT = '=6sH32s4xIIIIIIIIIIQ8x32x' + + def __init__(self, data, root_cell=False): + self.data = data + + try: + (signature, + revision, + name, + self.flags, + self.cpu_set_size, + self.num_memory_regions, + self.num_cache_regions, + self.num_irqchips, + self.num_pio_regions, + self.num_pci_devices, + self.num_pci_caps, + self.num_stream_ids, + self.vpci_irq_base, + self.cpu_reset_address) = \ + struct.unpack_from(CellConfig._HEADER_FORMAT, self.data) + if not root_cell: + if signature != b'JHCELL': + raise RuntimeError('Not a cell configuration') + if revision != _CONFIG_REVISION: + raise RuntimeError('Configuration file revision mismatch') + self.name = str(name.decode().strip('\0')) + + mem_region_offs = struct.calcsize(CellConfig._HEADER_FORMAT) + \ + self.cpu_set_size + self.memory_regions = [] + for n in range(self.num_memory_regions): + self.memory_regions.append( + MemRegion(self.data[mem_region_offs:])) + mem_region_offs += MemRegion.SIZE + + irqchip_offs = mem_region_offs + \ + self.num_cache_regions * CacheRegion.SIZE + self.irqchips = [] + for n in range(self.num_irqchips): + self.irqchips.append( + Irqchip(self.data[irqchip_offs:])) + irqchip_offs += Irqchip.SIZE + + pioregion_offs = irqchip_offs + self.pio_regions = [] + for n in range(self.num_pio_regions): + self.pio_regions.append(PIORegion(self.data[pioregion_offs:])) + pioregion_offs += PIORegion.SIZE + except struct.error: + raise RuntimeError('Not a %scell configuration' % + ('root ' if root_cell else '')) + + +class JAILHOUSE_IOMMU(ExtendedEnum, int): + _ids = { + 'UNUSED': 0, + 'AMD': 1, + 'INTEL': 2, + 'SMMUV3': 3, + 'TIPVU': 4, + 'ARM_MMU500': 5, + } + + +class IOMMU: + _IOMMU_HEADER_FORMAT = '=IQI' + _IOMMU_AMD_FORMAT = '=HBBI2x' + _IOMMU_TIPVU_FORMAT = '=QI' + _IOMMU_OTHER_FORMAT = '12x' + SIZE = struct.calcsize(_IOMMU_HEADER_FORMAT + _IOMMU_OTHER_FORMAT) + + def __init__(self, iommu_struct): + (self.type, + self.base, + self.size) = \ + struct.unpack_from(self._IOMMU_HEADER_FORMAT, iommu_struct) + + offs = struct.calcsize(self._IOMMU_HEADER_FORMAT) + if self.type == JAILHOUSE_IOMMU.AMD: + (self.amd_bdf, + self.amd_base_cap, + self.amd_msi_cap, + self.amd_features) = \ + struct.unpack_from(self._IOMMU_AMD_FORMAT, iommu_struct[offs:]) + elif self.type == JAILHOUSE_IOMMU.TIPVU: + (self.tipvu_tlb_base, + self.tipvu_tlb_size) = \ + struct.unpack_from(self._IOMMU_TIPVU_FORMAT, + iommu_struct[offs:]) + elif not self.type in (JAILHOUSE_IOMMU.UNUSED, + JAILHOUSE_IOMMU.INTEL, + JAILHOUSE_IOMMU.SMMUV3, + JAILHOUSE_IOMMU.ARM_MMU500): + raise RuntimeError('Unknown IOMMU type: %d' % self.type) + + +class SystemConfig: + _HEADER_FORMAT = '=6sH4x' + # ...followed by MemRegion as hypervisor memory + _CONSOLE_FORMAT = '32x' + _PCI_FORMAT = '=QBBH' + _NUM_IOMMUS = 8 + _ARCH_ARM_FORMAT = '=BB2xQQQQQ' + _ARCH_X86_FORMAT = '=HBxIII28x' + + def __init__(self, data, arch): + self.data = data + + try: + (signature, + revision) = \ + struct.unpack_from(self._HEADER_FORMAT, self.data) + + if signature != b'JHSYST': + raise RuntimeError('Not a root cell configuration') + if revision != _CONFIG_REVISION: + raise RuntimeError('Configuration file revision mismatch') + + offs = struct.calcsize(self._HEADER_FORMAT) + self.hypervisor_memory = MemRegion(self.data[offs:]) + + offs += struct.calcsize(MemRegion._REGION_FORMAT) + offs += struct.calcsize(self._CONSOLE_FORMAT) + (self.pci_mmconfig_base, + self.pci_mmconfig_end_bus, + self.pci_is_virtual, + self.pci_domain) = \ + struct.unpack_from(self._PCI_FORMAT, self.data[offs:]) + + offs += struct.calcsize(self._PCI_FORMAT) + self.iommus = [] + for n in range(self._NUM_IOMMUS): + iommu = IOMMU(self.data[offs:]) + if iommu.type != JAILHOUSE_IOMMU.UNUSED: + self.iommus.append(iommu) + offs += IOMMU.SIZE + + if arch in ('arm', 'arm64'): + (self.arm_maintenance_irq, + self.arm_gic_version, + self.arm_gicd_base, + self.arm_gicc_base, + self.arm_gich_base, + self.arm_gicv_base, + self.arm_gicr_base) = \ + struct.unpack_from(self._ARCH_ARM_FORMAT, self.data[offs:]) + elif arch == 'x86': + (self.x86_pm_timer_address, + self.x86_apic_mode, + self.x86_vtd_interrupt_limit, + self.x86_tsc_khz, + self.x86_apic_khz) = \ + struct.unpack_from(self._ARCH_X86_FORMAT, self.data[offs:]) + + offs += struct.calcsize(self._ARCH_ARM_FORMAT) + except struct.error: + raise RuntimeError('Not a root cell configuration') + + self.root_cell = CellConfig(self.data[offs:], root_cell=True) diff --git a/pyjailhouse/extendedenum.py b/pyjailhouse/extendedenum.py new file mode 100644 index 0000000000000000000000000000000000000000..bcb959bdb603926a1c00a69e0db215c5c820ae6b --- /dev/null +++ b/pyjailhouse/extendedenum.py @@ -0,0 +1,33 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) OTH Regensburg, 2019 +# +# Authors: +# Ralf Ramsauer +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +class ExtendedEnumMeta(type): + def __getattr__(cls, key): + return cls(cls._ids[key]) + + +class ExtendedEnum(metaclass=ExtendedEnumMeta): + def __init__(self, value): + self.value = value + + def __str__(self): + for key, value in self._ids.items(): + if value == self.value: + return '%s_%s' % (self.__class__.__name__, key) + + return '0x%x' % self.value + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return False diff --git a/pyjailhouse/sysfs_parser.py b/pyjailhouse/sysfs_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..35c597443f05140bec5a143e578e1839ddec0e2d --- /dev/null +++ b/pyjailhouse/sysfs_parser.py @@ -0,0 +1,1071 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014-2017 +# Copyright (c) Valentine Sinitsyn, 2014-2015 +# +# Authors: +# Henning Schild +# Jan Kiszka +# Valentine Sinitsyn +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# This script should help to create a basic jailhouse configuration file. +# It needs to be executed on the target machine, where it will gather +# information about the system. For more advanced scenarios you will have +# to change the generated C-code. + + +import re +import struct +import os +import fnmatch + +from .pci_defs import PCI_CAP_ID, PCI_EXT_CAP_ID + +root_dir = "/" +bdf_regex = re.compile(r'\w{4}:\w{2}:\w{2}\.\w') + + +def set_root_dir(dir): + global root_dir + root_dir = dir + + +inputs = { + 'files': set(), + 'files_opt': set(), + 'files_intel': set(), + 'files_amd': set() +} + +# required files +inputs['files'].add('/proc/iomem') +inputs['files'].add('/proc/cpuinfo') +inputs['files'].add('/proc/cmdline') +inputs['files'].add('/proc/ioports') +inputs['files'].add('/sys/bus/pci/devices/*/config') +inputs['files'].add('/sys/bus/pci/devices/*/resource') +inputs['files'].add('/sys/devices/system/cpu/cpu*/uevent') +inputs['files'].add('/sys/firmware/acpi/tables/APIC') +inputs['files'].add('/sys/firmware/acpi/tables/MCFG') +# optional files +inputs['files_opt'].add('/sys/class/dmi/id/product_name') +inputs['files_opt'].add('/sys/class/dmi/id/sys_vendor') +inputs['files_opt'].add('/sys/class/tty/*/iomem_base') +inputs['files_opt'].add('/sys/class/tty/*/iomem_reg_shift') +inputs['files_opt'].add('/sys/class/tty/*/io_type') +inputs['files_opt'].add('/sys/class/tty/*/port') +inputs['files_opt'].add('/sys/devices/jailhouse/enabled') +# platform specific files +inputs['files_intel'].add('/sys/firmware/acpi/tables/DMAR') +inputs['files_amd'].add('/sys/firmware/acpi/tables/IVRS') + + +def check_input_listed(name, optional=False): + set = inputs['files_opt'] + if optional is False: + set = inputs['files'] + cpuvendor = get_cpu_vendor() + if cpuvendor == 'GenuineIntel': + set = set.union(inputs['files_intel']) + elif cpuvendor == 'AuthenticAMD': + set = set.union(inputs['files_amd']) + + for file in set: + if fnmatch.fnmatch(name, file): + return True + raise RuntimeError('"' + name + '" is not a listed input file') + + +def input_open(name, mode='r', optional=False): + check_input_listed(name, optional) + try: + f = open(root_dir + name, mode) + except Exception as e: + if optional: + return open("/dev/null", mode) + raise e + return f + + +def input_listdir(dir, wildcards): + for w in wildcards: + check_input_listed(os.path.join(dir, w)) + dirs = os.listdir(root_dir + dir) + dirs.sort() + return dirs + + +def regions_split_by_kernel(tree): + kernel = [x for x in tree.children + if x.region.typestr.startswith('Kernel')] + if not kernel: + return [tree.region] + + r = tree.region + s = r.typestr + + kernel_start = kernel[0].region.start + kernel_stop = kernel[len(kernel) - 1].region.stop + + # align this for 16M, but only if we have enough space + kernel_stop = (kernel_stop & ~0xFFFFFF) + 0xFFFFFF + if kernel_stop > r.stop: + kernel_stop = r.stop + + result = [] + + # before Kernel if any + if r.start < kernel_start: + result.append(MemRegion(r.start, kernel_start - 1, s)) + + result.append(MemRegion(kernel_start, kernel_stop, "Kernel")) + + # after Kernel if any + if r.stop > kernel_stop: + result.append(MemRegion(kernel_stop + 1, r.stop, s)) + + return result + + +def parse_iomem_tree(tree): + regions = [] + dmar_regions = [] + + for tree in tree.children: + r = tree.region + s = r.typestr + + # System RAM on the first level will be added completely + # if it doesn't contain the kernel itself. If it does, + # we split it. + if tree.level == 1 and s == 'System RAM': + regions.extend(regions_split_by_kernel(tree)) + continue + + # blacklisted on all levels, covers both APIC and IOAPIC + if s.find('PCI MMCONFIG') >= 0 or s.find('APIC') >= 0: + continue + + # if the tree continues recurse further down ... + if tree.children: + (temp_regions, temp_dmar_regions) = parse_iomem_tree(tree) + regions.extend(temp_regions) + dmar_regions.extend(temp_dmar_regions) + continue + else: + # blacklisted if it has no children + if s.lower() == 'reserved': + continue + + # add all remaining leaves + regions.append(r) + + return regions, dmar_regions + + +def parse_iomem(pcidevices): + tree = IORegionTree.parse_io_file('/proc/iomem', MemRegion) + (regions, dmar_regions) = parse_iomem_tree(tree) + + rom_region = MemRegion(0xc0000, 0xdffff, 'ROMs') + add_rom_region = False + + ret = [] + for r in regions: + # Filter PCI buses in order to avoid mapping empty ones that might + # require interception when becoming non-empty. + # Exception: VGA region + if r.typestr.startswith('PCI Bus') and r.start != 0xa0000: + continue + + append_r = True + # filter the list for MSI-X pages + for d in pcidevices: + if r.start <= d.msix_address <= r.stop: + if d.msix_address > r.start: + head_r = MemRegion(r.start, d.msix_address - 1, + r.typestr, r.comments) + ret.append(head_r) + if d.msix_address + d.msix_region_size < r.stop: + tail_r = MemRegion(d.msix_address + d.msix_region_size, + r.stop, r.typestr, r.comments) + ret.append(tail_r) + append_r = False + break + # filter out the ROMs + if r.start >= rom_region.start and r.stop <= rom_region.stop: + add_rom_region = True + append_r = False + # filter out and save DMAR regions + if r.typestr.find('dmar') >= 0: + dmar_regions.append(r) + append_r = False + # filter out AMD IOMMU regions + if r.typestr.find('amd_iommu') >= 0: + append_r = False + # merge adjacent RAM regions + if append_r and len(ret) > 0: + prev = ret[-1] + if prev.is_ram() and r.is_ram() and prev.stop + 1 == r.start: + prev.stop = r.stop + append_r = False + if append_r: + ret.append(r) + + # add a region that covers all potential ROMs + if add_rom_region: + ret.append(rom_region) + + # newer Linux kernels will report the first page as reserved + # it is needed for CPU init so include it anyways + if ret[0].typestr == 'System RAM' and ret[0].start == 0x1000: + ret[0].start = 0 + + return ret, dmar_regions + + +def ioports_search_pci_devices(tree): + ret = [] + + if tree.region and bdf_regex.match(tree.region.typestr): + ret.append(tree.region) + else: + for subtree in tree: + ret += ioports_search_pci_devices(subtree) + + return ret + + +def parse_ioports(): + tree = IORegionTree.parse_io_file('/proc/ioports', PortRegion) + + pm_timer_base = tree.find_regions_by_name('ACPI PM_TMR') + if len(pm_timer_base) != 1: + raise RuntimeError('Found %u entries for ACPI PM_TMR (expected 1)' % + len(pm_timer_base)) + pm_timer_base = pm_timer_base[0].start + + leaves = tree.get_leaves() + + # Never expose PCI config space ports to the user + leaves = list(filter(lambda p: p.start != 0xcf8, leaves)) + + # Drop everything above 0xd00 + leaves = list(filter(lambda p: p.start < 0xd00, leaves)) + + whitelist = [ + 0x40, # PIT + 0x60, # keyboard + 0x61, # HACK: NMI status/control + 0x64, # I8042 + 0x70, # RTC + 0x2f8, # serial + 0x3f8, # serial + ] + + pci_devices = ioports_search_pci_devices(tree) + + # Drop devices below 0xd00 as leaves already contains them. Access should + # not be permitted by default. + pci_devices = list(filter(lambda p: p.start >= 0xd00, pci_devices)) + for pci_device in pci_devices: + pci_device.permit = True + + for r in leaves: + typestr = r.typestr.lower() + if r.start in whitelist or \ + True in [vga in typestr for vga in ['vesa', 'vga']]: + r.permit = True + + leaves += pci_devices + leaves.sort(key=lambda r: r.start) + + return leaves, pm_timer_base + + +def parse_pcidevices(): + devices = [] + basedir = '/sys/bus/pci/devices' + list = input_listdir(basedir, ['*/config']) + for dir in list: + d = PCIDevice.parse_pcidevice_sysfsdir(basedir, dir) + if d is not None: + devices.append(d) + return devices + + +def parse_madt(): + f = input_open('/sys/firmware/acpi/tables/APIC', 'rb') + signature = f.read(4) + if signature != b'APIC': + raise RuntimeError('MADT: incorrect input file format %s' % signature) + (length,) = struct.unpack(' 0: + offset = 0 + (struct_type, struct_len) = struct.unpack(' 0: + offset = 0 + (struct_type, struct_len) = struct.unpack('= 8: + raise RuntimeError('Too many DMAR units. ' + 'Raise JAILHOUSE_MAX_IOMMU_UNITS.') + size = 0 + for r in dmar_regions: + if base == r.start: + size = r.size() + if size == 0: + raise RuntimeError('DMAR region size cannot be identified.\n' + 'Target Linux must run with Intel IOMMU ' + 'enabled.') + if size > 0x3000: + raise RuntimeError('Unexpectedly large DMAR region.') + units.append(IOMMUConfig({ + 'type': 'JAILHOUSE_IOMMU_INTEL', + 'base_addr': base, + 'mmio_size': size + })) + if flags & 1: + for d in pcidevices: + if d.iommu is None: + d.iommu = len(units) - 1 + offset += 16 - offset + while offset < struct_len: + (scope_type, scope_len, id, bus, dev, fn) =\ + parse_dmar_devscope(f) + # PCI Endpoint Device + if scope_type == 1: + assert not (flags & 1) + for d in pcidevices: + if d.bus == bus and d.dev == dev and d.fn == fn: + d.iommu = len(units) - 1 + break + # PCI Sub-hierarchy + elif scope_type == 2: + assert not (flags & 1) + for d in pcidevices: + if d.bus == bus and d.dev == dev and d.fn == fn: + d.iommu = len(units) - 1 + (secondbus, subordinate) = \ + PCIPCIBridge.get_2nd_busses(d) + for d2 in pcidevices: + if ( + d2.bus >= secondbus and + d2.bus <= subordinate + ): + d2.iommu = len(units) - 1 + break + # IOAPIC + elif scope_type == 3: + ioapic = next(chip for chip in ioapics if chip.id == id) + bdf = (bus << 8) | (dev << 3) | fn + for chip in ioapics: + if chip.bdf == bdf: + raise RuntimeError('IOAPICs with identical BDF') + ioapic.bdf = bdf + ioapic.iommu = len(units) - 1 + offset += scope_len + + # Reserved Memory Region Reporting Structure + if struct_type == 1: + f.seek(8 - offset, os.SEEK_CUR) + offset += 8 - offset + (base, limit) = struct.unpack('> 8) & 0xff, (bdf >> 3) & 0x1f, bdf & 0x7 + return '%02x:%02x.%x' % (bus, dev, fun) + + f = input_open('/sys/firmware/acpi/tables/IVRS', 'rb') + signature = f.read(4) + if signature != b'IVRS': + raise RuntimeError('IVRS: incorrect input file format %s' % signature) + + (length, revision) = struct.unpack(' 2: + raise RuntimeError('IVRS: unsupported Revision %02x' % revision) + + f.seek(48, os.SEEK_SET) + length -= 48 + + units = [] + regions = [] + # BDF of devices that are permitted outside IOMMU: root complex + iommu_skiplist = set([0x0]) + ivhd_blocks = 0 + while length > 0: + (block_type, block_length) = struct.unpack(' 1: + raise RuntimeError('Jailhouse doesn\'t support more than one ' + 'AMD IOMMU per PCI function.') + # IVHD block + ivhd_fields = struct.unpack(' 8: + raise RuntimeError('Too many IOMMU units. ' + 'Raise JAILHOUSE_MAX_IOMMU_UNITS.') + + msi_cap_ofs = None + + for i, d in enumerate(pcidevices): + if d.bdf() == iommu_bdf: + # Extract MSI capability offset + for c in d.caps: + if c.id == PCI_CAP_ID.MSI: + msi_cap_ofs = c.start + # We must not map IOMMU to the cells + del pcidevices[i] + + if msi_cap_ofs is None: + raise RuntimeError('AMD IOMMU lacks MSI support, and ' + 'Jailhouse doesn\'t support MSI-X yet.') + + if (iommu_feat & (0xF << 13)) and (iommu_feat & (0x3F << 17)): + # Performance Counters are supported, allocate 512K + mmio_size = 524288 + else: + # Allocate 16K + mmio_size = 16384 + + units.append(IOMMUConfig({ + 'type': 'JAILHOUSE_IOMMU_AMD', + 'base_addr': base_addr, + 'mmio_size': mmio_size, + 'amd_bdf': iommu_bdf, + 'amd_base_cap': base_cap_ofs, + 'amd_msi_cap': msi_cap_ofs, + # IVHD block type 0x11 has exact EFR copy but type 0x10 may + # overwrite what hardware reports. Set reserved bit 0 in that + # case to indicate that the value is in use. + 'amd_features': (iommu_feat | 0x1) if block_type == 0x10 else 0 + })) + + bdf_start_range = None + while block_length > 0: + (entry_type, device_id) = struct.unpack('= bdf_start_range and d.bdf() <= device_id: + d.iommu = len(units) - 1 + bdf_start_range = None + elif entry_type == 0x42: + # Alias select + (device_id_b,) = struct.unpack('= 0x40: + f.seek(4, os.SEEK_CUR) + block_length -= 4 + + elif type in [0x20, 0x21, 0x22]: + # IVMD block + ivmd_fields = struct.unpack('>= 32 + n += 1 + else: + mask = ~(int(end, 16) - int(start, 16)) + else: + mask = 0 + self.mask.append(mask & 0xffffffff) + f.close() + + +class PCICapability: + def __init__(self, id, extended, start, len, flags, content, msix_address): + self.id = id + self.extended = extended + self.start = start + self.len = len + self.flags = flags + self.content = content + self.msix_address = msix_address + self.comments = [] + + def __eq__(self, other): + return self.id == other.id and self.start == other.start and \ + self.len == other.len and self.flags == other.flags + + def gen_id_str(self): + return str(self.id) + \ + (' | JAILHOUSE_PCI_EXT_CAP' if self.extended else '') + + RD = '0' + RW = 'JAILHOUSE_PCICAPS_WRITE' + + JAILHOUSE_PCI_EXT_CAP = 0x8000 + + @staticmethod + def parse_pcicaps(dir): + caps = [] + has_extended_caps = False + f = input_open(os.path.join(dir, 'config'), 'rb') + f.seek(0x06) + (status,) = struct.unpack('= 2: # v2 capability + len = 60 + # access side effects still need to be analyzed + flags = PCICapability.RD + has_extended_caps = True + elif id == PCI_CAP_ID.MSIX: + # access will be moderated by hypervisor + len = 12 + (table,) = struct.unpack('> 4 + # access side effects still need to be analyzed + flags = PCICapability.RD + + if id == PCI_EXT_CAP_ID.VNDR: + (vsec_len,) = struct.unpack('> 20) + elif id == PCI_EXT_CAP_ID.ACS: + len = 8 + + (acs_cap, acs_ctrl) = struct.unpack('> 8 + if vector_bits == 0: + vector_bits = 256 + + vector_bytes = int((vector_bits + 31) / (8 * 4)) + len += vector_bytes + elif id in [PCI_EXT_CAP_ID.VC, PCI_EXT_CAP_ID.VC9]: + # parsing is too complex, but we have at least 4 DWORDS + len = 4 * 4 + elif id == PCI_EXT_CAP_ID.MFVC: + len = 4 + elif id in [PCI_EXT_CAP_ID.LTR, PCI_EXT_CAP_ID.ARI, + PCI_EXT_CAP_ID.PASID]: + len = 8 + elif id in [PCI_EXT_CAP_ID.DSN, PCI_EXT_CAP_ID.PTM]: + len = 12 + elif id in [PCI_EXT_CAP_ID.PWR, PCI_EXT_CAP_ID.SECPCI]: + len = 16 + elif id == PCI_EXT_CAP_ID.MCAST: + len = 48 + elif id in [PCI_EXT_CAP_ID.SRIOV, PCI_EXT_CAP_ID.ERR]: + len = 64 + else: + # unknown/unhandled cap, mark its existence + len = 4 + f.seek(cap + 4) + content = f.read(len - 4) + caps.append(PCICapability(id, True, cap, len, flags, content, + 0)) + + f.close() + return caps + + +class PCIDevice: + def __init__(self, type, domain, bus, dev, fn, bars, caps, path): + self.type = type + self.iommu = None + self.domain = domain + self.bus = bus + self.dev = dev + self.fn = fn + self.bars = bars + self.caps = caps + self.path = path + self.caps_start = 0 + self.num_caps = len(caps) + self.num_msi_vectors = 0 + self.msi_64bits = 0 + self.msi_maskable = 0 + self.num_msix_vectors = 0 + self.msix_region_size = 0 + self.msix_address = 0 + for c in caps: + if c.id in (PCI_CAP_ID.MSI, PCI_CAP_ID.MSIX): + msg_ctrl = struct.unpack('> 1) & 0x7) + self.msi_64bits = (msg_ctrl >> 7) & 1 + self.msi_maskable = (msg_ctrl >> 8) & 1 + else: # MSI-X + if c.msix_address != 0: + vectors = (msg_ctrl & 0x7ff) + 1 + self.num_msix_vectors = vectors + self.msix_region_size = (vectors * 16 + 0xfff) & 0xf000 + self.msix_address = c.msix_address + else: + print('WARNING: Ignoring invalid MSI-X configuration' + ' of device %02x:%02x.%x' % (bus, dev, fn)) + + def __str__(self): + return 'PCIDevice: %02x:%02x.%x' % (self.bus, self.dev, self.fn) + + def bdf(self): + return self.bus << 8 | self.dev << 3 | self.fn + + @staticmethod + def parse_pcidevice_sysfsdir(basedir, dir): + dpath = os.path.join(basedir, dir) + f = input_open(os.path.join(dpath, 'config'), 'rb') + (vendor_device,) = struct.unpack('= 0: + regions.append(r) + + # if the tree continues recurse further down ... + if tree.children: + regions.extend(tree.find_regions_by_name(name)) + + return regions + + @staticmethod + def parse_io_line(line, TargetClass): + (region, type) = line.split(' : ', 1) + level = int(region.count(' ') / 2) + 1 + type = type.strip() + region = [r.strip() for r in region.split('-', 1)] + + return level, TargetClass(int(region[0], 16), int(region[1], 16), type) + + @staticmethod + def parse_io_file(filename, TargetClass): + root = IORegionTree(None, 0) + f = input_open(filename) + lastlevel = 0 + lastnode = root + for line in f: + (level, r) = IORegionTree.parse_io_line(line, TargetClass) + t = IORegionTree(r, level) + if t.level > lastlevel: + t.parent = lastnode + if t.level == lastlevel: + t.parent = lastnode.parent + if t.level < lastlevel: + p = lastnode.parent + while t.level < p.level: + p = p.parent + t.parent = p.parent + + t.parent.children.append(t) + lastnode = t + lastlevel = t.level + f.close() + + return root + + +class IOMMUConfig: + def __init__(self, props): + self.type = props['type'] + self.base_addr = props['base_addr'] + self.mmio_size = props['mmio_size'] + if 'amd_bdf' in props: + self.amd_bdf = props['amd_bdf'] + self.amd_base_cap = props['amd_base_cap'] + self.amd_msi_cap = props['amd_msi_cap'] + self.amd_features = props['amd_features'] + + @property + def is_amd_iommu(self): + return hasattr(self, 'amd_bdf') diff --git a/scripts/always-compat.mk b/scripts/always-compat.mk new file mode 100644 index 0000000000000000000000000000000000000000..a74f4df4765a5da6430e01e34530149b7f0ccf9e --- /dev/null +++ b/scripts/always-compat.mk @@ -0,0 +1,16 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2020 +# +# Authors: +# Jan Kiszka +# Benjamin Block +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +ifeq ($(shell expr \( $(VERSION) \* $$((0x100)) \+ $(PATCHLEVEL) \) \< $$((0x509))),1) +always = $(always-y) +endif diff --git a/scripts/arm64-parsedump.py b/scripts/arm64-parsedump.py new file mode 100755 index 0000000000000000000000000000000000000000..54f4fd6679bd1012181e7d0abdb3584a2d169031 --- /dev/null +++ b/scripts/arm64-parsedump.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (C) 2015-2016 Huawei Technologies Duesseldorf GmbH +# +# Authors: +# Dmitry Voytik +# +# ARM64 dump parser. +# Usage ./scripts/arm64-parsedump.py [dump.txt] +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + + +import subprocess +import sys +import fileinput +import os +import argparse + +split1 = "Cell's stack before exception " +split2 = "Hypervisor stack before exception " + + +# yep, this is most important feature +class Col: + ENDC = '\033[0m' + BOLD = '\033[1m' + FAIL = '\033[91m' + + @staticmethod + def init(): + t = os.environ['TERM'] + if t == '' or t == 'dumb' or t == 'vt220' or t == 'vt100': + # The terminal doesn't support colors + Col.ENDC = '' + Col.BOLD = '' + Col.FAIL = '' + + @staticmethod + def bold(string): + return Col.BOLD + str(string) + Col.ENDC + + @staticmethod + def pr_err(string): + print(Col.FAIL + "ERROR: " + Col.ENDC + str(string)) + + @staticmethod + def pr_note(string): + print(Col.BOLD + "NOTE: " + Col.ENDC + str(string)) + + +def addr2line(addr): + return subprocess.check_output(["addr2line", "-a", "-f", "-p", "-e", + objpath, hex(addr)]) + + +def print_faddr(addr): + s = str(addr2line(addr)) + if s.find("?") != -1: + print("[{:#016x}] {}".format(addr, Col.bold("uknown"))) + return + s = s.strip().split(" ") + print("[{}] {} {}".format(s[0][:-1], Col.bold(s[1]), + s[3].split('/')[-1])) + + +class Dump: + def __init__(self, dump_str): + if len(dump_str) < 50: + raise ValueError('Dump is too small') + # parse CPU state + pc_i = dump_str.find("pc:") + 4 + self.pc = int(dump_str[pc_i: pc_i+16], 16) + pc_i = dump_str.find("sp:") + 4 + self.sp = int(dump_str[pc_i: pc_i+16], 16) + el_i = dump_str.rfind("EL") + 2 + self.el = int(dump_str[el_i:el_i+1]) + if (self.el != 2): + Col.pr_err("This version supports only EL2 exception dump") + + # TODO: parse other registers: ESR, etc + + # parse stack dump + stack_start = str.rfind(dump_str, split1) + if (stack_start == -1): + stack_start = str.rfind(dump_str, split2) + if (stack_start == -1): + raise ValueError('Dump is damaged') + + stack_str = dump_str[stack_start:].strip().split('\n') + stack_addr_start = int(stack_str[0][35:53], 16) + stack_addr_end = int(stack_str[0][56:74], 16) + + # parse stack memory dump + stack = [] + for line in stack_str[1:]: + if (len(line) < 5): + continue + if (line[4] != ':'): + continue + line = line[5:].strip().split(" ") + for value in line: + stack.append(int(value, 16)) + + self.stack_mem = stack + self.stack_start = stack_addr_start + self.stack_end = stack_addr_end + + def stack_get64(self, addr): + assert addr >= self.sp + i = int((addr - self.sp) / 4) + hi32 = self.stack_mem[i] + lo32 = self.stack_mem[i + 1] + return lo32 + (hi32 << 32) + + def print_unwinded_stack(self): + print_faddr(self.pc) + addr = self.sp + while True: + prev_sp = self.stack_get64(addr) + print_faddr(self.stack_get64(addr+4)) + addr = prev_sp + if (addr > self.stack_end - 256): + break + + +def main(): + Col.init() + + parser = argparse.ArgumentParser(description='ARM64 exception dump parser') + parser.add_argument('--objpath', '-o', default="./hypervisor/hypervisor.o", + type=str, help="Path to hypervisor.o file") + parser.add_argument('-f', '--filedump', default="", type=str, + help="Exception dump text file") + args = parser.parse_args() + + global objpath + objpath = args.objpath + + stdin_used = False + infile = [args.filedump] + if args.filedump == "": + infile = [] + Col.pr_note("Input dumped text then press Enter, Control+D, Control+D") + stdin_used = True + + ilines = [] + for line in fileinput.input(infile): + ilines.append(line) + dump_str = "".join(ilines) + if (not stdin_used): + print(dump_str) + else: + print("\n") + try: + dump = Dump(dump_str) + except ValueError as err: + Col.pr_err(err) + return + dump.print_unwinded_stack() + +if __name__ == "__main__": + main() diff --git a/scripts/gen_pci_defs.sh b/scripts/gen_pci_defs.sh new file mode 100755 index 0000000000000000000000000000000000000000..480f7fbbfa102d006e3f0056aea5f5954adef29f --- /dev/null +++ b/scripts/gen_pci_defs.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) OTH Regensburg, 2019 +# +# Authors: +# Ralf Ramsauer +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +CELL_CONFIG_H=$1 + +function find_defines() { + header=$1 + prefix=$2 + search="#define\s\+${prefix}\(\S*\)\s\+\(\S*\).*" + replace=" '\1'\t: \2," + + grep $prefix $header | sed -e "s/$search/$replace/" +} + +PCI_CAP_IDS=$(find_defines $CELL_CONFIG_H PCI_CAP_ID_) +PCI_EXT_CAP_IDS=$(find_defines $CELL_CONFIG_H PCI_EXT_CAP_ID_) + +cat < +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +echo "/* Auto-generated - leave alone and don't commit! */" +echo "" + +cd "$1" > /dev/null + +if ! git rev-parse 2>/dev/null; then + version="`cat VERSION`" +else + describe="`git describe --long --dirty --match "v[0-9].[0-9]*"`" + version="`echo $describe | sed -e 's/\([^-]*\)-\(.*\)/\1 (\2)/'`" +fi + +cd - > /dev/null + +echo "#define JAILHOUSE_VERSION \"$version\"" diff --git a/scripts/header_check b/scripts/header_check new file mode 100755 index 0000000000000000000000000000000000000000..6487378b78fea42f51274acde1ee2d4dbaf94058 --- /dev/null +++ b/scripts/header_check @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +if [ "$ARCH" == "" ]; then + ARCH=x86 +fi + +INCLUDE_ARM_COMMON= +if [ "$ARCH" == "arm" ] || [ "$ARCH" == "arm64" ]; then + INCLUDE_ARM_COMMON=-Ihypervisor/arch/arm-common/include +fi + +CFLAGS="-fno-builtin-ffsl -Wall -Wstrict-prototypes -Wtype-limits \ + -Wmissing-declarations -Wmissing-prototypes \ + -Ihypervisor/arch/$ARCH/include -Ihypervisor/include \ + -Iinclude/arch/$ARCH -Iinclude \ + $INCLUDE_ARM_COMMON $EXTRA_CFLAGS" + +test_compile() +{ + header=`basename $2` + prepend= + case $header in + cell-config.h|console.h|header.h|hypercall.h) + prepend="#include " + ;; + jailhouse_hypercall.h) + # only included directly on arm64 + if [ "$ARCH" != "arm64" ]; then + return; + fi + prepend="#define __ASSEMBLY__ + #include " + ;; + bitops.h) + if [ "$1" == "asm" ]; then + # must be included by jailhouse/bitops.h only + return + fi + ;; + ivshmem.h) + if [ "$1" == "asm" ]; then + # must be included by jailhouse/ivshmem.h only + return + fi + ;; + traps.h) + if [ "$2" == "hypervisor/arch/arm-common/include/asm/traps.h" ]; then + # must be included by arm{,64}/include/asm/traps.h only + return + fi + ;; + esac + + echo "$prepend" > .header_check.tmp.c + echo "#include <$1/$header>" >> .header_check.tmp.c + + if ! ${CROSS_COMPILE}gcc -c -o .header_check.tmp.o .header_check.tmp.c $CFLAGS; then + exit 1; + fi + echo $1/$header - OK +} + +for header in hypervisor/include/jailhouse/*.h; do + test_compile jailhouse $header +done + +for header in hypervisor/arch/$ARCH/include/asm/*.h; do + test_compile asm $header +done + +if [ "$ARCH" == "arm" -o "$ARCH" == "arm64" ]; then + for header in hypervisor/arch/arm-common/include/asm/*.h; do + test_compile asm $header + done +fi + +for header in include/jailhouse/*.h; do + test_compile jailhouse $header +done + +for header in include/arch/$ARCH/asm/*.h; do + test_compile asm $header +done + +rm -f .header_check.tmp.[oc] diff --git a/scripts/include.mk b/scripts/include.mk new file mode 100644 index 0000000000000000000000000000000000000000..d0139d8eb08a6328a179fa210c0dba1a23421328 --- /dev/null +++ b/scripts/include.mk @@ -0,0 +1,69 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jan Kiszka +# Benjamin Block +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +ifeq ($(V),1) + Q = +else + Q = @ +endif + +MAKEFLAGS += --no-print-directory + +prefix ?= /usr/local +exec_prefix ?= $(prefix) +sbindir ?= $(exec_prefix)/sbin +libexecdir ?= $(exec_prefix)/libexec +datarootdir ?= $(prefix)/share +datadir ?= $(datarootdir) +man8dir ?= $(datarootdir)/man/man8 +completionsdir ?= /usr/share/bash-completion/completions +firmwaredir ?= /lib/firmware + +# all directories listed here will be created using a generic rule below +INSTALL_DIRECTORIES := $(sbindir) \ + $(libexecdir) \ + $(datadir) \ + $(man8dir) \ + $(completionsdir) \ + $(firmwaredir) + +INSTALL ?= install +INSTALL_PROGRAM ?= $(INSTALL) +INSTALL_DATA ?= $(INSTALL) -m 644 +INSTALL_DIR ?= $(INSTALL) -d -m 755 + +PYTHON3 ?= python3 +PIP := $(PYTHON3) -m pip + +ifeq ($(strip $(shell $(PIP) > /dev/null 2> /dev/null && echo "y")), y) +PYTHON_PIP_USABLE := yes +endif + +# creates a rule for each dir in $(INSTALL_DIRECTORIES) under the current +# $(DESTDIR) and additionally to that for each of these dirs a subdir named +# `jailhouse`. These can be used as prerequirement for install-rules and will +# thus be created on demand (or not at all if not used in that way). +$(sort $(INSTALL_DIRECTORIES:%=$(DESTDIR)%) \ + $(INSTALL_DIRECTORIES:%=$(DESTDIR)%/jailhouse)): + $(INSTALL_DIR) $@ + +ARCH ?= $(shell uname -m) +ifeq ($(ARCH),x86_64) +override ARCH = x86 +endif +ifeq ($(ARCH),armv7l) +override ARCH = arm +endif +ifeq ($(ARCH),aarch64) +override ARCH = arm64 +endif diff --git a/scripts/make_release b/scripts/make_release new file mode 100755 index 0000000000000000000000000000000000000000..86c9642d00b199ee158087e2537b964ca3918570 --- /dev/null +++ b/scripts/make_release @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +usage() { + echo "usage: $0 name" + exit 1 +} + +name=$1 + +if [ -z "$name" ]; then + usage +fi + +if [ ! -f VERSION ] || [ ! -d .git ]; then + echo "Must be run from top-level directory" + exit 1 +fi + +if [ -n "`git status -s -uno`" ]; then + echo "Working directory is dirty!" + exit 1 +fi + +echo -e "Tag commit\n\n `git log -1 --oneline`" +echo -e "\nof branch\n\n `git branch | sed -n 's/^\* //p'`" +echo -ne "\nas $name? (y/N) " +read answer +if [ "$answer" != "y" ]; then + exit 1 +fi + +echo $name > VERSION +git commit -sv VERSION -m "Bump version number" +git tag -as $name -m "Release $name" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..790f71f72b8ab5e76fc63f9becf5d1218cbb87be --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +# +# pyjailhouse, a python interface for the Jailhouse hypervisor +# +# Copyright (c) Christopher Goldsworthy, 2018 +# +# This script is used to create project metadata when installing pyjailhouse +# using pip. +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +from setuptools import setup, find_packages + +with open("VERSION") as version_file: + version = version_file.read().lstrip("v") + +setup(name="pyjailhouse", version=version, + description="A Python interface for the Jailhouse Hypervisor", + license="GPLv2", url="https://github.com/siemens/jailhouse", + author_email="jailhouse-dev@googlegroups.com", + packages=find_packages()) diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1108433a83dcbd7904c1d7722435502ff31e81c0 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,146 @@ +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2013-2017 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +include $(ALWAYS_COMPAT_MK) + +-include $(GEN_CONFIG_MK) + +# includes installation-related variables and definitions +include $(src)/../scripts/include.mk + +LD = $(CC) $(KBUILD_CFLAGS) +NOSTDINC_FLAGS := +LINUXINCLUDE := -I$(src)/../driver +KBUILD_CFLAGS := -g -O3 -DLIBEXECDIR=\"$(libexecdir)\" \ + -Wall -Wextra -Wmissing-declarations -Wmissing-prototypes -Werror \ + -D__LINUX_COMPILER_TYPES_H \ + -DJAILHOUSE_VERSION=\"$(shell cat $(src)/../VERSION)\" $(EXTRA_CFLAGS) +KBUILD_CPPFLAGS := +# prior to 4.19 +LDFLAGS := +# since 4.19 +KBUILD_LDFLAGS := + +# force no-pie for distro compilers that enable pie by default +KBUILD_CFLAGS += $(call cc-option, -fno-pie) +KBUILD_CFLAGS += $(call cc-option, -no-pie) + +BINARIES := jailhouse demos/ivshmem-demo +targets += jailhouse.o demos/ivshmem-demo.o + +ifeq ($(ARCH),x86) +BINARIES += demos/cache-timings +targets += demos/cache-timings.o +endif # $(ARCH),x86 + +always-y := $(BINARIES) + +HAS_PYTHON_MAKO := \ + $(shell $(PYTHON3) -c "from mako.template import Template" 2>/dev/null \ + && echo yes) + +ifeq ($(strip $(HAS_PYTHON_MAKO)), yes) +always-y += jailhouse-config-collect +HELPERS := jailhouse-config-collect + +else # !HAS_PYTHON_MAKO + +HELPERS := +$(info WARNING: Could not create the helper script to generate \ + configurations on remote machines \ + ("jailhouse-config-collect"). You need Python and the \ + Mako library for it.) +endif # !HAS_PYTHON_MAKO + +ifeq ($(strip $(PYTHON_PIP_USABLE)), yes) +HELPERS += \ + jailhouse-cell-linux \ + jailhouse-cell-stats \ + jailhouse-config-create \ + jailhouse-config-check \ + jailhouse-hardware-check +TEMPLATES := jailhouse-config-collect.tmpl root-cell-config.c.tmpl + +install-libexec: $(HELPERS) $(DESTDIR)$(libexecdir)/jailhouse + $(INSTALL_PROGRAM) $^ + $(Q)$(call patch_dirvar,libexecdir,$(lastword $^)/jailhouse-cell-linux) + $(Q)$(call patch_dirvar,datadir,$(lastword $^)/jailhouse-config-create) + $(Q)$(call patch_pyjh_import,$(lastword $^)/jailhouse-cell-linux) + $(Q)$(call patch_pyjh_import,$(lastword $^)/jailhouse-config-check) + +install-data: $(TEMPLATES) $(DESTDIR)$(datadir)/jailhouse + $(INSTALL_DATA) $^ + +else # !PYTHON_PIP_USABLE + +install-libexec install-data: + @ + +install:: + $(info WARNING: Could not install Python-based helpers. You need \ + Python and pip in order to install them.) +endif # !PYTHON_PIP_USABLE + +MAN8_PAGES := jailhouse.8 jailhouse-cell.8 jailhouse-enable.8 + +define patch_dirvar + sed -i 's|^$1 = None|$1 = "$($1)"|' $2 +endef + +define patch_pyjh_import + sed -i '/^sys.path\[0\] = .*/d' $1 +endef + +quiet_cmd_gen_collect = GEN $@ +define cmd_gen_collect + $< -g $@; \ + chmod +x $@ +endef + +quiet_cmd_gen_man = GEN $@ +define cmd_gen_man + sed 's/$${VERSION}/$(shell cat $(src)/../VERSION)/g' $< > $@ +endef + +$(obj)/%: $(obj)/%.o FORCE + $(call if_changed,ld) + +CFLAGS_jailhouse-gcov-extract.o := -I$(src)/../hypervisor/include \ + -I$(src)/../hypervisor/arch/$(SRCARCH)/include +# just change ldflags not cflags, we are not profiling the tool +LDFLAGS_jailhouse-gcov-extract := -lgcov -fprofile-arcs + +targets += jailhouse-gcov-extract.o +always-y += jailhouse-gcov-extract + +$(obj)/jailhouse-config-collect: $(src)/jailhouse-config-create $(src)/jailhouse-config-collect.tmpl FORCE + $(call if_changed,gen_collect) + +targets += $(MAN8_PAGES) +always-y += $(MAN8_PAGES) + +$(obj)/%.8: $(src)/%.8.in FORCE + $(call if_changed,gen_man) + +install-bin: $(BINARIES) $(DESTDIR)$(sbindir) + $(INSTALL_PROGRAM) $^ + +install-completion: jailhouse-completion.bash $(DESTDIR)$(completionsdir) + $(INSTALL_DATA) $< $(DESTDIR)$(completionsdir)/jailhouse + +install-man8: $(MAN8_PAGES) $(DESTDIR)$(man8dir) + $(INSTALL_DATA) $^ + +install:: install-bin install-libexec install-data install-completion \ + install-man8 + +.PHONY: install install-bin install-libexec install-data install-completion diff --git a/tools/demos/cache-timings.c b/tools/demos/cache-timings.c new file mode 100644 index 0000000000000000000000000000000000000000..2c591dab38d364ec40be6923adb0b16b581560e5 --- /dev/null +++ b/tools/demos/cache-timings.c @@ -0,0 +1,29 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) OTH Regensburg, 2020 + * + * Authors: + * Ralf Ramsauer + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#define printk printf + +typedef unsigned int u32; +typedef unsigned long long u64; + +void inmate_main(void); + +#include "../inmates/demos/x86/cache-timings-common.c" + +int main(void) +{ + inmate_main(); + return 0; +} diff --git a/tools/demos/ivshmem-demo.c b/tools/demos/ivshmem-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..f9ef438e5c88cca65aa3a6f53e3b09d5c5263052 --- /dev/null +++ b/tools/demos/ivshmem-demo.c @@ -0,0 +1,215 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2019-2020 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ivshm_regs { + uint32_t id; + uint32_t max_peers; + uint32_t int_control; + uint32_t doorbell; + uint32_t state; +}; + +static volatile uint32_t *state, *rw, *in, *out; + +static inline uint32_t mmio_read32(void *address) +{ + return *(volatile uint32_t *)address; +} + +static inline void mmio_write32(void *address, uint32_t value) +{ + *(volatile uint32_t *)address = value; +} + +static size_t uio_read_mem_size(char *uio_devname, int idx) +{ + char sysfs_path[64]; + char output[20] = ""; + size_t size; + int fd, ret; + + snprintf(sysfs_path, sizeof(sysfs_path), + "/sys/class/uio/%s/maps/map%d/size", + uio_devname, idx); + fd = open(sysfs_path, O_RDONLY); + if (fd < 0) + error(1, errno, "open(sysfs)"); + ret = read(fd, output, sizeof(output)); + if (ret < 0) + error(1, errno, "read(sysfs)"); + close(fd); + if (sscanf(output, "0x%zx", &size) != 1) + error(1, EINVAL, "sscanf(sysfs)"); + return size; +} + +static void print_shmem(void) +{ + printf("state[0] = %d\n", state[0]); + printf("state[1] = %d\n", state[1]); + printf("state[2] = %d\n", state[2]); + printf("rw[0] = %d\n", rw[0]); + printf("rw[1] = %d\n", rw[1]); + printf("rw[2] = %d\n", rw[2]); + printf("in@0x0000 = %d\n", in[0/4]); + printf("in@0x2000 = %d\n", in[0x2000/4]); + printf("in@0x4000 = %d\n", in[0x4000/4]); +} + +int main(int argc, char *argv[]) +{ + char sysfs_path[64]; + struct ivshm_regs *regs; + uint32_t int_no, target = INT_MAX; + struct signalfd_siginfo siginfo; + struct pollfd fds[2]; + sigset_t sigset; + char *path = strdup("/dev/uio0"); + char *uio_devname; + int has_msix, i; + int ret, size, offset, pgsize; + uint32_t id, max_peers, int_count; + + pgsize = getpagesize(); + + for (i = 1; i < argc; i++) { + if (!strcmp("-t", argv[i]) || !strcmp("--target", argv[i])) { + i++; + target = atoi(argv[i]); + continue; + } else if (!strcmp("-d", argv[i]) || !strcmp("--device", argv[i])) { + i++; + path = argv[i]; + continue; + } else { + printf("Invalid argument '%s'\n", argv[i]); + error(1, EINVAL, "Usage: ivshmem-demo [-d DEV] [-t TARGET]"); + } + } + + fds[0].fd = open(path, O_RDWR); + if (fds[0].fd < 0) + error(1, errno, "open(%s)", path); + fds[0].events = POLLIN; + + uio_devname = basename(path); + snprintf(sysfs_path, sizeof(sysfs_path), + "/sys/class/uio/%s/device/msi_irqs", uio_devname); + has_msix = access(sysfs_path, R_OK) == 0; + + offset = 0; + size = uio_read_mem_size(uio_devname, 0); + regs = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + fds[0].fd, offset); + if (regs == MAP_FAILED) + error(1, errno, "mmap(regs)"); + + id = mmio_read32(®s->id); + printf("ID = %d\n", id); + + max_peers = mmio_read32(®s->max_peers); + printf("Maximum peers = %d\n", max_peers); + + if (target == INT_MAX) + target = (id + 1) % max_peers; + if (target >= max_peers || target == id) + error(1, EINVAL, "invalid peer number"); + + offset += pgsize; + size = uio_read_mem_size(uio_devname, 1); + state = mmap(NULL, size, PROT_READ, MAP_SHARED, fds[0].fd, offset); + if (state == MAP_FAILED) + error(1, errno, "mmap(state)"); + + offset += pgsize; + size = uio_read_mem_size(uio_devname, 2); + rw = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + fds[0].fd, offset); + if (rw == MAP_FAILED) + error(1, errno, "mmap(rw)"); + + offset += pgsize; + size = uio_read_mem_size(uio_devname, 3); + in = mmap(NULL, size, PROT_READ, MAP_SHARED, fds[0].fd, offset); + if (in == MAP_FAILED) + error(1, errno, "mmap(in)"); + + offset += pgsize; + size = uio_read_mem_size(uio_devname, 4); + out = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + fds[0].fd, offset); + if (out == MAP_FAILED) + error(1, errno, "mmap(out)"); + + mmio_write32(®s->state, id + 1); + rw[id] = 0; + out[0] = 0; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + sigprocmask(SIG_BLOCK, &sigset, NULL); + fds[1].fd = signalfd(-1, &sigset, 0); + if (fds[1].fd < 0) + error(1, errno, "signalfd"); + fds[1].events = POLLIN; + + mmio_write32(®s->int_control, 1); + alarm(1); + + print_shmem(); + + while (1) { + ret = poll(fds, 2, -1); + if (ret < 0) + error(1, errno, "poll"); + + if (fds[0].revents & POLLIN) { + ret = read(fds[0].fd, &int_count, sizeof(int_count)); + if (ret != sizeof(int_count)) + error(1, errno, "read(uio)"); + + rw[id] = int_count; + out[0] = int_count * 10; + printf("\nInterrupt #%d\n", int_count); + print_shmem(); + + mmio_write32(®s->int_control, 1); + } + if (fds[1].revents & POLLIN) { + ret = read(fds[1].fd, &siginfo, sizeof(siginfo)); + if (ret != sizeof(siginfo)) + error(1, errno, "read(sigfd)"); + + int_no = has_msix ? (id + 1) : 0; + printf("\nSending interrupt %d to peer %d\n", + int_no, target); + mmio_write32(®s->doorbell, int_no | (target << 16)); + + alarm(1); + } + } +} diff --git a/tools/jailhouse-cell-linux b/tools/jailhouse-cell-linux new file mode 100755 index 0000000000000000000000000000000000000000..a1650912c012c65dc32f3ea1d71dca5cdf4f8b99 --- /dev/null +++ b/tools/jailhouse-cell-linux @@ -0,0 +1,746 @@ +#!/usr/bin/env python3 + +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2015-2016 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +import argparse +import gzip +import os +import struct +import sys + +# Imports from directory containing this must be done before the following +sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.." +from pyjailhouse.cell import JailhouseCell +import pyjailhouse.config_parser as config_parser + +libexecdir = None + + +def page_align(value, page_size=0x1000): + return (value + page_size - 1) & ~(page_size - 1) + + +def unpack_cstring(blob): + string = '' + pos = 0 + (byte,) = struct.unpack_from('B', blob[pos:pos+1]) + while byte != 0: + string += chr(byte) + pos += 1 + (byte,) = struct.unpack_from('B', blob[pos:pos+1]) + return string + + +class DTBHeader: + def __init__(self, blob): + (self.total_size, self.off_dt_struct, self.off_dt_strings, + self.off_mem_rsvmap, self.version, self.last_comp_version, + self.boot_cpuid_phys, self.size_dt_strings, self.size_dt_struct) = \ + struct.unpack_from('>4x9I', blob) + if self.version < 17 or self.last_comp_version > 17: + print('Unsupported DTB version %d' % self.version) + exit(1) + self.header_blob = blob + + def get(self): + return struct.pack('>10I', 0xd00dfeed, self.total_size, + self.off_dt_struct, self.off_dt_strings, + self.off_mem_rsvmap, self.version, + self.last_comp_version, self.boot_cpuid_phys, + self.size_dt_strings, self.size_dt_struct) + + +class DTBReserveMap: + def __init__(self, blob): + self.blob = blob[0:16] + pos = 0 + while struct.unpack_from('>8xQ', self.blob[pos:pos+16]) != (0,): + self.blob += blob[pos+16:pos+32] + pos += 16 + + +class DTBStrings: + def __init__(self, blob): + self.blob = blob + + def add(self, string): + offset = len(self.blob) + self.blob += string.encode() + b'\0' + return offset + + def get(self, off): + strings = str(self.blob.decode()) + return strings[off:].split('\0', 1)[0] + + +OF_DT_BEGIN_NODE = 0x00000001 +OF_DT_END_NODE = 0x00000002 +OF_DT_PROP = 0x00000003 +OF_DT_END = 0x00000009 + + +class DTBProperty: + def __init__(self, name_off, value, strings): + self.name_off = name_off + self.name = strings.get(self.name_off) + self.data = value + + @staticmethod + def parse(blob, strings): + (datasize, name_off) = struct.unpack_from('>II', blob) + data = blob[8:8+datasize] + prop = DTBProperty(name_off, data, strings) + length = 8 + (datasize + 3) & ~3 + return (prop, length) + + @staticmethod + def create(name, value, strings): + return DTBProperty(strings.add(name), value, strings) + + def set_value(self, value): + self.data = value + + def get(self): + datasize = len(self.data) + blob = struct.pack('>III', OF_DT_PROP, datasize, self.name_off) + blob += self.data + if datasize & 3 != 0: + blob += bytearray(4 - datasize & 3) + return blob + + +class DTBNode: + def __init__(self, name, children, properties, strings): + self.name = name + self.children = children + self.properties = properties + self.strings = strings + + @staticmethod + def parse(blob, strings): + name = unpack_cstring(blob) + # next field is word-aligned + length = ((len(name) + 1) + 3) & ~3 + + children = [] + properties = [] + + while True: + (token,) = struct.unpack_from('>I', blob[length:]) + length += 4 + if token == OF_DT_BEGIN_NODE: + (child, child_length) = DTBNode.parse(blob[length:], strings) + length += child_length + children.append(child) + elif token == OF_DT_PROP: + (prop, prop_length) = DTBProperty.parse(blob[length:], strings) + length += prop_length + properties.append(prop) + elif token == OF_DT_END_NODE: + break + else: + raise RuntimeError('Invalid DTB') + + return (DTBNode(name, children, properties, strings), length) + + def find(self, path): + if path == '': + return self + if path.find('/') >= 0: + (childname, subpath) = path.split('/', 1) + else: + childname = path + subpath = '' + matches = [c for c in self.children if c.name == childname] + if len(matches) > 1: + raise RuntimeError('Invalid DTB') + if not matches: + return None + else: + return matches[0].find(subpath) + + def add_node(self, name): + child = DTBNode(name, [], [], self.strings) + self.children.append(child) + return child + + def get_prop(self, name): + matches = [p for p in self.properties if p.name == name] + if len(matches) > 1: + raise RuntimeError('Invalid DTB') + return matches[0] if matches else None + + def add_prop(self, name, value): + prop = DTBProperty.create(name, value, self.strings) + self.properties.append(prop) + + def get(self): + namelen = ((len(self.name) + 1) + 3) & ~3 + blob = struct.pack('>I%ds' % namelen, OF_DT_BEGIN_NODE, + self.name.encode()) + for prop in self.properties: + blob += prop.get() + for child in self.children: + blob += child.get() + return blob + struct.pack('>I', OF_DT_END_NODE) + + +class DTB: + def __init__(self, blob): + self.header = DTBHeader(blob[0:40]) + + self.rsvmap = DTBReserveMap(blob[self.header.off_mem_rsvmap:]) + + end_idx = self.header.off_dt_strings + self.header.size_dt_strings + self.strings = DTBStrings(blob[self.header.off_dt_strings:end_idx]) + + start_idx = self.header.off_dt_struct + end_idx = start_idx + self.header.size_dt_struct + + (begin_token,) = struct.unpack_from('>I', blob[start_idx:end_idx]) + if begin_token != OF_DT_BEGIN_NODE: + raise RuntimeError('Invalid DTB') + (self.root_node, length) = DTBNode.parse(blob[start_idx+4:end_idx], + self.strings) + + def get_prop(self, path, name): + node = self.root_node.find(path[path.find('/')+1:]) + if not node: + raise RuntimeError('DTB is missing node %s' % path) + prop = node.get_prop(name) + return prop.data if prop else None + + def set_prop(self, path, name, value): + subpath = path[path.find('/')+1:] + node = self.root_node.find(subpath) + if not node: + (parent_path, new_node) = path.rsplit('/') + parent = self.root_node.find(parent_path) + node = parent.add_node(new_node) + prop = node.get_prop(name) + if prop: + prop.set_value(value) + else: + node.add_prop(name, value) + + def get(self): + nodes = self.root_node.get() + struct.pack('>I', OF_DT_END) + self.header.off_mem_rsvmap = 40 + self.header.off_dt_struct = 40 + len(self.rsvmap.blob) + self.header.size_dt_struct = len(nodes) + self.header.off_dt_strings = self.header.off_dt_struct + len(nodes) + self.header.size_dt_strings = len(self.strings.blob) + self.header.total_size = self.header.off_dt_strings + \ + len(self.strings.blob) + + return self.header.get() + self.rsvmap.blob + nodes + self.strings.blob + + +class X86: + name = 'x86' + + def setup(self, args, config): + if config.cpu_reset_address != 0: + raise RuntimeError('x86 requires cpu_reset_address=0') + + self.kernel_image = args.kernel.read() + + self._zero_page = X86ZeroPage(self.kernel_image, args.initrd, + args.kernel_decomp_factor, config) + + setup_data = x86_gen_setup_data(config) + + self._zero_page.setup_header.set_setup_data( + arch.params_address() + 0x1000) + self._zero_page.setup_header.set_cmd_line_ptr( + self._zero_page.setup_header.setup_data + len(setup_data)) + + self.params = self._zero_page.get_data() + setup_data + \ + (args.cmdline.encode() if args.cmdline else b'') + b'\0' + + def write_params(self, args, config): + args.write_params.write(arch.params) + args.write_params.close() + + print('\ +Boot parameters written. Start Linux with the following commands (adjusting \ +paths as needed):\n\ +\n\ +jailhouse cell create %s\n\ +jailhouse cell load %s linux-loader.bin -a 0x%x %s -a 0x%x ' % + (args.config.name, config.name, self.loader_address(), + args.kernel.name, self._zero_page.kernel_load_addr), + end='') + if args.initrd: + print('%s -a 0x%x ' % (args.initrd.name, + self._zero_page.setup_header.ramdisk_image), + end='') + print('%s -a 0x%x' % (args.write_params.name, arch.params_address())) + print('jailhouse cell start %s' % config.name) + + def loader_address(self): + return 0 + + def params_address(self): + return 0x1000 + + def kernel_address(self): + return self._zero_page.kernel_load_addr + + def dtb_address(self): + return None + + def dtb(self): + return None + + def ramdisk_address(self): + return self._zero_page.setup_header.ramdisk_image + + +class ARMCommon: + def setup(self, args, config): + self._cpu_reset_address = config.cpu_reset_address + + (self.kernel_image, + self._kernel_gz) = self.get_uncompressed_kernel(args.kernel) + kernel_size = page_align(len(self.kernel_image)) + kernel_load_offset = self.get_kernel_offset(self.kernel_image) + image_size = kernel_load_offset + kernel_size + self.kernel_alignment() + + ramdisk_size = 0 + if args.initrd: + ramdisk_size = os.fstat(args.initrd.fileno()).st_size + # leave sufficient space between the kernel and the initrd + decompression_factor = self.default_decompression_factor() + if args.kernel_decomp_factor: + decompression_factor = args.kernel_decomp_factor + decompression_space = decompression_factor * kernel_size + kernel_size += decompression_space + image_size += decompression_space + + if not args.dtb: + print('No device tree specified', file=sys.stderr) + exit(1) + # add one page to the DTB size to be safe when extending it + dtb_size = page_align(os.fstat(args.dtb.fileno()).st_size) + 0x1000 + image_size += dtb_size + + # add some pages in case the region contains the loader + image_size += 0x2000 + + ram_regions = [region for region in config.memory_regions + if region.is_ram() and region.size >= image_size] + if not ram_regions: + print('No space found to load all images', file=sys.stderr) + exit(1) + + self._dtb_addr = ram_regions[0].virt_start + if self._dtb_addr == 0: + # leave room for the loader + self._dtb_addr += 0x2000 + self._kernel_addr = page_align(self._dtb_addr + dtb_size, + self.kernel_alignment()) + self._kernel_addr += kernel_load_offset + self._ramdisk_addr = self._kernel_addr + kernel_size + + self.params = 'kernel=0x%x dtb=0x%x' % (self._kernel_addr, + self._dtb_addr) + self.params = self.params.encode() + + self.dtb = DTB(args.dtb.read()) + + prop = self.dtb.get_prop('/', '#address-cells') + if not prop: + raise RuntimeError('Invalid DTB') + (cells,) = struct.unpack_from('>I', prop) + addr_format = '>Q' if cells == 2 else '>I' + + prop = self.dtb.get_prop('/', '#size-cells') + if not prop: + raise RuntimeError('Invalid DTB') + (cells,) = struct.unpack_from('>I', prop) + reg_format = addr_format + ('Q' if cells == 2 else 'I') + + self.dtb.set_prop('/memory', 'device_type', 'memory'.encode() + b'\0') + reg = bytearray(0) + for region in config.memory_regions: + # Filter out non-RAM regions and small ones at the start of the + # cell address space that is used for the loader. + if region.is_ram() and \ + (region.virt_start > 0 or region.size > 0x10000): + reg += struct.pack(reg_format, region.virt_start, region.size) + self.dtb.set_prop('/memory', 'reg', reg) + + if args.cmdline: + self.dtb.set_prop('/chosen', 'bootargs', + args.cmdline.encode() + b'\0') + if args.initrd: + self.dtb.set_prop('/chosen', 'linux,initrd-start', + struct.pack(addr_format, arch.ramdisk_address())) + end_addr = arch.ramdisk_address() + ramdisk_size + self.dtb.set_prop('/chosen', 'linux,initrd-end', + struct.pack(addr_format, end_addr)) + + def params_address(self): + return self._cpu_reset_address + 0x1000 + + def write_params(self, args, config): + args.write_params.write(self.dtb.get()) + args.write_params.close() + + print('\ +Modified device tree written. Start Linux with the following commands \ +(adjusting paths as needed):\n\ +\n\ +jailhouse cell create %s\n\ +jailhouse cell load %s linux-loader.bin -a 0x%x -s "%s" -a 0x%x %s -a 0x%x ' % + (args.config.name, config.name, self.loader_address(), + self.params.decode(), self.params_address(), + args.kernel.name + ('-unzipped' if self._kernel_gz else ''), + self._kernel_addr), end='') + if args.initrd: + print('%s -a 0x%x ' % (args.initrd.name, self._ramdisk_addr), + end='') + print('%s -a 0x%x' % (args.write_params.name, self._dtb_addr)) + print('jailhouse cell start %s' % config.name) + if self._kernel_gz: + print('\nNote that %s is zipped and requires decompression first.' + % args.kernel.name) + + def loader_address(self): + return self._cpu_reset_address + + def kernel_address(self): + return self._kernel_addr + + def dtb_address(self): + return self._dtb_addr + + def dtb(self): + return self.dtb.get() + + def ramdisk_address(self): + return self._ramdisk_addr + + +class ARM(ARMCommon): + name = 'arm' + + @staticmethod + def get_uncompressed_kernel(kernel): + return (kernel.read(), False) + + @staticmethod + def kernel_alignment(): + return 0x1000 + + @staticmethod + def get_kernel_offset(kernel): + return 0 + + @staticmethod + def default_decompression_factor(): + return 4 + + +class ARM64(ARMCommon): + name = 'arm64' + + @staticmethod + def get_uncompressed_kernel(kernel): + try: + unzipped = gzip.GzipFile(fileobj=kernel) + return (unzipped.read(), True) + except IOError: + kernel.seek(0) + return (kernel.read(), False) + + @staticmethod + def kernel_alignment(): + return 0x200000 + + @staticmethod + def get_kernel_offset(kernel_image): + (text_offset,) = struct.unpack_from('<8xQ', kernel_image) + return text_offset + + @staticmethod + def default_decompression_factor(): + return 1 + + +def resolve_arch(defined_arch=None): + arch_classes = {'x86': X86, 'arm': ARM, 'arm64': ARM64, None: None} + try: + arch_class = arch_classes[defined_arch] + except KeyError: + print('Unknown architecture', file=sys.stderr) + exit(1) + if not arch_class: + arch_str = os.uname()[4] + if arch_str in ('i686', 'x86_64'): + arch_class = X86 + elif arch_str == 'armv7l': + arch_class = ARM + elif arch_str == 'aarch64': + arch_class = ARM64 + else: + print('Unsupported architecture', file=sys.stderr) + exit(1) + return arch_class() + + +# see linux/Documentation/x86/boot.txt +class X86SetupHeader: + BASE_OFFSET = 0x1f0 + _HEADER_FORMAT = 'xB2xI8xH14xB7xII8xI4xI20xI4xQQ' + + def __init__(self, kernel_image): + base = X86SetupHeader.BASE_OFFSET + parse_size = struct.calcsize(X86SetupHeader._HEADER_FORMAT) + (self.setup_sects, + self.syssize, + self.jump, + self.type_of_loader, + self.ramdisk_image, + self.ramdisk_size, + self.cmd_line_ptr, + self.kernel_alignment, + self.payload_offset, + self.setup_data, + self.pref_address) = \ + struct.unpack(X86SetupHeader._HEADER_FORMAT, + kernel_image[base:base+parse_size]) + + self.size = 0x202 + (self.jump >> 8) - X86SetupHeader.BASE_OFFSET + self.data = bytearray(kernel_image[base:base+self.size]) + + def set_value_in_data(self, fmt, offset, value): + struct.pack_into(fmt, self.data, offset - X86SetupHeader.BASE_OFFSET, + value) + + def set_type_of_loader(self, value): + self.type_of_loader = value + self.set_value_in_data('B', 0x210, value) + + def set_ramdisk_image(self, value): + self.ramdisk_image = value + self.set_value_in_data('I', 0x218, value) + + def set_ramdisk_size(self, value): + self.ramdisk_size = value + self.set_value_in_data('I', 0x21c, value) + + def set_cmd_line_ptr(self, value): + self.cmd_line_ptr = value + self.set_value_in_data('I', 0x228, value) + + def set_kernel_alignment(self, value): + self.kernel_alignment = value + self.set_value_in_data('Q', 0x230, value) + + def set_setup_data(self, value): + self.setup_data = value + self.set_value_in_data('Q', 0x250, value) + + def set_pref_address(self, value): + self.pref_address = value + self.set_value_in_data('Q', 0x258, value) + + def get_data(self): + return self.data + + +def get_kernel_compression_method(payload_magic): + if payload_magic[0] == 0x1f and payload_magic[1] in (0x8b, 0x9e): + return 'gzip' + elif payload_magic[0] == 0x42 and payload_magic[1] == 0x5a: + return 'bzip2' + elif payload_magic[0] == 0x5d and payload_magic[1] == 0x0: + return 'lzma' + elif payload_magic[0] == 0xfd and payload_magic[1] == 0x37: + return 'xz' + elif payload_magic[0] == 0x02 and payload_magic[1] == 0x21: + return 'lz4' + elif payload_magic[0] == 0x89 and payload_magic[1] == 0x4c: + return 'lzo' + elif payload_magic[0] == 0x7f and payload_magic[1] == 0x45 and \ + payload_magic[2] == 0x4c and payload_magic[3] == 0x46: + return 'uncompressed' + else: + return 'unknown' + + +def mem_region_as_e820(mem): + E820_RAM = 1 + E820_RESERVED = 2 + + return struct.pack('QQI', mem.virt_start, mem.size, + E820_RAM if mem.is_ram() else E820_RESERVED) + + +# see linux/Documentation/x86/zero-page.txt +class X86ZeroPage: + def __init__(self, kernel_image, initrd, kernel_decomp_factor, config): + self.setup_header = X86SetupHeader(kernel_image) + + prot_image_offs = (self.setup_header.setup_sects + 1) * 512 + prot_image_size = self.setup_header.syssize * 16 + + self.kernel_load_addr = self.setup_header.pref_address - \ + prot_image_offs + + self.setup_header.set_kernel_alignment(self.setup_header.pref_address) + self.setup_header.set_type_of_loader(0xff) + + ramdisk_size = 0 + ramdisk_load_addr = 0 + if initrd: + kernel_size = len(kernel_image) + ramdisk_size = os.fstat(initrd.fileno()).st_size + + offs = prot_image_offs + self.setup_header.payload_offset + payload_magic = bytearray(kernel_image[offs:offs+4]) + compression_method = get_kernel_compression_method(payload_magic) + + # Unless specified, derive decompression factor from method + if kernel_decomp_factor: + decompression_factor = kernel_decomp_factor + elif compression_method in ('bzip2'): + # "Bzip2 uses a large amount of memory." + # And that causes a larger binary, thus a smaller factor. + decompression_factor = 4 + elif compression_method in ('lz4', 'lzo'): + decompression_factor = 6 + elif compression_method in ('gzip'): + decompression_factor = 7 + elif compression_method in ('lzma'): + decompression_factor = 8 + else: # xz or unknown + decompression_factor = 9 + decompression_space = decompression_factor * kernel_size + + ramdisk_load_addr = page_align(self.kernel_load_addr + + decompression_space) + + self.setup_header.set_ramdisk_image(ramdisk_load_addr) + self.setup_header.set_ramdisk_size(ramdisk_size) + + self.e820_entries = [] + for region in config.memory_regions: + if region.is_ram() or region.is_comm_region(): + if len(self.e820_entries) >= 128: + print('Too many memory regions', file=sys.stderr) + exit(1) + self.e820_entries.append(region) + + def get_data(self): + data = bytearray(0x1e8) + \ + struct.pack('B', len(self.e820_entries)) + \ + bytearray(X86SetupHeader.BASE_OFFSET - 0x1e9) + \ + self.setup_header.get_data() + \ + bytearray(0x2d0 - X86SetupHeader.BASE_OFFSET - + self.setup_header.size) + for region in self.e820_entries: + data += mem_region_as_e820(region) + return data + bytearray(0x1000 - len(data)) + + +def x86_gen_setup_data(config): + SETUP_TYPE_JAILHOUSE = 6 + MAX_CPUS = 255 + SETUP_DATA_VERSION = 2 + SETUP_DATA_COMPAT_VERSION = 1 + standard_ioapic = 0 + setup_data_hdr_struct = '8xII' + setup_data_struct = ('HH12x8xB%uxI' % MAX_CPUS) + + for irqchip in config.irqchips: + if irqchip.is_standard(): + standard_ioapic = 1 + + flags = 0 + platform_uarts = [0x3f8, 0x2f8, 0x3e8, 0x2e8] + for pio_region in config.pio_regions: + if pio_region.base in platform_uarts and pio_region.length == 8: + flags |= (1 << platform_uarts.index(pio_region.base)) + + return struct.pack(setup_data_hdr_struct, SETUP_TYPE_JAILHOUSE, + struct.calcsize(setup_data_struct)) + \ + struct.pack(setup_data_struct, SETUP_DATA_VERSION, + SETUP_DATA_COMPAT_VERSION, standard_ioapic, flags) + + +# pretend to be part of the jailhouse tool +sys.argv[0] = sys.argv[0].replace('-', ' ') + +parser = argparse.ArgumentParser(description='Boot Linux in a non-root cell.') +parser.add_argument('config', metavar='CELLCONFIG', + type=argparse.FileType('rb'), + help='cell configuration file') +parser.add_argument('kernel', metavar='KERNEL', + type=argparse.FileType('rb'), + help='image of the kernel to be booted') +parser.add_argument('-d', '--dtb', metavar='DTB', + type=argparse.FileType('rb'), + help='device tree for the kernel [arm/arm64 only]') +parser.add_argument('-i', '--initrd', metavar='INITRD', + type=argparse.FileType('rb'), + help='initrd/initramfs for the kernel') +parser.add_argument('-c', '--cmdline', metavar='"CMDLINE"', + help='kernel command line') +parser.add_argument('-w', '--write-params', metavar='PARAMS_FILE', + type=argparse.FileType('wb'), + help='only parse cell configuration, write out ' + 'parameters into the specified file and print ' + 'required jailhouse cell commands to boot Linux ' + 'to the console') +parser.add_argument('-a', '--arch', metavar='ARCH', + help='target architecture') +parser.add_argument('-k', '--kernel-decomp-factor', metavar='FACTOR', + type=int, + help='decompression factor of the kernel image, used to ' + 'reserve space between the kernel and the initramfs') + +try: + args = parser.parse_args() +except IOError as e: + print(e.strerror, file=sys.stderr) + exit(1) + +arch = resolve_arch(args.arch) + +try: + config = config_parser.CellConfig(args.config.read()) +except RuntimeError as e: + print(str(e) + ": " + args.config.name, file=sys.stderr) + exit(1) + +arch.setup(args, config) + +if args.write_params: + arch.write_params(args, config) +else: + if libexecdir: + linux_loader = libexecdir + '/jailhouse/linux-loader.bin' + else: + linux_loader = os.path.abspath(os.path.dirname(sys.argv[0])) + \ + '/../inmates/tools/' + arch.name + '/linux-loader.bin' + + cell = JailhouseCell(config) + cell.load(open(linux_loader, mode='rb').read(), arch.loader_address()) + cell.load(arch.kernel_image, arch.kernel_address()) + if arch.dtb_address(): + cell.load(arch.dtb.get(), arch.dtb_address()) + if args.initrd: + cell.load(args.initrd.read(), arch.ramdisk_address()) + cell.load(arch.params, arch.params_address()) + cell.start() diff --git a/tools/jailhouse-cell-stats b/tools/jailhouse-cell-stats new file mode 100755 index 0000000000000000000000000000000000000000..7a6342121b09a982bb4781000571abfd349b9bc8 --- /dev/null +++ b/tools/jailhouse-cell-stats @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +import curses +import datetime +import os +import sys + +cells_dir = "/sys/devices/jailhouse/cells/" +cell_dir = cells_dir + "%d/" +stats_dir = cell_dir + "statistics/" + + +def main(stdscr, cell_id, cell_name, stats_names, cpus): + def reset_stats(): + curses.halfdelay(10) + return dict.fromkeys(stats_names, None) + + try: + curses.use_default_colors() + curses.curs_set(0) + except curses.error: + pass + curses.noecho() + value = dict.fromkeys(stats_names) + old_value = reset_stats() + cpu = -1 + while True: + now = datetime.datetime.now() + + for name in stats_names: + cpu_dir = ("/cpu%d" % cpus[cpu]) if cpu >= 0 else "" + f = open((stats_dir + cpu_dir + "/%s") % (cell_id, name), "r") + value[name] = int(f.read()) + + def sortkey(name): + if old_value[name] is None: + return (-value[name], name) + else: + return (old_value[name] - value[name], -value[name], name) + + stdscr.erase() + stdscr.addstr(0, 0, "Statistics for %s cell" % cell_name) + (height, width) = stdscr.getmaxyx() + stdscr.hline(2, 0, " ", width, curses.A_REVERSE) + stdscr.addstr(2, 0, "COUNTER ", curses.A_REVERSE) + if cpu >= 0: + stdscr.addstr(2, 8, "(CPU %d)" % cpus[cpu], curses.A_REVERSE) + else: + stdscr.addstr(2, 8, "(All CPUs)", curses.A_REVERSE) + stdscr.addstr(2, 30, "%10s" % "SUM", curses.A_REVERSE) + stdscr.addstr(2, 40, "%10s" % "PER SEC", curses.A_REVERSE) + line = 3 + for name in sorted(stats_names, key=sortkey): + stdscr.addstr(line, 0, name) + stdscr.addstr(line, 30, "%10u" % value[name]) + if not old_value[name] is None: + dt = (now - last_refresh).total_seconds() + delta_per_sec = (value[name] - old_value[name]) / dt + stdscr.addstr(line, 40, "%10u" % round(delta_per_sec)) + old_value[name] = value[name] + line += 1 + stdscr.hline(height - 1, 0, " ", width, curses.A_REVERSE) + stdscr.addstr(height - 1, 1, + "Q - Quit | C - Toggle CPU | A - All CPUs", + curses.A_REVERSE) + stdscr.refresh() + + last_refresh = now + + try: + c = stdscr.getch() + if c == ord('q'): + break + elif c == ord('c'): + old_value = reset_stats() + cpu = (cpu + 1) % len(cpus) + elif c == ord('a'): + old_value = reset_stats() + cpu = -1 + else: + curses.halfdelay(40) + except KeyboardInterrupt: + break + except curses.error: + continue + + +def usage(exit_code): + prog = os.path.basename(sys.argv[0]).replace('-', ' ') + print("usage: %s { ID | [--name] NAME }" % prog) + exit(exit_code) + + +argc = len(sys.argv) +use_name = argc >= 2 and sys.argv[1] == "--name" + +if argc < 2 or argc > 3 or (not use_name and argc > 2): + usage(1) +if sys.argv[1] in ("--help", "-h"): + usage(0) + +cell_id = -1 +try: + if use_name: + cell_name = sys.argv[2] + else: + cell_name = sys.argv[1] + try: + cell_id = int(sys.argv[1]) + with open((cell_dir + "name") % cell_id, "r") as f: + cell_name = f.read().rstrip() + except ValueError: + pass + + if cell_id == -1: + for id in os.listdir(cells_dir): + f = open((cell_dir + "name") % int(id), "r") + if f.read().rstrip() == cell_name: + cell_id = int(id) + break + + entries = os.listdir(stats_dir % cell_id) + stats_names = [d for d in entries if d.startswith("vmexits_")] + cpus = sorted([int(d[3:]) for d in entries if d.startswith("cpu")]) +except OSError as e: + print("reading stats: %s" % e.strerror, file=sys.stderr) + exit(1) + +curses.wrapper(main, cell_id, cell_name, stats_names, cpus) diff --git a/tools/jailhouse-cell.8.in b/tools/jailhouse-cell.8.in new file mode 100644 index 0000000000000000000000000000000000000000..34d7be767f5a5e8f51bf175874039bcb59c20831 --- /dev/null +++ b/tools/jailhouse-cell.8.in @@ -0,0 +1,123 @@ +'\" t +.\" Title: jailhouse +.\" Author: [see the "Authors" section] +.\" Date: 14/04/2018 +.\" Manual: Jailhouse Manual +.\" Source: Git 0.8 +.\" Language: English +.\" +.TH "JAILHOUSE-CELL" "8" "14/04/2018" "Jailhouse ${VERSION}" "Jailhouse Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +jailhouse-cell \- controlling cells +.SH "SYNOPSIS" +.sp +.nf +\fIjailhouse\fR cell [collect | create | destroy | linux | load | shutdown | start | stats] [] +.fi +.sp +.SH "DESCRIPTION" +.sp +.PP +\fBjailhouse cell load\fR { ID | [--name] NAME } { } ... +.RS 4 +.sp +Where is { IMAGE | { -s | --string } "STRING" } [-a | --address ADDRESS]} +.RE +.RS 4 +.sp +Valid forms are: +.sp + # loads inmate\&.bin (offset 0 assumed) + jailhouse cell load foocell inmate\&.bin +.sp + # same as above with explicit location + jailhouse cell load foocell inmate\&.bin -a 0 +.sp + # loads three binary objects (in order) + jailhouse cell load foocell \\ + inmate\&.bin \\ + sharedobject\&.so -a 0x1000000 \\ + ramfs\&.bin -a 0x2000000 +.RE +.RS 4 +.sp +If no address is specified (e.g., inmate\&.bin in the above example), the +address will default to 0x0. +.sp +The last example, loads in the order specified, three binary objects, +the first one at offset 0, the second one at 0x1000000\&. +Should inmate.bin be larger than 0x1000000, the upper part will be overridden +by sharedobject\&.so\&. +.sp +Whatever load order, execution starts in the cell at offset 0 unless otherwise +specified in the cell config (cpu_reset_address). +.sp +This multi-image loading capability can be used to patch images and +pass parameters to the image\&. The following explains how parameters are passed +with the inmate library\&. +.sp +The inmate library assumes a command line string to be located at a fixed +location. On all architectures, this is offset 0x1000 (see +inmates/lib/ARCH/inmate\&.lds[.S]) +.RE +.RS 4 +.sp +The command line string capacity is defined during compile time by CMDLINE_BUFFER_SIZE +in inmates/lib/cmdline\&.c or by defining a non weak instance of CMDLINE_BUFFER()\&. +Please note that capacity includes trailing \\0. +.sp +Here is an example to pass parameters stored in the file commandline.txt to the +inmate inmate\&.bin: +.sp + CMDLINE_OFFSET=0x1000 + jailhouse cell load foocell \\ + inmate\&.bin \\ + commandline\&.txt -a $CMDLINE_OFFSET \\ + sharedobject\&.so -a 0x1000000 \\ + ramfs\&.bin -a 0x2000000 +.sp +This command patches inmate.bin at offset 0x1000 that corresponds to the "char +*cmdline" location as controlled by the link script for inmates\&. +.sp +To be more practical and avoid using a text file, there is an image-as-string +option: +.sp + CMDLINE_OFFSET=0x1000 + jailhouse cell load foocell \\ + inmate\&.bin \\ + -s "" -a $CMDLINE_OFFSET \\ + sharedobject\&.so -a 0x1000000 \\ + ramfs\&.bin -a 0x2000000 +.sp + +.RE + +.SH "SEE ALSO" +jailhouse(8) jailhouse-enable(8) jailhouse.ko(8) +.SH "AUTHORS" +.sp +Jailhouse was started by Jan Kiszka\&. Contributions have come from the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2>\&. +.sp +If you have a clone of jailhouse\&.git itself, the output of \fBgit-shortlog\fR(1) and \fBgit-blame\fR(1) can show you the authors for specific parts of the project\&. +.SH "REPORTING BUGS" +.sp +Report bugs to the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2> where the development and maintenance is primarily done\&. You do not have to be subscribed to the list to send a message there\&. diff --git a/tools/jailhouse-completion.bash b/tools/jailhouse-completion.bash new file mode 100644 index 0000000000000000000000000000000000000000..09a9a1ed76b6e229480bea41a017c8118ec085c5 --- /dev/null +++ b/tools/jailhouse-completion.bash @@ -0,0 +1,432 @@ +# bash completion for jailhouse +# +# Copyright (c) Benjamin Block, 2014 +# Copyright (c) Siemens AG, 2015-2020 +# +# Authors: +# Benjamin Block +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# + +# usage: - add the directory containing the `jailhouse`-tool to your +# ${PATH}-variable +# - source this file `. tools/jailhouse-completion.bash` +# - alternatively you can put this file into your distribution's +# bash-completion directory +# +# there is a broad variety of places where distributions may put this: +# - /usr/share/bash-completion/ +# - /etc/bash_completion.d/ +# - $BASH_COMPLETION_COMPAT_DIR +# - $BASH_COMPLETION_DIR +# - ... + +# dependencies: - bash-completion (>= 1.3) package installed and activated in +# your bash + +# bash-completion websites: +# - http://bash-completion.alioth.debian.org/ +# - https://wiki.debian.org/Teams/BashCompletion +# - http://anonscm.debian.org/cgit/bash-completion/bash-completion.git/ + +# only if jailhouse is in ${PATH} +( which jailhouse &>/dev/null ) && \ +{ + +# test for the required helper-functions +if ! type _filedir &>/dev/null; then + # functions not defined + # + # The distributions seem to handle the inclusion of these function in a + # broad variety of ways. To keep this script as simple as possible we + # depend on this to work. + + return 1 +fi + +function _jailhouse_get_id() { + local names ids cur prev quoted quoted_cur toks + + cur="${1}" + prev="${2}" + if [[ ${3} = with_root ]]; then + cells=/sys/devices/jailhouse/cells/* + else + cells=/sys/devices/jailhouse/cells/[1-9]* + fi + + ids="" + names="" + + _quote_readline_by_ref "$cur" quoted_cur + + # handle the '{ ID | [--name] NAME }' part of cell-calls + # + # if we are at position 3 of the commnadline we can either input a + # concrete `ID`/`NAME` or the option `--name` + if [ "${COMP_CWORD}" -eq 3 ]; then + shopt -q nullglob && nullglob_set=true + shopt -s nullglob + + # get possible ids and names + for i in ${cells}; do + ids="${ids} ${i##*/}" + names="${names} $(<${i}/name)" + done + + [ ! $nullglob_set ] && shopt -u nullglob + + if [ "${ids}" == "" ]; then + return 1; + fi + + COMPREPLY=( $( compgen -W "--name ${ids} ${names}" -- \ + ${quoted_cur} ) ) + + # if we are already at position 4, may enter a `NAME`, if `--name` was + # given before + elif [ "${COMP_CWORD}" -eq 4 ]; then + [ "${prev}" = "--name" ] || return 1 + + shopt -q nullglob && nullglob_set=true + shopt -s nullglob + + # get possible names + for n in ${cells}; do + names="${names} $(<${n})" + done + + [ ! $nullglob_set ] && shopt -u nullglob + + COMPREPLY=( $( compgen -W "${names}" -- ${quoted_cur} ) ) + + # the id or name is only accepted at position 3 or 4 + else + return 1; + fi + + return 0; +} + +function _jailhouse_cell_linux() { + local cur prev word + + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + options="-h --help -i --initrd -c --cmdline -w --write-params" + + # if we already have begun to write an option + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "${options}" -- "${cur}") ) + else + # if the previous was on of the following options + case "${prev}" in + -d|--dtb|-i|--initrd|-w|--write-params) + # search an existing file + _filedir + return $? + ;; + -c|--cmdline) + # we can't really predict this + return 0 + ;; + esac + + # neither option, nor followup of one. Lets assume we want + # the cell or the kernel + for n in `seq ${COMP_CWORD-1}`; do + word="${COMP_WORDS[n]}" + if [[ "${word}" == *.cell ]] && ( [ $n -eq 1 ] || + [[ "${COMP_WORDS[n-1]}" != -* ]] ); then + # we already have a cell, this is the kernel + _filedir + return 0 + fi + done + _filedir "cell" + fi + + return 0 +} + +function _jailhouse_cell() { + local cur prev quoted_cur + + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + _quote_readline_by_ref "$cur" quoted_cur + + # handle subcommand of the cell-command + case "${1}" in + create) + # search for guest-cell configs + + # this command takes only a argument at place 3 + [ "${COMP_CWORD}" -gt 3 ] && return 1 + + _filedir "cell" + ;; + load) + # first, select the id/name of the cell we want to load a image + # for + _jailhouse_get_id "${cur}" "${prev}" no_root && return 0 + + # [image & address] can be repeated + + # after id/name insert image-file or string switch (always true) + if [ "${COMP_CWORD}" -eq 4 ] || ( [ "${COMP_CWORD}" -eq 5 ] && \ + [ "${COMP_WORDS[3]}" = "--name" ] ); then + + # did we already start to type string switch? + if [[ "${COMP_CWORD}" -eq 4 && "$cur" == -* ]]; then + COMPREPLY=( $( compgen \ + -W "-s --string" -- \ + "${cur}") ) + fi + + _filedir + return 0 + fi + + # the first image or string have to be given, after that it is: + # + # [{image | <-s|--string> string} [<-a|--address>
] + # [{image | <-s|--string> string} [...] ... ]] + + # prev was an address or a string switch, no image here + if [[ "${prev}" = "-a" || "${prev}" = "--address" || + "${prev}" = "-s" || "${prev}" = "--string" ]]; then + return 0 + + # prev was an image, a string or an address-number + else + # did we already start to type another switch + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen \ + -W "-a --address -s --string" -- \ + "${cur}") ) + fi + + # default to image-file + _filedir + return 0 + fi + + ;; + start) + # takes only one argument (id/name) + _jailhouse_get_id "${cur}" "${prev}" no_root || return 1 + ;; + shutdown) + # takes only one argument (id/name) + _jailhouse_get_id "${cur}" "${prev}" no_root || return 1 + ;; + destroy) + # takes only one argument (id/name) + _jailhouse_get_id "${cur}" "${prev}" no_root || return 1 + ;; + linux) + _jailhouse_cell_linux || return 1 + ;; + list) + # list all cells + + # this command takes only a argument at place 3 + [ "${COMP_CWORD}" -gt 3 ] && return 1 + + COMPREPLY=( $( compgen -W "-h --help" -- "${cur}") ) + return 0;; + stats) + # takes only one argument (id/name) + _jailhouse_get_id "${cur}" "${prev}" with_root || return 1 + + if [ "${COMP_CWORD}" -eq 3 ]; then + COMPREPLY=( ${COMPREPLY[@]-} $( compgen -W "-h --help" \ + -- ${quoted_cur} ) ) + fi + ;; + *) + return 1;; + esac + + return 0 +} + +function _jailhouse_config_create() { + local cur prev + + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + options="-h --help -g --generate-collector -r --root -t --template-dir \ + --mem-inmates --mem-hv" + + # if we already have begun to write an option + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "${options}" -- "${cur}") ) + else + # if the previous was on of the following options + case "${prev}" in + -r|--root|-t|--template-dir) + # search a existing directory + _filedir -d + return $? + ;; + --mem-inmates|--mem-hv) + # we can't really predict this + return 0 + ;; + esac + + # neither option, nor followup of one. Lets assume we want the + # target-filename + _filedir + fi + + return 0 +} + +function _jailhouse_config_check() { + local cur + + cur="${COMP_WORDS[COMP_CWORD]}" + + options="-h --help" + + # if we already have begun to write an option + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "${options}" -- "${cur}") ) + else + # neither option, nor followup of one. Lets assume we want the + # target-filename + _filedir "cell" + fi + + return 0 +} + +function _jailhouse() { + # returns two value: - numeric from "return" (success/failure) + # - ${COMPREPLY}; an bash-array from which bash will + # read the possible completions (reset this here) + COMPREPLY=() + + local command command_cell command_config cur prev subcommand + + # first level + command="enable disable console cell config hardware --help" + + # second level + command_cell="create load start shutdown destroy linux list stats" + command_config="create collect check" + + # ${COMP_WORDS} array containing the words on the current command line + # ${COMP_CWORD} index into COMP_WORDS, pointing at the current position + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + # command line parsing for the jaihouse-tool is pretty static right + # now, the first two levels can be parsed simpy by comparing + # postions + + # ${COMP_CWORD} contains at which argument-position we currently are + # + # if at level 1, we select from first level list + if [ "${COMP_CWORD}" -eq 1 ]; then + COMPREPLY=( $( compgen -W "${command}" -- "${cur}") ) + + # if at level 2, we have to evaluate level 1 and look for the main + # command + elif [ "${COMP_CWORD}" -eq 2 ]; then + command="${COMP_WORDS[1]}" + + case "${command}" in + enable) + # a root-cell configuration + _filedir "cell" + ;; + console) + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "-f --follow" -- \ + "${cur}") ) + fi + ;; + cell) + # one of the following subcommands + COMPREPLY=( $( compgen -W "${command_cell}" -- \ + "${cur}") ) + ;; + config) + # one of the following subcommands + COMPREPLY=( $( compgen -W "${command_config}" -- \ + "${cur}") ) + ;; + hardware) + COMPREPLY="check" + ;; + --help|disable) + # these first level commands have no further subcommand + # or option OR we don't even know it + return 0;; + *) + return 1;; + esac + + # after level 2 it gets more complecated in some cases + else + command="${COMP_WORDS[1]}" + subcommand="${COMP_WORDS[2]}" + + case "${command}" in + cell) + # handle cell-commands + _jailhouse_cell "${subcommand}" || return 1 + ;; + config) + case "${subcommand}" in + create) + _jailhouse_config_create || return 1 + ;; + collect) + # config-collect writes to a new file + + # this command takes only a argument at place 3 + [ "${COMP_CWORD}" -gt 3 ] && return 1 + + _filedir + ;; + check) + _jailhouse_config_check || return 1 + ;; + *) + return 1;; + esac + ;; + hardware) + case "${subcommand}" in + check) + # this command takes only a argument at place 3 + [ "${COMP_CWORD}" -gt 3 ] && return 1 + + _filedir + ;; + *) + return 1;; + esac + ;; + *) + # no further subsubcommand/option known for this + return 1;; + esac + fi + + return 0 +} +complete -F _jailhouse jailhouse + +} diff --git a/tools/jailhouse-config-check b/tools/jailhouse-config-check new file mode 100755 index 0000000000000000000000000000000000000000..d6ea707943e2fdf4027ac2b2b022607388a2edfa --- /dev/null +++ b/tools/jailhouse-config-check @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2020 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# This script should help to create a basic jailhouse configuration file. +# It needs to be executed on the target machine, where it will gather +# information about the system. For more advanced scenarios you will have +# to change the generated C-code. + +import argparse +import os +import sys + +# Imports from directory containing this must be done before the following +sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.." +import pyjailhouse.config_parser as config_parser + + +class ResourceRegion(config_parser.MemRegion): + def __init__(self, phys_start, size, name=None): + self.phys_start = phys_start + self.virt_start = phys_start + self.size = size + self.flags = 0 + self.name = name + + +# pretend to be part of the jailhouse tool +sys.argv[0] = sys.argv[0].replace('-', ' ') + +parser = argparse.ArgumentParser(description='Check system and cell configurations.') +parser.add_argument('-a', '--arch', metavar='ARCH', + help='target architecture') +parser.add_argument('syscfg', metavar='SYSCONFIG', + type=argparse.FileType('rb'), + help='system configuration file') +parser.add_argument('cellcfgs', metavar='CELLCONFIG', nargs="*", + type=argparse.FileType('rb'), + help='cell configuration file') + +try: + args = parser.parse_args() +except IOError as e: + print(e.strerror, file=sys.stderr) + exit(1) + +arch = args.arch +if not arch: + arch_str = os.uname()[4] + if arch_str in ('i686', 'x86_64'): + arch = 'x86' + elif arch_str == 'armv7l': + arch = 'arm' + elif arch_str == 'aarch64': + arch = 'arm64' + else: + arch = None +if not arch in ('x86', 'arm', 'arm64'): + print('Unsupported architecture', file=sys.stderr) + exit(1) + +print("Reading configuration set:") + +try: + sysconfig = config_parser.SystemConfig(args.syscfg.read(), arch) + root_cell = sysconfig.root_cell +except RuntimeError as e: + print(str(e) + ": " + args.syscfg.name, file=sys.stderr) + exit(1) +cells = [root_cell] +print(" Root cell: %s (%s)" % (root_cell.name, args.syscfg.name)) + +non_root_cells = [] +for cfg in args.cellcfgs: + try: + cell = config_parser.CellConfig(cfg.read()) + except RuntimeError as e: + print(str(e) + ": " + cfg.name, file=sys.stderr) + exit(1) + non_root_cells.append(cell) + cells.append(cell) + print(" Non-root cell: %s (%s)" % (cell.name, cfg.name)) + +ret=0 + +print("Overlapping memory regions inside cell:", end='') +found=False +for cell in cells: + for mem in cell.memory_regions: + idx = cell.memory_regions.index(mem) + for mem2 in cell.memory_regions[idx + 1:]: + idx2 = cell.memory_regions.index(mem2) + overlaps = [] + if (mem.phys_overlaps(mem2)): + overlaps.append("physically") + if (mem.virt_overlaps(mem2)): + overlaps.append("virtually") + if overlaps: + print("\n\nIn cell '%s', region %d" % (cell.name, idx)) + print(str(mem)) + print(" and ".join(overlaps) + \ + " overlaps with region %d\n" % idx2 + str(mem2), end='') + found=True + ret=1 +print("\n" if found else " None") + +print("Overlapping memory regions with hypervisor:", end='') +found=False +for cell in cells: + for mem in cell.memory_regions: + if mem.phys_overlaps(sysconfig.hypervisor_memory): + idx = cell.memory_regions.index(mem) + print("\n\nIn cell '%s', region %d" % (cell.name, idx)) + print(str(mem)) + print("overlaps with hypervisor memory region") + print(str(sysconfig.hypervisor_memory), end='') + found=True + ret=1 +print("\n" if found else " None") + +if sysconfig.pci_mmconfig_base > 0: + print("Missing PCI MMCONFIG interceptions:", end='') + mmcfg_size = (sysconfig.pci_mmconfig_end_bus + 1) * 256 * 4096 + pci_mmcfg = ResourceRegion(sysconfig.pci_mmconfig_base, mmcfg_size) + + for cell in cells: + for mem in cell.memory_regions: + idx = cell.memory_regions.index(mem) + if mem.phys_overlaps(pci_mmcfg): + print("\n\nIn cell '%s', region %d" %(cell.name, idx)) + print(str(mem)) + print("overlaps with MMCONFIG") + print(str(pci_mmcfg), end='') + found=True + ret=1 + print("\n" if found else " None") + +iommu_resources = [] +for iommu in sysconfig.iommus: + iommu_resources.append(ResourceRegion(iommu.base, iommu.size, "IOMMU")) +if len(iommu_resources) > 0: + print("Missing IOMMU interceptions:", end='') + found=False + for cell in cells: + for mem in cell.memory_regions: + idx = cell.memory_regions.index(mem) + for iommu in iommu_resources: + if mem.phys_overlaps(iommu): + print("\n\nIn cell '%s', region %d" %(cell.name, idx)) + print(str(mem)) + print("overlaps with IOMMU") + print(str(iommu), end='') + found=True + ret=1 + print("\n" if found else " None") + +print("Missing resource interceptions for architecture %s:" % arch, end='') +found=False +if arch in ('arm', 'arm64'): + arch_resources = [] + if sysconfig.arm_gic_version == 2: + arch_resources.append(ResourceRegion(sysconfig.arm_gicd_base, 0x1000, + "GICD")) + arch_resources.append(ResourceRegion(sysconfig.arm_gicc_base, 0x2000, + "GICC")) + arch_resources.append(ResourceRegion(sysconfig.arm_gich_base, 0x2000, + "GICH")) + arch_resources.append(ResourceRegion(sysconfig.arm_gicv_base, 0x2000, + "GICV")) + elif sysconfig.arm_gic_version == 3: + arch_resources.append(ResourceRegion(sysconfig.arm_gicd_base, 0x10000, + "GICD")) + arch_resources.append(ResourceRegion(sysconfig.arm_gicr_base, 0x20000, + "GICR")) + else: + raise RuntimeError("Unknown GIC version: %d" % + sysconfig.arm_gic_version) +elif arch == 'x86': + arch_resources = [ResourceRegion(0xfee00000, 0x1000, "xAPIC")] + for irqchip in root_cell.irqchips: + arch_resources.append(ResourceRegion(irqchip.address, 0x1000, + "IOAPIC")) +for cell in cells: + for mem in cell.memory_regions: + idx = cell.memory_regions.index(mem) + for arch_resource in arch_resources: + if mem.phys_overlaps(arch_resource): + print("\n\nIn cell '%s', region %d" % (cell.name, idx)) + print(str(mem)) + print("overlaps with %s" % arch_resource.name) + print(str(arch_resource), end='') + found=True + ret=1 +print("\n" if found else " None") + +exit(ret) diff --git a/tools/jailhouse-config-collect.tmpl b/tools/jailhouse-config-collect.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..c8ca89c94e876f32d578ddb63ffc38ce4cd925c2 --- /dev/null +++ b/tools/jailhouse-config-collect.tmpl @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014 +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# This script will collect information needed to generate a Jailhouse +# configuration for hypervisor and root cell (Linux). +# +# Run it like that: +# $ jailhouse-config-collect.sh mytarget.tar +# +# Copying files and directories from /sys and /proc is surprisingly hard +# it would be nice to use just one tool together with the list of files. +# The main problem is that stat does not report the correct file sizes. In +# procfs files seem to have a size of 0 while in sysfs they often appear +# bigger than they really are. +# Archivers like tar/cpio etc. can not be used for procfs and sysfs. +# This script first gets a temporary copy of all the files we want. After +# copying the files can be archived with tar. + +set -e + +if test "x$( id -u )" != "x0"; then + echo "Please run as root" 1>&2 + exit 1 +fi + +if test -z "$1" || test "$1" = "--help"; then + echo "Usage: $0 mytarget.tar" 1>&2 + exit 1 +fi + +filelist="${filelist}" +filelist_opt="${filelist_opt}" +filelist_intel="${filelist_intel}" +filelist_amd="${filelist_amd}" + +tmpdir=/tmp/jailhouse-config-collect.$$ + +rm -rf $tmpdir +mkdir $tmpdir + +copy_file() +{ + dstdir=$tmpdir/$(dirname $1) + if [ ! -d $dstdir ]; then + mkdir -p $dstdir + fi + cp -p $1 $tmpdir/$1 +} + +# copy all the files we need to a temporary directory first +for f in $filelist; do + copy_file $f +done +grep GenuineIntel /proc/cpuinfo > /dev/null && + for f in $filelist_intel; do + copy_file $f + done +grep AuthenticAMD /proc/cpuinfo > /dev/null && + for f in $filelist_amd; do + copy_file $f + done +for f in $filelist_opt; do + if [ -f $f ]; then + copy_file $f + fi +done + +# now archive it and remove temporary copy +tar -C $tmpdir -cf $1 . +rm -rf $tmpdir + +exit 0 diff --git a/tools/jailhouse-config-create b/tools/jailhouse-config-create new file mode 100755 index 0000000000000000000000000000000000000000..c2cd5952bcb242439ec4f9da325fa8a8bacf5c5a --- /dev/null +++ b/tools/jailhouse-config-create @@ -0,0 +1,336 @@ +#!/usr/bin/env python3 +# +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2014-2017 +# Copyright (c) Valentine Sinitsyn, 2014-2015 +# +# Authors: +# Henning Schild +# Jan Kiszka +# Valentine Sinitsyn +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# This script should help to create a basic jailhouse configuration file. +# It needs to be executed on the target machine, where it will gather +# information about the system. For more advanced scenarios you will have +# to change the generated C-code. + +import sys +import os +import math +import re +import argparse +import struct + +try: + from mako.template import Template +except ImportError: + print("This script requires the mako library to run.") + sys.exit(1) + +# Imports from directory containing this must be done before the following +sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.." +import pyjailhouse.sysfs_parser as sysfs_parser + +datadir = None + +if datadir: + template_default_dir = datadir + "/jailhouse" +else: + template_default_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + +# pretend to be part of the jailhouse tool +sys.argv[0] = sys.argv[0].replace('-', ' ') + +parser = argparse.ArgumentParser() +parser.add_argument('-g', '--generate-collector', + help='generate a script to collect input files on ' + 'a remote machine', + action='store_true') +parser.add_argument('-r', '--root', + help='gather information in ROOT/, the default is "/" ' + 'which means creating a config for localhost', + default='/', + action='store', + type=str) +parser.add_argument('-t', '--template-dir', + help='the directory where the templates are located,' + 'the default is "' + template_default_dir + '"', + default=template_default_dir, + action='store', + type=str) +parser.add_argument('-c', '--console', + help='the name of the UART device that should be used as ' + 'primary hypervisor debug console ("ttyX" or "none")', + default='ttyS0', + action='store', + type=str) + +memargs = [['--mem-inmates', '76M', 'inmate'], + ['--mem-hv', '6M', 'hypervisor']] + +for entry in memargs: + parser.add_argument(entry[0], + help='the amount of ' + entry[2] + + ' memory, default is "' + entry[1] + + '", format "xxx[K|M|G]"', + default=entry[1], + action='store', + type=str) + +parser.add_argument('file', metavar='FILE', + help='name of file to write out', + type=str) + +options = parser.parse_args() + + +def kmg_multiply(value, kmg): + if (kmg == 'K' or kmg == 'k'): + return 1024 * value + if (kmg == 'M' or kmg == 'm'): + return 1024**2 * value + if (kmg == 'G' or kmg == 'g'): + return 1024**3 * value + return value + + +def kmg_multiply_str(str): + m = re.match(r'([0-9a-fA-FxX]+)([KMG]?)', str) + if m is not None: + return kmg_multiply(int(m.group(1)), m.group(2)) + raise RuntimeError('kmg_multiply_str can not parse input "' + str + '"') + + +def input_readline(name, optional=False): + f = sysfs_parser.input_open(name, optional=optional) + line = f.readline() + f.close() + return line + + +def parse_kernel_cmdline(): + line = input_readline('/proc/cmdline') + ma = re.findall(r'memmap=([0-9a-fA-FxX]+)([KMG]?)\$' + '([0-9a-fA-FxX]+)([KMG]?)', line) + if (len(ma) == 0): + return None + size = kmg_multiply(int(ma[0][0], 0), ma[0][1]) + start = kmg_multiply(int(ma[0][2], 0), ma[0][3]) + if (len(ma) > 1): + print('WARNING: Multiple "memmap" reservations in /proc/cmdline. ' + 'Picking the first for jailhouse!', file=sys.stderr) + + return [start, size] + + +def alloc_mem(regions, size): + mem = [0x3a000000, size] + for r in regions: + if ( + r.typestr == 'System RAM' and + r.start <= mem[0] and + r.stop + 1 >= mem[0] + mem[1] + ): + if r.start < mem[0]: + head_r = sysfs_parser.MemRegion(r.start, mem[0] - 1, r.typestr, + r.comments) + regions.insert(regions.index(r), head_r) + if r.stop + 1 > mem[0] + mem[1]: + tail_r = sysfs_parser.MemRegion(mem[0] + mem[1], r.stop, + r.typestr, r.comments) + regions.insert(regions.index(r), tail_r) + regions.remove(r) + return mem + for r in reversed(regions): + if (r.typestr == 'System RAM' and r.size() >= mem[1]): + mem[0] = r.start + r.start += mem[1] + return mem + raise RuntimeError('failed to allocate memory') + + +def count_cpus(): + list = sysfs_parser.input_listdir('/sys/devices/system/cpu', ['cpu*/uevent']) + count = 0 + for f in list: + if re.match(r'cpu[0-9]+', f): + count += 1 + return count + +class MMConfig: + def __init__(self, base, end_bus): + self.base = base + self.end_bus = end_bus + + @staticmethod + def parse(): + f = sysfs_parser.input_open('/sys/firmware/acpi/tables/MCFG', 'rb') + signature = f.read(4) + if signature != b'MCFG': + raise RuntimeError('MCFG: incorrect input file format %s' % + signature) + (length,) = struct.unpack(' 60: + raise RuntimeError('Multiple MMCONFIG regions found! ' + 'This is not supported') + f.seek(44) + (base, segment, start_bus, end_bus) = \ + struct.unpack(' ourmem[1]): + raise RuntimeError('Your memmap reservation is too small you need >="' + + hex(total) + '". Hint: your kernel cmd line needs ' + '"memmap=' + hex(total) + '$' + hex(ourmem[0]) + '"') + +hvmem[0] = ourmem[0] +mem_regions.append(sysfs_parser.MemRegion(ourmem[0] + hvmem[1], + ourmem[0] + hvmem[1] + inmatemem - 1, + 'JAILHOUSE Inmate Memory')) + +kwargs = { + 'mem_regions': mem_regions, + 'port_regions': port_regions, + 'ourmem': ourmem, + 'argstr': ' '.join(sys.argv), + 'hvmem': hvmem, + 'product': product, + 'pcidevices': pci_devices, + 'pcicaps': pci_caps, + 'cpucount': cpu_count, + 'irqchips': ioapics, + 'pm_timer_base': pm_timer_base, + 'vtd_interrupt_limit': vtd_interrupt_limit, + 'mmconfig': mmconfig, + 'iommu_units': iommu_units, + 'debug_console': debug_console, +} + +tmpl = Template(filename=os.path.join(options.template_dir, + 'root-cell-config.c.tmpl')) + +with open(options.file, 'w') as f: + f.write(tmpl.render(**kwargs)) diff --git a/tools/jailhouse-enable.8.in b/tools/jailhouse-enable.8.in new file mode 100644 index 0000000000000000000000000000000000000000..b2c0fa3e274e38ce46a8234244af63ee767ba147 --- /dev/null +++ b/tools/jailhouse-enable.8.in @@ -0,0 +1,63 @@ +'\" t +.\" Title: jailhouse +.\" Author: [see the "Authors" section] +.\" Date: 14/04/2018 +.\" Manual: Jailhouse Manual +.\" Source: Git 0.8 +.\" Language: English +.\" +.TH "JAILHOUSE-ENABLE" "8" "14/04/2018" "Jailhouse ${VERSION}" "Jailhouse Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +jailhouse-enable \- start the lightweight partitioning hypervisor and wraps the running Linux into the root-cell +.SH "SYNOPSIS" +.sp +.nf +\fIjailhouse enable\fR +.fi +.sp +.SH "DESCRIPTION" +Once the jailhouse\&.ko driver is active in the kernel, Jailhouse has to be enabled: +.sp +.RS +\fIjailhouse enable\fR +.sp + is a Jailhouse binary configuration file that describe all present hardware or the necessary hardware for the root cell to be operational\&. This binary configuration file is obtained by compiling a config file in C language format. On x86, the following command can be used to generate a C language configuration file that represent all known hardware: +.sp +.RS +\fIjailhouse config create\fR +.sp +From this file, the system administrator can remove all hardware that should be dedicated to future cells. Simplest way to compile this file into a is to copy it in and launch a build\&. +.RE +.sp +.RE +.PP +.RE +.SH "SEE ALSO" +jailhouse(8) jailhouse-cell(8) jailhouse.ko(8) +.SH "AUTHORS" +.sp +Jailhouse was started by Jan Kiszka\&. Contributions have come from the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2>\&. +.sp +If you have a clone of jailhouse\&.git itself, the output of \fBgit-shortlog\fR(1) and \fBgit-blame\fR(1) can show you the authors for specific parts of the project\&. +.SH "REPORTING BUGS" +.sp +Report bugs to the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2> where the development and maintenance is primarily done\&. You do not have to be subscribed to the list to send a message there\&. diff --git a/tools/jailhouse-gcov-extract.c b/tools/jailhouse-gcov-extract.c new file mode 100644 index 0000000000000000000000000000000000000000..5bb337a568be22f70ae07b886f8f14f666e11de8 --- /dev/null +++ b/tools/jailhouse-gcov-extract.c @@ -0,0 +1,225 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2017 + * + * Authors: + * Henning Schild + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) +#error "Gcov format of gcc < 4.7 is not supported!" +#endif + +#ifdef __ARM_EABI__ +#define BITS_PER_LONG 32 +#else +#define BITS_PER_LONG 64 +#endif +/* + * the following bits are heavily inspired by linux/kernel/gcov/gcc_4.7.c + * with some slight modification + */ +#if BITS_PER_LONG >= 64 +typedef long gcov_type; +#else +typedef long long gcov_type; +#endif + +#if (__GNUC__ >= 7) +#define GCOV_COUNTERS 9 +#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) +#define GCOV_COUNTERS 10 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 +#define GCOV_COUNTERS 9 +#else +#define GCOV_COUNTERS 8 +#endif + +struct gcov_ctr_info { + unsigned int num; + gcov_type *values; +}; + +struct gcov_fn_info { + struct gcov_info *key; + unsigned int ident; + unsigned int lineno_checksum; + unsigned int cfg_checksum; + struct gcov_ctr_info ctrs[0]; +}; + +struct gcov_info { + unsigned int version; + struct gcov_info *next; + unsigned int stamp; + char *filename; + void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int); + unsigned int n_functions; + struct gcov_fn_info **functions; +}; +/* + * end of linux/kernel/gcov/gcc_4.7.c + */ + +static void *hypervisor; +static ssize_t hypervisor_size; +extern void __gcov_merge_add(gcov_type *counters, unsigned int n_counters); +extern void __gcov_init(struct gcov_info *); +extern void __gcov_dump(); + +static void *hypervisor2current(void *hvp) +{ + unsigned long hvaddr = (unsigned long)hvp; + void *ret; + + if (hvp == NULL) + return NULL; + assert(hvaddr >= JAILHOUSE_BASE && + hvaddr < JAILHOUSE_BASE + (unsigned long)hypervisor_size); + ret = (void *)(hvaddr - JAILHOUSE_BASE + (unsigned long)hypervisor); + + return ret; +} + +/* + * translate one gcov-"tree" from the hypervisor address space to the current + * addresses + */ +static void translate_all_pointers(struct gcov_info *info) +{ + struct gcov_fn_info *fn_info; + struct gcov_ctr_info *ctr_info; + unsigned int i, j, active; + + info->next = hypervisor2current(info->next); + info->filename = hypervisor2current(info->filename); + active = 0; + for (i = 0; i < GCOV_COUNTERS; i++) { + if (info->merge[i]) { + active++; + info->merge[i] = &__gcov_merge_add; + } else + break; + } + info->functions = hypervisor2current(info->functions); + for (i = 0; i < info->n_functions; i++) { + info->functions[i] = hypervisor2current(info->functions[i]); + fn_info = info->functions[i]; + if (fn_info) { + fn_info->key = hypervisor2current(fn_info->key); + assert(fn_info->key == info); + for (j = 0; j < active; j++) { + ctr_info = fn_info->ctrs + j; + ctr_info->values = + hypervisor2current(ctr_info->values); + } + } + } +} + +int main(int argc, char **argv) +{ + struct gcov_info *gcov_info_head, *info, *next; + struct jailhouse_header *header; + struct stat sbuf; + char *filename; + char *errstr = NULL; + ssize_t count, ret; + int fd; + + if (argc == 1) { + filename = "/sys/devices/jailhouse/core"; + } else { + if (argc != 2 || (strncmp(argv[1], "-", 1) == 0)) { + printf("Usage: %s [-h] [FILE]\n", argv[0]); + if (strcmp(argv[1], "-h")) { + errno = EINVAL; + errstr = argv[1]; + } + goto out; + } + filename = argv[1]; + } + fd = open(filename, O_RDONLY); + if (fd < 1) { + errstr = filename; + goto out; + } + + ret = fstat(fd, &sbuf); + if (ret) { + errstr = filename; + goto out; + } + hypervisor_size = sbuf.st_size; + hypervisor = malloc(hypervisor_size); + if (hypervisor == NULL) { + errstr = "malloc"; + goto out_f; + } + + count = 0; + while (count < hypervisor_size) { + ret = read(fd, hypervisor + count, hypervisor_size-count); + if (ret < 0 && errno != EINTR) { + errstr = "read"; + goto out_m; + } + count += ret; + } + assert(count == hypervisor_size); + + header = (struct jailhouse_header *)hypervisor; + if (memcmp(header->signature, JAILHOUSE_SIGNATURE, + sizeof(header->signature))) { + errno = EINVAL; + error(0, 0, "%s does not seem to be a hypervisor image", + filename); + goto out_m; + } + + gcov_info_head = hypervisor2current(header->gcov_info_head); + if (!gcov_info_head) { + errno = EINVAL; + error(0, 0, "%s does not contain gcov information.", filename); + goto out_m; + } + info = gcov_info_head; + for (info = gcov_info_head; info; info = info->next) + translate_all_pointers(info); + + for (info = gcov_info_head; info;) { + /* remember next because __gcov_init changes it */ + next = info->next; + __gcov_init(info); + info = next; + } + __gcov_dump(); + +out_m: + free(hypervisor); +out_f: + close(fd); +out: + if (errno && errstr) + error(errno, errno, "%s", errstr); + return 0; +} diff --git a/tools/jailhouse-hardware-check b/tools/jailhouse-hardware-check new file mode 100755 index 0000000000000000000000000000000000000000..fc8ce4f1884a0411ec5ec7a847150099644d71c1 --- /dev/null +++ b/tools/jailhouse-hardware-check @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 + +# Jailhouse, a Linux-based partitioning hypervisor +# +# Copyright (c) Siemens AG, 2018 +# +# Authors: +# Jan Kiszka +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + +import mmap +import os +import struct +import sys + +# Imports from directory containing this must be done before the following +sys.path[0] = os.path.dirname(os.path.abspath(__file__)) + "/.." +import pyjailhouse.sysfs_parser as sysfs_parser + + +check_passed = True +ran_all = True + + +def check_feature(msg, ok, optional=False): + if not (ok or optional): + global check_passed + check_passed = False + print('%-32s%s' % (msg, 'ok' if ok else + ('missing (optional)' if optional else 'MISSING'))) + return ok + + +def parse_cpuinfo(): + vendor = None + features = None + cpus = 0 + with open('/proc/cpuinfo', 'r') as info: + for line in info: + if not line.strip(): + continue + key, value = line.split(':') + if key.strip() == 'vendor_id': + if not vendor: + vendor = value.strip() + elif vendor != value.strip(): + print('ERROR: Inconsistent vendor string on CPU %d' % cpus, + file=sys.stderr) + sys.exit(2) + cpus += 1 + if key.strip() == 'flags': + if not features: + features = value.strip().split(' ') + elif features != value.strip().split(' '): + print('ERROR: Inconsistent feature set on CPU %d' % cpus, + file=sys.stderr) + sys.exit(2) + return (vendor, features, cpus) + + +class MSR: + IA32_FEATURE_CONTROL = 0x0000003a + IA32_VMX_BASIC = 0x00000480 + IA32_VMX_PINBASED_CTLS = 0x00000481 + IA32_VMX_PROCBASED_CTLS = 0x00000482 + IA32_VMX_EXIT_CTLS = 0x00000483 + IA32_VMX_ENTRY_CTLS = 0x00000484 + IA32_VMX_MISC = 0x00000485 + IA32_VMX_PROCBASED_CTLS2 = 0x0000048b + IA32_VMX_EPT_VPID_CAP = 0x0000048c + IA32_VMX_TRUE_PROCBASED_CTLS = 0x0000048e + + def __init__(self, num_cpus): + self.num_cpus = num_cpus + self.msr = [] + for n in range(self.num_cpus): + self.msr.append(open('/dev/cpu/%d/msr' % n, 'rb', 0)) + + def read(self, index): + try: + self.msr[0].seek(index) + value = struct.unpack('Q', self.msr[0].read(8))[0] + except: + return 0 + + for n in range(1, self.num_cpus): + self.msr[n].seek(index) + if value != struct.unpack('Q', self.msr[n].read(8))[0]: + print('ERROR: Inconsistent value of MSR 0x%x on CPU %d' % + (index, n), file=sys.stderr) + sys.exit(2) + return value + + +class MMIO: + def __init__(self, base, size): + self.mmap = None + try: + f = os.open('/dev/mem', os.O_RDONLY | os.O_SYNC) + self.mmap = mmap.mmap(f, size, mmap.MAP_SHARED, mmap.PROT_READ, + offset=base) + except (PermissionError, OSError, mmap.error): + pass + + def read64(self, offset): + if self.mmap is None: + global ran_all + print(' Skipping MMIO tests, your kernel might have ' + 'CONFIG_STRICT_DEVMEM enabled.\n Disable for thorough ' + 'testing.\n') + ran_all = False + return None + self.mmap.seek(offset) + return struct.unpack('Q', self.mmap.read(8))[0] + + +if os.uname()[4] not in ('x86_64', 'i686'): + print('Unsupported architecture', file=sys.stderr) + sys.exit(1) + + +ioapics = sysfs_parser.parse_madt() +pci_devices = sysfs_parser.parse_pcidevices() + +(cpu_vendor, cpu_features, cpu_count) = parse_cpuinfo() + +print('Feature Availability') +print('------------------------------ ------------------') +check_feature('Number of CPUs > 1', cpu_count > 1) +check_feature('Long mode', 'lm' in cpu_features) + +if cpu_vendor == 'GenuineIntel': + if not os.access('/dev/cpu/0/msr', os.R_OK): + if os.system('/sbin/modprobe msr'): + sys.exit(1) + + msr = MSR(cpu_count) + + _, dmar_regions = sysfs_parser.parse_iomem(pci_devices) + iommu, _ = sysfs_parser.parse_dmar(pci_devices, ioapics, dmar_regions) + + check_feature('x2APIC', 'x2apic' in cpu_features, True) + print() + check_feature('VT-x (VMX)', 'vmx' in cpu_features) + + feature = msr.read(MSR.IA32_FEATURE_CONTROL) + check_feature(' VMX outside SMX', feature & (1 << 2)) + check_feature(' VMX inside SMX', feature & (1 << 1), True) + check_feature(' IA32_TRUE_*_CLTS', + msr.read(MSR.IA32_VMX_BASIC) & (1 << 55)) + + pinbased = msr.read(MSR.IA32_VMX_PINBASED_CTLS) >> 32 + check_feature(' NMI exiting', pinbased & (1 << 3)) + check_feature(' Preemption timer', pinbased & (1 << 6)) + + procbased = msr.read(MSR.IA32_VMX_PROCBASED_CTLS) >> 32 + check_feature(' I/O bitmap', procbased & (1 << 25)) + check_feature(' MSR bitmap', procbased & (1 << 28)) + check_feature(' Secondary controls', procbased & (1 << 31)) + check_feature(' Optional CR3 interception', + (msr.read(MSR.IA32_VMX_TRUE_PROCBASED_CTLS) & + (3 << 15)) == 0) + + procbased2 = msr.read(MSR.IA32_VMX_PROCBASED_CTLS2) >> 32 + check_feature(' Virtualize APIC access', procbased2 & (1 << 0)) + check_feature(' RDTSCP', procbased2 & (1 << 3), + 'rdtscp' not in cpu_features) + check_feature(' Unrestricted guest', procbased2 & (1 << 7)) + check_feature(' INVPCID', procbased2 & (1 << 12), + 'invpcid' not in cpu_features) + check_feature(' XSAVES', procbased2 & (1 << 20), + 'xsaves' not in cpu_features) + + check_feature(' EPT', procbased2 & (1 << 1)) + ept_cap = msr.read(MSR.IA32_VMX_EPT_VPID_CAP) + check_feature(' 4-level page walk', ept_cap & (1 << 6)) + check_feature(' EPTP write-back', ept_cap & (1 << 14)) + check_feature(' 2M pages', ept_cap & (1 << 16), True) + check_feature(' 1G pages', ept_cap & (1 << 17), True) + check_feature(' INVEPT', ept_cap & (1 << 20)) + check_feature(' Single or all-context', ept_cap & (3 << 25)) + + vmexit = msr.read(MSR.IA32_VMX_EXIT_CTLS) >> 32 + check_feature(' VM-exit save IA32_PAT', vmexit & (1 << 18)) + check_feature(' VM-exit load IA32_PAT', vmexit & (1 << 19)) + check_feature(' VM-exit save IA32_EFER', vmexit & (1 << 20)) + check_feature(' VM-exit load IA32_EFER', vmexit & (1 << 21)) + + vmentry = msr.read(MSR.IA32_VMX_ENTRY_CTLS) >> 32 + check_feature(' VM-entry load IA32_PAT', vmentry & (1 << 14)) + check_feature(' VM-entry load IA32_EFER', vmentry & (1 << 15)) + check_feature(' Activity state HLT', + msr.read(MSR.IA32_VMX_MISC) & (1 << 6)) + + for n in range(len(iommu)): + if iommu[n].base_addr == 0 and n > 0: + break + print() + check_feature('VT-d (IOMMU #%d)' % n, iommu[n].base_addr) + if iommu[n].base_addr == 0: + break + mmio = MMIO(iommu[n].base_addr, iommu[n].mmio_size) + cap = mmio.read64(0x08) + if cap is None: + continue + check_feature(' 39-bit AGAW', cap & (1 << 9), cap & (1 << 10)) + check_feature(' 48-bit AGAW', cap & (1 << 10), cap & (1 << 9)) + check_feature(' 2M pages', cap & (1 << 34), True) + check_feature(' 1G pages', cap & (1 << 35), True) + ecap = mmio.read64(0x10) + check_feature(' Queued invalidation', ecap & (1 << 1)) + check_feature(' Interrupt remapping', ecap & (1 << 3)) + check_feature(' Extended interrupt mode', ecap & (1 << 4), + 'x2apic' not in cpu_features) + +elif cpu_vendor == 'AuthenticAMD': + iommu, _ = sysfs_parser.parse_ivrs(pci_devices, ioapics) + + print() + check_feature('AMD-V (SVM)', 'svm' in cpu_features) + check_feature(' NPT', 'npt' in cpu_features) + check_feature(' Decode assist', 'decodeassists' in cpu_features, True) + check_feature(' AVIC', 'avic' in cpu_features, True) + check_feature(' Flush by ASID', 'flushbyasid' in cpu_features, True) + + for n in range(len(iommu)): + if iommu[n].base_addr == 0 and n > 0: + break + print() + check_feature('AMD-Vi (IOMMU #%d)' % n, iommu[n].base_addr) + if iommu[n].base_addr == 0: + break + + bdf = iommu[n].amd_bdf + path = '/sys/bus/pci/devices/0000:%02x:%02x.%x/config' % \ + (bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x7) + with open(path, 'rb') as config: + config.seek(iommu[n].amd_base_cap) + (caps, base) = struct.unpack('QQ', config.read(16)) + + check_feature(' Extended feature register', caps & (1 << 27)) + check_feature(' Valid base register', + (base & (1 << 0)) == 0 or + base == (iommu[n].base_addr | (1 << 0))) + + mmio = MMIO(iommu[n].base_addr, iommu[n].mmio_size) + efr = mmio.read64(0x30) + if efr is not None and \ + check_feature(' SMI filter', ((efr >> 16) & 0x3) == 1): + smi_filter_ok = True + num_filter_regs = 1 << ((efr >> 18) & 7) + for reg in range(num_filter_regs): + smi_freg = mmio.read64(0x60 + reg * 8) + # must not be locked AND set to match against specific device + if smi_freg & (1 << 17) and smi_freg & (1 << 16): + smi_filter_ok = False + check_feature(' Valid filter registers', smi_filter_ok) + + he_feature = iommu[n].amd_features + if he_feature == 0 and efr: + he_feature = efr + check_feature(' Hardware events', he_feature & (1 << 8), True) + +else: + print('Unsupported CPU', file=sys.stderr) + +print('\nCheck %s!' % ('passed' if check_passed else 'FAILED')) +if not ran_all: + print('BUT: Some essential checks had to be skipped!\n') + sys.exit(1) +sys.exit(0 if check_passed else 2) diff --git a/tools/jailhouse.8.in b/tools/jailhouse.8.in new file mode 100644 index 0000000000000000000000000000000000000000..f9daff9ed3f9a6f32975b68a4ae76ec72f8f461f --- /dev/null +++ b/tools/jailhouse.8.in @@ -0,0 +1,93 @@ +'\" t +.\" Title: jailhouse +.\" Author: [see the "Authors" section] +.\" Date: 14/04/2018 +.\" Manual: Jailhouse Manual +.\" Source: Git 0.8 +.\" Language: English +.\" +.TH "JAILHOUSE" "8" "14/04/2018" "Jailhouse ${VERSION}" "Jailhouse Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +jailhouse \- the lightweight partitioning hypervisor +.SH "SYNOPSIS" +.sp +.nf +\fIjailhouse\fR [] +.fi +.sp +.SH "DESCRIPTION" +.sp +Jailhouse is a partitioning Hypervisor based on Linux\&. It is able to run bare-metal applications or (adapted) operating systems besides Linux\&. For this purpose, it configures CPU and device virtualization features of the hardware platform in a way that none of these domains, called "cells" here, can interfere with each other in an unacceptable way\&. +.sp +Jailhouse is optimized for simplicity rather than feature richness\&. Unlike full-featured Linux-based hypervisors like KVM or Xen, Jailhouse does not support overcommitment of resources like CPUs, RAM or devices\&. It performs no scheduling and only virtualizes those resources in software, that are essential for a platform and cannot be partitioned in hardware\&. +.sp +Once Jailhouse is activated, it runs bare-metal, i\&.e\&. it takes full control over the hardware and needs no external support\&. However, in contrast to other bare-metal hypervisors, it is loaded and configured by a normal Linux system\&. Its management interface is based on Linux infrastructure\&. So you boot Linux first, then you enable Jailhouse and finally you split off parts of the system's resources and assign them to additional cells\&. +.SH "USAGE FLOW" +.sp +Once the jailhouse\&.ko driver is active in the kernel, Jailhouse has to be enabled with the following command: +.sp +.RS +\fIjailhouse enable\fR +.sp +This activates the hypervisor and wraps the executing Linux execution environment into a cell called the "root cell"\&. It is then possible to create and tear down cells with jailhouse cell commands\&. is a Jailhouse binary configuration file that describe all present hardware but the hardware devices destined to future cells\&. +.sp +.RE +Jailhouse enabled, then it is possible to create and terminate cells with the following set of commands: +.sp +.RS 4 +.nf +\fIjailhouse cell create\fR -name +\fIjailhouse cell load\fR -name +\fIjailhouse cell start\fR -name +\fIjailhouse cell destroy\fR -name +.fi +.RE +.sp +To terminate jailhouse alltogether, all cells must be destroyed and then hypervisor itself terminated with: +.sp +.RS +\fIjailhouse disable\fR +.sp +This unwraps the root cell into a bare metal environment\&. The jalhouse\&.ko driver can be unloaded once Jailhouse has been disabled\&. +.RE +.SH "JAILHOUSE COMMANDS" +.sp +.PP +\fBjailhouse-cell\fR(8) +.PP +\fBjailhouse-console\fR(8) +.PP +\fBjailhouse-disable\fR(8) +.PP +\fBjailhouse-enable\fR(8) +.PP +\fBjailhouse-hardware\fR(8) +.SH "SEE ALSO" +jailhouse-cell(8) jailhouse-enable(8) jailhouse.ko(8) +.SH "AUTHORS" +.sp +Jailhouse was started by Jan Kiszka\&. Contributions have come from the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2>\&. +.sp +If you have a clone of jailhouse\&.git itself, the output of \fBgit-shortlog\fR(1) and \fBgit-blame\fR(1) can show you the authors for specific parts of the project\&. +.SH "REPORTING BUGS" +.sp +Report bugs to the Jailhouse mailing list <\m[blue]\fBjailhouse\-dev@googlegroups\&.com\fR\m[]\&\s-2\u\d\s+2> where the development and maintenance is primarily done\&. You do not have to be subscribed to the list to send a message there\&. diff --git a/tools/jailhouse.c b/tools/jailhouse.c new file mode 100644 index 0000000000000000000000000000000000000000..215d239b96768ba01f84b35dd3daefe88116fcb9 --- /dev/null +++ b/tools/jailhouse.c @@ -0,0 +1,590 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2013-2016 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define JAILHOUSE_EXEC_DIR LIBEXECDIR "/jailhouse" +#define JAILHOUSE_DEVICE "/dev/jailhouse" +#define JAILHOUSE_CELLS "/sys/devices/jailhouse/cells/" + +enum shutdown_load_mode {LOAD, SHUTDOWN}; + +struct extension { + char *cmd, *subcmd, *help; +}; + +struct jailhouse_cell_info { + struct jailhouse_cell_id id; + char *state; + char *cpus_assigned_list; + char *cpus_failed_list; +}; + +static const struct extension extensions[] = { + { "cell", "linux", "[-h] [-d DTB] [-i INITRD] [-c \"CMDLINE\"]" + " [-w PARAMS_FILE]\n" + " [-a ARCH] [-k FACTOR]\n" + " CELLCONFIG KERNEL" }, + { "cell", "stats", "{ ID | [--name] NAME }" }, + { "config", "create", "[-h] [-g] [-r ROOT] [-t TEMPLATE_DIR]" + " [-c CONSOLE]\n" + " [--mem-inmates MEM_INMATES] [--mem-hv MEM_HV]\n" + " FILE" }, + { "config", "collect", "FILE.TAR" }, + { "config", "check", "[-h] SYSCONFIG [CELLCONFIG [CELLCONFIG ...]]" }, + { "hardware", "check", "" }, + { NULL } +}; + +static void __attribute__((noreturn)) help(char *prog, int exit_status) +{ + const struct extension *ext; + + printf("Usage: %s { COMMAND | --help | --version }\n" + "\nAvailable commands:\n" + " enable SYSCONFIG\n" + " disable\n" + " console [-f | --follow]\n" + " cell create CELLCONFIG\n" + " cell list\n" + " cell load { ID | [--name] NAME } " + "{ IMAGE | { -s | --string } \"STRING\" }\n" + " [-a | --address ADDRESS] ...\n" + " cell start { ID | [--name] NAME }\n" + " cell shutdown { ID | [--name] NAME }\n" + " cell destroy { ID | [--name] NAME }\n", + basename(prog)); + for (ext = extensions; ext->cmd; ext++) + printf(" %s %s %s\n", ext->cmd, ext->subcmd, ext->help); + + exit(exit_status); +} + +static void call_extension_script(const char *cmd, int argc, char *argv[]) +{ + const struct extension *ext; + char new_path[PATH_MAX]; + char script[64]; + + if (argc < 3) + return; + + for (ext = extensions; ext->cmd; ext++) { + if (strcmp(ext->cmd, cmd) != 0 || + strcmp(ext->subcmd, argv[2]) != 0) + continue; + + snprintf(new_path, sizeof(new_path), "PATH=%s:%s:%s", + dirname(argv[0]), JAILHOUSE_EXEC_DIR, + getenv("PATH") ? : ""); + putenv(new_path); + + snprintf(script, sizeof(script), "jailhouse-%s-%s", + cmd, ext->subcmd); + execvp(script, &argv[2]); + + perror("execvp"); + exit(1); + } +} + +static int open_dev() +{ + int fd; + + fd = open(JAILHOUSE_DEVICE, O_RDWR); + if (fd < 0) { + perror("opening " JAILHOUSE_DEVICE); + exit(1); + } + return fd; +} + +static void *read_string(const char *string, size_t *size) +{ + void *buffer; + + *size = strlen(string) + 1; + + buffer = strdup(string); + if (!buffer) { + fprintf(stderr, "insufficient memory\n"); + exit(1); + } + + return buffer; +} + +static void *read_file(const char *name, size_t *size) +{ + struct stat stat; + ssize_t result; + void *buffer; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "opening %s: %s\n", name, strerror(errno)); + exit(1); + } + + if (fstat(fd, &stat) < 0) { + perror("fstat"); + exit(1); + } + + buffer = malloc(stat.st_size); + if (!buffer) { + fprintf(stderr, "insufficient memory\n"); + exit(1); + } + + result = read(fd, buffer, stat.st_size); + if (result < 0) { + fprintf(stderr, "reading %s: %s\n", name, strerror(errno)); + exit(1); + } + + close(fd); + + if (size) + *size = (size_t)result; + + return buffer; +} + +static char *read_sysfs_cell_string(const unsigned int id, const char *entry) +{ + char *ret, buffer[128]; + size_t size; + + snprintf(buffer, sizeof(buffer), JAILHOUSE_CELLS "%u/%s", id, entry); + ret = read_file(buffer, &size); + + /* entries in /sys/devices/jailhouse/cells must not be empty */ + if (size == 0) { + snprintf(buffer, sizeof(buffer), + "reading " JAILHOUSE_CELLS "%u/%s", id, entry); + perror(buffer); + exit(1); + } + + /* chop trailing linefeeds and enforce the string to be + * null-terminated */ + if (ret[size-1] != '\n') { + ret = realloc(ret, ++size); + if (ret == NULL) { + fprintf(stderr, "insufficient memory\n"); + exit(1); + } + } + ret[size-1] = 0; + + return ret; +} + +static int enable(int argc, char *argv[]) +{ + void *config; + int err, fd; + + if (argc != 3) + help(argv[0], 1); + + config = read_file(argv[2], NULL); + + fd = open_dev(); + + err = ioctl(fd, JAILHOUSE_ENABLE, config); + if (err) + perror("JAILHOUSE_ENABLE"); + + close(fd); + free(config); + + return err; +} + +static int cell_create(int argc, char *argv[]) +{ + struct jailhouse_cell_create cell_create; + size_t size; + int err, fd; + + if (argc != 4) + help(argv[0], 1); + + cell_create.config_address = (unsigned long)read_file(argv[3], &size); + cell_create.config_size = size; + + fd = open_dev(); + + err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create); + if (err) + perror("JAILHOUSE_CELL_CREATE"); + + close(fd); + free((void *)(unsigned long)cell_create.config_address); + + return err; +} + +static int parse_cell_id(struct jailhouse_cell_id *cell_id, int argc, + char *argv[]) +{ + bool use_name = false; + int arg_pos = 0; + char *endp; + + memset(cell_id, 0, sizeof(*cell_id)); + + if (argc < 1) + return 0; + + if (strcmp(argv[0], "--name") == 0) { + if (argc < 2) + return 0; + arg_pos++; + use_name = true; + } else { + errno = 0; + cell_id->id = strtoll(argv[0], &endp, 0); + if (errno != 0 || *endp != 0 || cell_id->id < 0) + use_name = true; + } + + if (use_name) { + cell_id->id = JAILHOUSE_CELL_ID_UNUSED; + /* cell_id is initialized with zeros, so leaving out the last + * byte ensures that the string is always terminated. */ + strncpy(cell_id->name, argv[arg_pos], + sizeof(cell_id->name) - 1); + } + + return arg_pos + 1; +} + +static bool match_opt(const char *argv, const char *short_opt, + const char *long_opt) +{ + return strcmp(argv, short_opt) == 0 || + strcmp(argv, long_opt) == 0; +} + +static struct jailhouse_cell_info *get_cell_info(const unsigned int id) +{ + struct jailhouse_cell_info *cinfo; + char *tmp; + + cinfo = malloc(sizeof(struct jailhouse_cell_info)); + if (cinfo == NULL) { + fprintf(stderr, "insufficient memory\n"); + exit(1); + } + + /* set cell id */ + cinfo->id.id = id; + + /* get cell name */ + tmp = read_sysfs_cell_string(id, "name"); + strncpy(cinfo->id.name, tmp, JAILHOUSE_CELL_ID_NAMELEN); + cinfo->id.name[JAILHOUSE_CELL_ID_NAMELEN] = 0; + free(tmp); + + /* get cell state */ + cinfo->state = read_sysfs_cell_string(id, "state"); + + /* get assigned cpu list */ + cinfo->cpus_assigned_list = + read_sysfs_cell_string(id, "cpus_assigned_list"); + + /* get failed cpu list */ + cinfo->cpus_failed_list = read_sysfs_cell_string(id, "cpus_failed_list"); + + return cinfo; +} + +static void cell_info_free(struct jailhouse_cell_info *cinfo) +{ + free(cinfo->state); + free(cinfo->cpus_assigned_list); + free(cinfo->cpus_failed_list); + free(cinfo); +} + +static int cell_match(const struct dirent *dirent) +{ + return dirent->d_name[0] != '.'; +} + +static int cell_list(int argc, char *argv[]) +{ + struct dirent **namelist; + struct jailhouse_cell_info *cinfo; + unsigned int id; + int i, num_entries; + (void)argv; + + if (argc != 3) + help(argv[0], 1); + + num_entries = scandir(JAILHOUSE_CELLS, &namelist, cell_match, alphasort); + if (num_entries == -1) { + /* Silently return if kernel module is not loaded */ + if (errno == ENOENT) + return 0; + + perror("scandir"); + return -1; + } + + if (num_entries > 0) + printf("%-8s%-24s%-18s%-24s%-24s\n", + "ID", "Name", "State", "Assigned CPUs", "Failed CPUs"); + for (i = 0; i < num_entries; i++) { + id = (unsigned int)strtoul(namelist[i]->d_name, NULL, 10); + + cinfo = get_cell_info(id); + printf("%-8d%-24s%-18s%-24s%-24s\n", cinfo->id.id, cinfo->id.name, + cinfo->state, cinfo->cpus_assigned_list, cinfo->cpus_failed_list); + cell_info_free(cinfo); + free(namelist[i]); + } + + free(namelist); + return 0; +} + +static int cell_shutdown_load(int argc, char *argv[], + enum shutdown_load_mode mode) +{ + struct jailhouse_preload_image *image; + struct jailhouse_cell_load *cell_load; + struct jailhouse_cell_id cell_id; + int err, fd, id_args, arg_num; + unsigned int images, n; + size_t size; + char *endp; + + id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]); + arg_num = 3 + id_args; + if (id_args == 0 || (mode == SHUTDOWN && arg_num != argc) || + (mode == LOAD && arg_num == argc)) + help(argv[0], 1); + + images = 0; + while (arg_num < argc) { + if (match_opt(argv[arg_num], "-s", "--string")) { + if (arg_num + 1 >= argc) + help(argv[0], 1); + arg_num++; + } + + images++; + arg_num++; + + if (arg_num < argc && + match_opt(argv[arg_num], "-a", "--address")) { + if (arg_num + 1 >= argc) + help(argv[0], 1); + arg_num += 2; + } + } + + cell_load = malloc(sizeof(*cell_load) + sizeof(*image) * images); + if (!cell_load) { + fprintf(stderr, "insufficient memory\n"); + exit(1); + } + cell_load->cell_id = cell_id; + cell_load->num_preload_images = images; + + arg_num = 3 + id_args; + + for (n = 0, image = cell_load->image; n < images; n++, image++) { + if (match_opt(argv[arg_num], "-s", "--string")) { + arg_num++; + image->source_address = + (unsigned long)read_string(argv[arg_num++], + &size); + } else { + image->source_address = + (unsigned long)read_file(argv[arg_num++], + &size); + } + image->size = size; + image->target_address = 0; + + if (arg_num < argc && + match_opt(argv[arg_num], "-a", "--address")) { + errno = 0; + image->target_address = + strtoll(argv[arg_num + 1], &endp, 0); + if (errno != 0 || *endp != 0) + help(argv[0], 1); + arg_num += 2; + } + } + + fd = open_dev(); + + err = ioctl(fd, JAILHOUSE_CELL_LOAD, cell_load); + if (err) + perror("JAILHOUSE_CELL_LOAD"); + + close(fd); + for (n = 0, image = cell_load->image; n < images; n++, image++) + free((void *)(unsigned long)image->source_address); + free(cell_load); + + return err; +} + +static int cell_simple_cmd(int argc, char *argv[], unsigned int command) +{ + struct jailhouse_cell_id cell_id; + int id_args, err, fd; + + id_args = parse_cell_id(&cell_id, argc - 3, &argv[3]); + if (id_args == 0 || 3 + id_args != argc) + help(argv[0], 1); + + fd = open_dev(); + + err = ioctl(fd, command, &cell_id); + if (err) + perror(command == JAILHOUSE_CELL_START ? + "JAILHOUSE_CELL_START" : + command == JAILHOUSE_CELL_DESTROY ? + "JAILHOUSE_CELL_DESTROY" : + ""); + + close(fd); + + return err; +} + +static int cell_management(int argc, char *argv[]) +{ + int err; + + if (argc < 3) + help(argv[0], 1); + + if (strcmp(argv[2], "create") == 0) { + err = cell_create(argc, argv); + } else if (strcmp(argv[2], "list") == 0) { + err = cell_list(argc, argv); + } else if (strcmp(argv[2], "load") == 0) { + err = cell_shutdown_load(argc, argv, LOAD); + } else if (strcmp(argv[2], "start") == 0) { + err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_START); + } else if (strcmp(argv[2], "shutdown") == 0) { + err = cell_shutdown_load(argc, argv, SHUTDOWN); + } else if (strcmp(argv[2], "destroy") == 0) { + err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_DESTROY); + } else { + call_extension_script("cell", argc, argv); + help(argv[0], 1); + } + + return err; +} + +static int console(int argc, char *argv[]) +{ + bool non_block = true; + char buffer[128]; + ssize_t ret; + int fd; + + if (argc == 3) { + if (match_opt(argv[2], "-f", "--follow")) + non_block = false; + else + help(argv[0], 1); + } + + fd = open_dev(); + + if (non_block) { + ret = fcntl(fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + perror("fcntl(set O_NONBLOCK)"); + goto out; + } + } + + do { + ret = read(fd, buffer, sizeof(buffer)); + if (ret < 0) { + perror("read(console)"); + break; + } + ret = write(STDOUT_FILENO, buffer, ret); + } while (ret > 0); + +out: + close(fd); + + return ret; +} + +int main(int argc, char *argv[]) +{ + int fd; + int err; + + if (argc < 2) + help(argv[0], 1); + + if (strcmp(argv[1], "enable") == 0) { + err = enable(argc, argv); + } else if (strcmp(argv[1], "disable") == 0) { + fd = open_dev(); + err = ioctl(fd, JAILHOUSE_DISABLE); + if (err) + perror("JAILHOUSE_DISABLE"); + close(fd); + } else if (strcmp(argv[1], "cell") == 0) { + err = cell_management(argc, argv); + } else if (strcmp(argv[1], "console") == 0) { + err = console(argc, argv); + } else if (strcmp(argv[1], "config") == 0 || + strcmp(argv[1], "hardware") == 0) { + call_extension_script(argv[1], argc, argv); + help(argv[0], 1); + } else if (strcmp(argv[1], "--version") == 0) { + printf("Jailhouse management tool %s\n", JAILHOUSE_VERSION); + return 0; + } else if (strcmp(argv[1], "--help") == 0) { + help(argv[0], 0); + } else { + help(argv[0], 1); + } + + return err ? 1 : 0; +} diff --git a/tools/root-cell-config.c.tmpl b/tools/root-cell-config.c.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..c28fcfa489a109efbf6fdf837cf7c22f16e59be9 --- /dev/null +++ b/tools/root-cell-config.c.tmpl @@ -0,0 +1,202 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014-2017 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Alternatively, you can use or redistribute this file under the following + * BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 HOLDER 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. + * + * Configuration for ${product[0]} ${product[1]} + * created with '${argstr}' + * + * NOTE: This config expects the following to be appended to your kernel cmdline + * "memmap=${hex(ourmem[1])}$${hex(ourmem[0])}" + */ + +#include +#include + +struct { + struct jailhouse_system header; + __u64 cpus[${int((cpucount + 63) / 64)}]; + struct jailhouse_memory mem_regions[${len(mem_regions)}]; + struct jailhouse_irqchip irqchips[${len(irqchips)}]; + struct jailhouse_pio pio_regions[${len([1 for r in port_regions if r.permit])}]; + struct jailhouse_pci_device pci_devices[${len(pcidevices)}]; + struct jailhouse_pci_capability pci_caps[${len(pcicaps)}]; +} __attribute__((packed)) config = { + .header = { + .signature = JAILHOUSE_SYSTEM_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE, + .hypervisor_memory = { + .phys_start = ${hex(hvmem[0])}, + .size = ${hex(hvmem[1])}, + }, + .debug_console = { + % if debug_console.address != 0: + .address = ${hex(debug_console.address)}, + .type = JAILHOUSE_CON_TYPE_8250, + % if not debug_console.pio: + .size = 0x1000, + % endif + % if debug_console.pio: + .flags = JAILHOUSE_CON_ACCESS_PIO | + % else: + .flags = JAILHOUSE_CON_ACCESS_MMIO | + % endif + % if debug_console.dist1: + JAILHOUSE_CON_REGDIST_1, + % else: + JAILHOUSE_CON_REGDIST_4, + % endif + % else: + .type = JAILHOUSE_CON_TYPE_NONE, + % endif + }, + .platform_info = { + .pci_mmconfig_base = ${hex(mmconfig.base)}, + .pci_mmconfig_end_bus = ${hex(mmconfig.end_bus)}, + % if iommu_units: + .iommu_units = { + % for unit in iommu_units: + { + .type = ${unit.type}, + .base = ${hex(unit.base_addr)}, + .size = ${hex(unit.mmio_size)}, + % if unit.is_amd_iommu: + .amd.bdf = ${hex(unit.amd_bdf)}, + .amd.base_cap = ${hex(unit.amd_base_cap)}, + .amd.msi_cap = ${hex(unit.amd_msi_cap)}, + .amd.features = ${hex(unit.amd_features)}, + % endif + }, + % endfor + }, + % endif + .x86 = { + .pm_timer_address = ${hex(pm_timer_base)}, + .vtd_interrupt_limit = ${int(vtd_interrupt_limit)}, + }, + }, + .root_cell = { + .name = "RootCell", + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pio_regions = ARRAY_SIZE(config.pio_regions), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .num_pci_caps = ARRAY_SIZE(config.pci_caps), + }, + }, + + .cpus = { + % for n in range(int(cpucount / 64)): + 0xffffffffffffffff, + % endfor + % if (cpucount % 64): + ${'0x%016x,' % ((1 << (cpucount % 64)) - 1)} + % endif + }, + + .mem_regions = { + % for r in mem_regions: + /* ${str(r)} */ + % for c in r.comments: + /* ${c} */ + % endfor + { + .phys_start = ${r.start_str()}, + .virt_start = ${r.start_str()}, + .size = ${r.size_str()}, + .flags = ${r.flagstr('\t\t')}, + }, + % endfor + }, + + .irqchips = { + % for i in irqchips: + /* ${str(i)} */ + { + .address = ${hex(i.address)}, + .id = ${hex(i.irqchip_id())}, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }, + }, + % endfor + }, + + .pio_regions = { + % for r in port_regions: + /* ${str(r)} */ + ${'' if r.permit else '/* '}PIO_RANGE(${r.start_str()}, ${r.size_str()}),${'' if r.permit else ' */'} + % endfor + }, + + .pci_devices = { + % for d in pcidevices: + /* ${str(d)} */ + { + .type = ${d.type}, + % if d.iommu is not None: + .iommu = ${d.iommu}, + % endif + .domain = ${hex(d.domain)}, + .bdf = ${hex(d.bdf())}, + .bar_mask = { + ${'0x%08x' % d.bars.mask[0]}, ${'0x%08x' % d.bars.mask[1]}, ${'0x%08x' % d.bars.mask[2]}, + ${'0x%08x' % d.bars.mask[3]}, ${'0x%08x' % d.bars.mask[4]}, ${'0x%08x' % d.bars.mask[5]}, + }, + .caps_start = ${d.caps_start}, + .num_caps = ${d.num_caps}, + .num_msi_vectors = ${d.num_msi_vectors}, + .msi_64bits = ${d.msi_64bits}, + .msi_maskable = ${d.msi_maskable}, + .num_msix_vectors = ${d.num_msix_vectors}, + .msix_region_size = ${hex(d.msix_region_size)}, + .msix_address = ${hex(d.msix_address).strip('L')}, + }, + % endfor + }, + + .pci_caps = { + % for c in pcicaps: + % for comment in c.comments: + /* ${comment} */ + % endfor + { + .id = ${c.gen_id_str()}, + .start = ${hex(c.start)}, + .len = ${hex(c.len)}, + .flags = ${c.flags}, + }, + % endfor + }, +};