From 97da642960ac4719504db4d7f3811bf119243a00 Mon Sep 17 00:00:00 2001 From: Kevin Broch Date: Mon, 3 Jun 2024 11:34:26 -0700 Subject: [PATCH 1/5] update spec to use latest docs-spec-template features no spec content changes, just long list of workflow/infra change: * update Makefile (src/build dir; html output;) * update docs-resources to lastest commit * adoc attributes * include global attributes from docs-resources * fix others to reflect src/build * move spec files to src dir * update github actions to latest * install pre-commit (config file and github action) * update README.adoc * add MAINTAINERS, CONTRIBUTING, CODE_OF_CONDUCT files relates to #340 Signed-off-by: Kevin Broch --- .github/workflows/build-pdf.yml | 100 ++++---- .github/workflows/pre-commit.yml | 15 ++ .gitignore | 5 +- .pre-commit-config.yaml | 25 ++ CODE_OF_CONDUCT.md | 3 + CONTRIBUTING.md | 59 +++++ GOVERNANCE.md | 9 + LICENSE | 3 +- MAINTAINERS.md | 7 + Makefile | 58 +++-- README.adoc | 109 ++++++++ dependencies/README.md | 3 +- dependencies/package.json | 6 +- docs-resources | 2 +- images/risc-v_logo.svg | 1 - iommu_ref_model/README.md | 47 ++-- iommu_ref_model/libiommu/Makefile | 2 +- iommu_ref_model/libiommu/include/iommu_atc.h | 15 +- iommu_ref_model/libiommu/include/iommu_ats.h | 18 +- .../libiommu/include/iommu_command_queue.h | 3 +- .../libiommu/include/iommu_data_structures.h | 38 +-- .../libiommu/include/iommu_fault.h | 4 +- iommu_ref_model/libiommu/include/iommu_hpm.h | 2 +- .../libiommu/include/iommu_ref_api.h | 4 +- .../libiommu/include/iommu_registers.h | 212 ++++++++-------- .../libiommu/include/iommu_req_rsp.h | 22 +- .../libiommu/include/iommu_translate.h | 18 +- iommu_ref_model/libiommu/src/iommu_atc.c | 28 +-- iommu_ref_model/libiommu/src/iommu_ats.c | 109 ++++---- .../libiommu/src/iommu_command_queue.c | 230 ++++++++--------- .../libiommu/src/iommu_device_context.c | 32 +-- iommu_ref_model/libiommu/src/iommu_faults.c | 44 ++-- iommu_ref_model/libiommu/src/iommu_hpm.c | 62 ++--- .../libiommu/src/iommu_interrupt.c | 44 ++-- .../libiommu/src/iommu_msi_trans.c | 14 +- .../libiommu/src/iommu_process_context.c | 26 +- iommu_ref_model/libiommu/src/iommu_reg.c | 238 +++++++++--------- .../libiommu/src/iommu_second_stage_trans.c | 96 +++---- .../libiommu/src/iommu_translate.c | 114 ++++----- .../libiommu/src/iommu_two_stage_trans.c | 126 +++++----- iommu_ref_model/libtables/src/build_ddt.c | 4 +- iommu_ref_model/test/tbapi.c | 34 +-- iommu_ref_model/test/test_app.c | 226 ++++++++--------- iommu_ref_model/test/test_app.h | 8 +- iommu_ref_model/test/test_utils.c | 54 ++-- readme.adoc | 38 --- bibliography.adoc => src/bibliography.adoc | 0 contributors.adoc => src/contributors.adoc | 0 {images => src/images}/ddt-base.svg | 2 +- {images => src/images}/ddt-ext.svg | 2 +- {images => src/images}/guest-OS.svg | 2 +- {images => src/images}/hypervisor.svg | 2 +- {images => src/images}/interfaces.svg | 2 +- {images => src/images}/msi-imsic.svg | 2 +- {images => src/images}/non-virt-OS.svg | 2 +- {images => src/images}/pdt.svg | 2 +- {images => src/images}/placement.svg | 2 +- index.adoc => src/index.adoc | 0 iommu.bib => src/iommu.bib | 0 .../iommu_data_structures.adoc | 2 +- iommu_debug.adoc => src/iommu_debug.adoc | 0 .../iommu_hw_guidelines.adoc | 1 - .../iommu_in_memory_queues.adoc | 0 iommu_intro.adoc => src/iommu_intro.adoc | 5 +- .../iommu_registers.adoc | 4 +- .../iommu_sw_guidelines.adoc | 6 +- header.adoc => src/riscv-iommu.adoc | 35 ++- 67 files changed, 1312 insertions(+), 1076 deletions(-) create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .pre-commit-config.yaml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 GOVERNANCE.md create mode 100644 MAINTAINERS.md create mode 100644 README.adoc delete mode 120000 images/risc-v_logo.svg delete mode 100644 readme.adoc rename bibliography.adoc => src/bibliography.adoc (100%) rename contributors.adoc => src/contributors.adoc (100%) rename {images => src/images}/ddt-base.svg (99%) rename {images => src/images}/ddt-ext.svg (99%) rename {images => src/images}/guest-OS.svg (99%) rename {images => src/images}/hypervisor.svg (99%) rename {images => src/images}/interfaces.svg (99%) rename {images => src/images}/msi-imsic.svg (99%) rename {images => src/images}/non-virt-OS.svg (99%) rename {images => src/images}/pdt.svg (99%) rename {images => src/images}/placement.svg (99%) rename index.adoc => src/index.adoc (100%) rename iommu.bib => src/iommu.bib (100%) rename iommu_data_structures.adoc => src/iommu_data_structures.adoc (99%) rename iommu_debug.adoc => src/iommu_debug.adoc (100%) rename iommu_hw_guidelines.adoc => src/iommu_hw_guidelines.adoc (99%) rename iommu_in_memory_queues.adoc => src/iommu_in_memory_queues.adoc (100%) rename iommu_intro.adoc => src/iommu_intro.adoc (99%) rename iommu_registers.adoc => src/iommu_registers.adoc (99%) rename iommu_sw_guidelines.adoc => src/iommu_sw_guidelines.adoc (99%) rename header.adoc => src/riscv-iommu.adoc (66%) diff --git a/.github/workflows/build-pdf.yml b/.github/workflows/build-pdf.yml index 57cc750a..ad46db4c 100644 --- a/.github/workflows/build-pdf.yml +++ b/.github/workflows/build-pdf.yml @@ -1,25 +1,27 @@ +--- name: Create Specification Document # The workflow is triggered by pull request, push to main, and manual dispatch. on: workflow_dispatch: inputs: - version: - description: 'Release version, e.g. X.Y.Z:' + revision_mark: + description: "Set revision mark as Draft, Release or Stable:" required: true - type: string - revision_mark: - description: 'Set revision mark as Draft, Release or Stable:' - required: true - type: string - default: 'Draft' + type: choice + options: + - Development + - Stable + - Frozen + - Ratified + default: Development prerelease: - description: 'Tag as a pre-release?' + description: Tag as a pre-release? required: false type: boolean default: true draft: - description: 'Create release as a draft?' + description: Create release as a draft? required: false type: boolean default: false @@ -33,40 +35,52 @@ jobs: runs-on: ubuntu-latest steps: - # Step 1: Checkout the repository - - name: Checkout repository - uses: actions/checkout@v3 - with: - submodules: 'recursive' + # Checkout the repository + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive - # Step 2: Pull the latest RISC-V Docs container image - - name: Pull Container - run: docker pull riscvintl/riscv-docs-base-container-image:latest + - name: Get next version + uses: reecetech/version-increment@2024.4.4 + id: version + with: + scheme: semver + increment: patch - # Step 3: Build Files - - name: Build Files - run: make - env: - VERSION: v${{ github.event.inputs.version }} - REVMARK: ${{ github.event.inputs.revision_mark }} + # Pull the latest RISC-V Docs container image + - name: Pull Container + run: docker pull riscvintl/riscv-docs-base-container-image:latest - # Step 4: Upload the built PDF files as a single artifact - - name: Upload Build Artifacts - uses: actions/upload-artifact@v3 - with: - path: ${{ github.workspace }}/*.pdf - retention-days: 30 + # Override VERSION and REVMARK for manual workflow dispatch + - name: Update environment variables + run: | + echo "VERSION=v${{ steps.version.outputs.version }}" >> "$GITHUB_ENV" + echo "REVMARK=${{ github.event.inputs.revision_mark }}" >> "$GITHUB_ENV" + if: github.event_name == 'workflow_dispatch' - # Create Release - - name: Create Release - uses: softprops/action-gh-release@v1 - with: - files: ${{ github.workspace }}/*.pdf - tag_name: v${{ github.event.inputs.version }} - name: Release ${{ github.event.inputs.version }} - draft: ${{ github.event.inputs.draft }} - prerelease: ${{ github.event.inputs.prerelease }} - env: - GITHUB_TOKEN: ${{ secrets.GHTOKEN }} - if: github.event_name == 'workflow_dispatch' - # This condition ensures this step only runs for workflow_dispatch events. + # Build Files + - name: Build Files + run: make + + # Upload the built PDF files as a single artifact + - name: Upload Build Artifacts + uses: actions/upload-artifact@v4 + with: + name: Build Artifacts + path: ${{ github.workspace }}/build/*.pdf + retention-days: 30 + + # Create Release + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + files: ${{ github.workspace }}/build/*.pdf + tag_name: v${{ steps.version.outputs.version }} + name: Release ${{ steps.version.outputs.version }} + draft: ${{ github.event.inputs.draft }} + prerelease: ${{ github.event.inputs.prerelease }} + env: + GITHUB_TOKEN: ${{ secrets.GHTOKEN }} + if: github.event_name == 'workflow_dispatch' + # This condition ensures this step only runs for workflow_dispatch events. diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..74b9ec35 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,15 @@ +--- +name: pre-commit + +on: + pull_request: + push: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + - uses: pre-commit/action@v3.0.0 diff --git a/.gitignore b/.gitignore index bd98a737..f7fffe0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -*.pdf - +/build/* +/images/* +.vscode diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..c2654dc2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,25 @@ +--- +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-json + - id: check-symlinks + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + + - repo: local + hooks: + - id: forbidden-file-extensions + name: forbidden-file-extensions + entry: disallow these file extensions + language: fail + # Disallow other asciidoc extensions except .adoc + files: .*\.(asciidoc|asc)$ + + - repo: https://github.com/rbubley/mirrors-prettier + rev: v3.3.0 + hooks: + - id: prettier diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..e9f5ea0f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# RISC-V Code of Conduct + +All RISC-V International projects are governed by the RISC-V Code of Conduct found at https://riscv.org/community/community-code-of-conduct/. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..16c86450 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contribution Guidelines + +As an open-source project, we appreciate and encourage community members to submit patches directly to the project. To maintain a well-organized development environment, we have established standards and methods for submitting changes. This document outlines the process for submitting patches to the project, ensuring that your contribution is swiftly incorporated into the codebase. + +# Licensing + +Licensing is crucial for open-source projects, as it guarantees that the software remains available under the conditions specified by the author. + +This project employs the Creative Commons Attribution 4.0 International license, which can be found in the LICENSE file within the project's repository. + +Licensing defines the rights granted to you as an author by the copyright holder. It is essential for contributors to fully understand and accept these licensing rights. In some cases, the copyright holder may not be the contributor, such as when the contributor is working on behalf of a company. + +# Developer Certificate of Origin (DCO) + +To uphold licensing criteria and demonstrate good faith, this project mandates adherence to the Developer Certificate of Origin (DCO) process. + +The DCO is an attestation appended to every contribution from each author. In the commit message of the contribution (explained in greater detail later in this document), the author adds a Signed-off-by statement, thereby accepting the DCO. + +When an author submits a patch, they affirm that they possess the right to submit the patch under the designated license. The DCO agreement is displayed below and at https://developercertificate.org. + +Developer's Certificate of Origin 1.1 + +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. + +# DCO Sign-Off Methods + +The DCO necessitates the inclusion of a sign-off message in the following format for each commit within the pull request: + +Signed-off-by: Stephano Cetola + +Please use your real name in the sign-off message. + +You can manually add the DCO text to your commit body or include either -s or --signoff in your standard Git commit commands. If you forget to incorporate the sign-off, you can also amend a previous commit with the sign-off by executing git commit --amend -s. If you have already pushed your changes to GitHub, you will need to force push your branch afterward using git push -f. + +Note: + +Ensure that the name and email address associated with your GitHub account match the name and email address in the Signed-off-by line of your commit message. diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 00000000..df8ca25e --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,9 @@ +# Governance + +This project for the template specification is governed by the Documentation SIG. + +The group can be joined by RISC-V members at: https://lists.riscv.org/g/sig-documentation. + +Mailing list archives are available at: https://lists.riscv.org/g/sig-documentation/topics. + +**_NOTE:_** PROJECTS BUILT USING THE TEMPLATE SHOULD UPDATE THE ABOVE TEXT AS-NEEDED. diff --git a/LICENSE b/LICENSE index 53883b1c..2f244ac8 100644 --- a/LICENSE +++ b/LICENSE @@ -49,7 +49,7 @@ exhaustive, and do not form part of our licenses. such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More_considerations - for the public: + for the public: wiki.creativecommons.org/Considerations_for_licensees ======================================================================= @@ -393,4 +393,3 @@ the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. - diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000..1df8389b --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,7 @@ +# Maintainers + +This project is maintained by the following people: + +- FIXME + +**_NOTE:_** PROJECTS BUILT USING THE TEMPLATE SHOULD UPDATE THE ABOVE TEXT AS-NEEDED. diff --git a/Makefile b/Makefile index ad5798e2..a6188e81 100644 --- a/Makefile +++ b/Makefile @@ -8,20 +8,33 @@ # SPDX-License-Identifier: CC-BY-SA-4.0 # # Description: -# -# This Makefile is designed to automate the process of building and packaging +# +# This Makefile is designed to automate the process of building and packaging # the Doc Template for RISC-V Extensions. +DOCS := \ + riscv-iommu.adoc + DATE ?= $(shell date +%Y-%m-%d) -VERSION ?= v0.0.0 -REVMARK ?= Draft -DOCKER_RUN := docker run --rm -v ${PWD}:/build -w /build \ -riscvintl/riscv-docs-base-container-image:latest +VERSION ?= v1.0 +REVMARK ?= 'This document is Ratified. See http://riscv.org/spec-state for details.' +DOCKER_IMG := riscvintl/riscv-docs-base-container-image:latest +ifneq ($(SKIP_DOCKER),true) + DOCKER_CMD := docker run --rm -v ${PWD}:/build -w /build \ + ${DOCKER_IMG} \ + /bin/sh -c + DOCKER_QUOTE := " +endif -HEADER_SOURCE := header.adoc -PDF_RESULT := riscv-iommu.pdf +SRC_DIR := src +BUILD_DIR := build +DOCS_PDF := $(DOCS:%.adoc=%.pdf) +DOCS_HTML := $(DOCS:%.adoc=%.html) + +XTRA_ADOC_OPTS := ASCIIDOCTOR_PDF := asciidoctor-pdf +ASCIIDOCTOR_HTML := asciidoctor OPTIONS := --trace \ -a compress \ -a mathematical-format=svg \ @@ -29,17 +42,30 @@ OPTIONS := --trace \ -a revremark=${REVMARK} \ -a revdate=${DATE} \ -a pdf-fontsdir=docs-resources/fonts \ - -a pdf-style=docs-resources/themes/riscv-pdf.yml \ + -a pdf-theme=docs-resources/themes/riscv-pdf.yml \ + $(XTRA_ADOC_OPTS) \ + -D build \ --failure-level=ERROR REQUIRES := --require=asciidoctor-bibtex \ --require=asciidoctor-diagram \ + --require=asciidoctor-lists \ --require=asciidoctor-mathematical -.PHONY: all build clean build-container build-no-container +.PHONY: all build clean build-container build-no-container build-docs all: build -build: +build-docs: $(DOCS_PDF) $(DOCS_HTML) + +vpath %.adoc $(SRC_DIR) + +%.pdf: %.adoc + $(DOCKER_CMD) $(DOCKER_QUOTE) $(ASCIIDOCTOR_PDF) $(OPTIONS) $(REQUIRES) $< $(DOCKER_QUOTE) + +%.html: %.adoc + $(DOCKER_CMD) $(DOCKER_QUOTE) $(ASCIIDOCTOR_HTML) $(OPTIONS) $(REQUIRES) $< $(DOCKER_QUOTE) + +build: @echo "Checking if Docker is available..." @if command -v docker >/dev/null 2>&1 ; then \ echo "Docker is available, building inside Docker container..."; \ @@ -51,15 +77,19 @@ build: build-container: @echo "Starting build inside Docker container..." - $(DOCKER_RUN) /bin/sh -c "$(ASCIIDOCTOR_PDF) $(OPTIONS) $(REQUIRES) --out-file=$(PDF_RESULT) $(HEADER_SOURCE)" + $(MAKE) build-docs @echo "Build completed successfully inside Docker container." build-no-container: @echo "Starting build..." - $(ASCIIDOCTOR_PDF) $(OPTIONS) $(REQUIRES) --out-file=$(PDF_RESULT) $(HEADER_SOURCE) + $(MAKE) SKIP_DOCKER=true build-docs @echo "Build completed successfully." +# Update docker image to latest +docker-pull-latest: + docker pull ${DOCKER_IMG} + clean: @echo "Cleaning up generated files..." - rm -f $(PDF_RESULT) + rm -rf $(BUILD_DIR) @echo "Cleanup completed." diff --git a/README.adoc b/README.adoc new file mode 100644 index 00000000..ce2420b6 --- /dev/null +++ b/README.adoc @@ -0,0 +1,109 @@ += RISC-V IOMMU specification + +The specification is in Frozen state and pending ratification. + +== License + +This work is licensed under a Creative Commons Attribution 4.0 International License (CC-BY-4.0). For details, see the link:LICENSE[LICENSE] file. + +== Maintainers + +The list of maintainers of this specification is maintained in the link:MAINTAINERS.md[MAINTAINERS] file. + +== Contributors + +The list of contributors to this specification is maintained in the link:src/contributors.adoc[contributors] file. + +For guidelines on how to contribute, refer to the link:CONTRIBUTING.md[CONTRIBUTING] file. + +== Governance + +The governance for this project is defined in the link:GOVERNANCE.md[GOVERNANCE] file. + +Community information, including meeting (if held) and mailing lists are detailed in this file. + +== Building the Document + +=== Directory Structure + +The following directories are used to organize the contents of this repo: + +* `dependencies/`: software dependencies needed to build the specification +* `docs-resources/`: resources for all specifications sourced from link:.gitmodules[git submodule] +* `src/`: source files for the specification +* `build/`: default directory where the build artifacts are generated + +=== Prerequisites + +To build the document, you'll need the following tools installed on your system: + +* Make +* asciiDoctor-pdf, asciidoctor-bibtex, asciidoctor-diagram, and asciidoctor-mathematical +* Docker + +=== Cloning the Repository + +```shell +git clone --recurse-submodules https://github.com/riscv-non-isa/riscv-iommu.git +``` + +All in one single line: + +```shell +git clone --recurse-submodules https://github.com/riscv-non-isa/riscv-iommu.git && cd riscv-iommu && git submodule update --init --recursive + +``` + +=== Building the Documentation + +To start the build process, run: + +```shell +cd ./riscv-iommu && make build +``` + +The link:Makefile[] script will check the availability of Docker on your system: + +* If Docker is available, the documentation will be built inside a Docker container using the image riscvintl/riscv-docs-base-container-image:latest. This ensures a consistent build environment across different systems. +* If Docker is not available, the documentation will be built directly on your system using the installed tools. + +The documentation is generated from the AsciiDoctor source files in your project. The primary source file is specified by the `HEADER_SOURCE` variable in the Makefile. + +The build process utilizes several options, including theming and font settings, and generates a PDF document as output. + +=== Cleaning up + +To clean up the generated files, run: + +```shell +make clean +``` + +== Enabling pre-commit checks locally + +The repository has some basic commit checks set up with https://pre-commit.com/[pre-commit] that will be enforced by the GitHub CI. +To ensure these checks are also run in the local repository while making changes the following can be done: + +.Installing pre-commit tool +[source,shell] +---- +# Do once on your system +pip3 install pre-commit +---- + +.Installing pre-commit git hook in repo +[source,shell] +---- +# Do once in local repo +pre-commit install +---- + +Rather than doing the above `pre-commit install` in every repo that uses it, you can do it https://pre-commit.com/#automatically-enabling-pre-commit-on-repositories[once on your system.] + +When enabling additional checks https://pre-commit.com/#plugins[by editing .pre-commit-config.yaml], it is recommended running the newly added check on all files in the repository. This can be done with the following command: + +.Running all pre-commit hooks on all files +[source,shell] +---- +pre-commit run --all-files +---- diff --git a/dependencies/README.md b/dependencies/README.md index 0841ce89..36e5f3ce 100644 --- a/dependencies/README.md +++ b/dependencies/README.md @@ -1,3 +1,2 @@ -Dependencies for the build environment for various package managers. Used in +Dependencies for the build environment for various package managers. Used in `.github/workflows/`. - diff --git a/dependencies/package.json b/dependencies/package.json index 457d43de..7347d43a 100644 --- a/dependencies/package.json +++ b/dependencies/package.json @@ -1,7 +1,7 @@ { - "dependencies": { - "bytefield-svg": "^1.8.0", - "wavedrom-cli": "^2.6.8" + "dependencies": { + "bytefield-svg": "^1.8.0", + "wavedrom-cli": "^2.6.8" }, "name": "local", "version": "0.0.1" diff --git a/docs-resources b/docs-resources index 6a2d5b1f..c0ff7005 160000 --- a/docs-resources +++ b/docs-resources @@ -1 +1 @@ -Subproject commit 6a2d5b1f929e0e25df0c832b522ed1fc0c78e325 +Subproject commit c0ff7005346bc05dee68fa20354f454aea193ee2 diff --git a/images/risc-v_logo.svg b/images/risc-v_logo.svg deleted file mode 120000 index 31e4a40b..00000000 --- a/images/risc-v_logo.svg +++ /dev/null @@ -1 +0,0 @@ -../docs-resources/images/risc-v_logo.svg \ No newline at end of file diff --git a/iommu_ref_model/README.md b/iommu_ref_model/README.md index 73af1e9c..5e7f0203 100644 --- a/iommu_ref_model/README.md +++ b/iommu_ref_model/README.md @@ -1,13 +1,16 @@ # RISC-V IOMMU reference model + This code implements the RISC-V IOMMU specification - https://github.com/riscv-non-isa/riscv-iommu - and is intended to be a behavioural reference model for the specification. # Files organization -- libiommu - Files implementing the specification + +- libiommu - Files implementing the specification - libtables - a support library to build page and directory tables -- test - a sample test application illustrating how to invoke and use libiommu and libtables +- test - a sample test application illustrating how to invoke and use libiommu and libtables # Building and Running tests + The project builds two libraries libiommu.a and libtables.a. The test application links to both the libraries and uses the API provided by libtables to build the memory resident tables. @@ -16,11 +19,12 @@ of the tests and a coverage report on the reference model. The coverage report m generation of further tests. The reference model, may be used in conjuction with a IOMMU to verify the behavior of the IOMMU. For -example, the tests may provide identical stimulus to the IOMMU reference model and the IOMMU and +example, the tests may provide identical stimulus to the IOMMU reference model and the IOMMU and compare the results. The debug interface of the IOMMU may be used to provide stimulus when its simpler not to use real IO devices to generate the stimulus. The stock test application generates the following output. + ```bash Running IOMMU test suite Test 01 : All inbound transactions disallowed : PASS @@ -47,16 +51,17 @@ File 'src/iommu_utils.c' :100.00% ``` # Reference model test bench functions + To drive the reference mode, the model exposes the following APIs that must be implemented by the test bench: 1. **`uint8_t read_memory(uint64_t address, uint8_t size, char *data)`** -This function is used by the reference model to read memory. The bit 0 of the -return value may be set to 1 to indicate an access violation and the bit 1 set -to 1 to indicate that the data returned is corrupted and thus must cause a data -corruption fault. If neither bits are set then the read is assumed to be -successful and the data bytes placed in the buffer identified by the data +This function is used by the reference model to read memory. The bit 0 of the +return value may be set to 1 to indicate an access violation and the bit 1 set +to 1 to indicate that the data returned is corrupted and thus must cause a data +corruption fault. If neither bits are set then the read is assumed to be +successful and the data bytes placed in the buffer identified by the data parameter. 2. **`uint8_t read_memory_for_AMO(uint64_t address, uint8_t size, char *data)`** @@ -66,9 +71,9 @@ operation but is otherwise identical to the read_memory API. 3. **`uint8_t write_memory(char *data, uint64_t address, uint32_t size)`** -This function is used by the reference model to write memory. The bit 0 of the +This function is used by the reference model to write memory. The bit 0 of the return value may be set to 1 to indicate an access violation. If the return value is -0 then the write is assumed to be successful and the data bytes in the buffer +0 then the write is assumed to be successful and the data bytes in the buffer identified by the data parameter are written to the memory identified by the address parameter. @@ -85,7 +90,7 @@ group response - to the test bench. # Reference model functions -These functions are provided by the reference model to the test bench to input stimulii and +These functions are provided by the reference model to the test bench to input stimulii and obtain responses from the model. 1. **`uint64_t read_register(uint16_t offset, uint8_t num_bytes)`** @@ -107,12 +112,12 @@ an abort response. 3. **`int reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, uint8_t num_vec_bits, uint8_t reset_iommu_mode, capabilities_t capabilities, fctrl_t fctrl)`** This function is provided by the reference model to establish the resset default state. -The num_hpm indicates the number of hardware performace monitoring counters to be +The num_hpm indicates the number of hardware performace monitoring counters to be implemented by the model and the hpmctr_bits indicates the width of the counters in bits. The eventID_mask indicates the width of the eventID field in the hardware performance -monitoring event registers that should be implemented by the reference model. The +monitoring event registers that should be implemented by the reference model. The num_vec_bits indicates the width in bits of the vector field of the ICVEC register. The -default IOMMU mode - Off or Bare - is selected by the reset_iommu_mode parameter. The +default IOMMU mode - Off or Bare - is selected by the reset_iommu_mode parameter. The capabilities of the IOMMU that should be implemented are specified by the capabilities parameter. The default value of the feature control register is provided by the fctrl parameter. The function returns 0 if the reference model could be successfully initialized @@ -134,7 +139,7 @@ This function is used by the test bench to send a invalidation completion messag 7. **`void do_ats_timer_expiry(uint32_t itag_vector)`** This function is used by the test bench to signal a timeout for one or more ATS invalidation -requests sent by the IOMMU. +requests sent by the IOMMU. 8. **`void process_commands(void)`** @@ -148,6 +153,7 @@ This function is used to extract the read, write, execute, and privilege attributes from the the request. # Libtables functions + The following functions are provided by the libtables to build memory resident data structures. The functions do not implement extensive error checking and providing bad inputs may lead to bad tables being created. @@ -156,13 +162,13 @@ tables being created. This function is used to build the device directory table by adding non-leaf entries when needed and inserting the device context in the leaf entry. The function returns the address, in test memory -space, where the leaf entry was inserted. +space, where the leaf entry was inserted. 2. **`uint64_t add_process_context(device_context_t *DC, process_context_t *PC, uint32_t process_id)`** This function is used to build the process directory table by adding non-leaf entries when needed and inserting the process context in the leaf entry. The function returns the address, in test memory -space, where the leaf entry was inserted. +space, where the leaf entry was inserted. 3. **`uint64_t add_g_stage_pte(iohgatp_t iohgatp, uint64_t gpa, gpte_t gpte, uint8_t add_level)`** @@ -173,7 +179,6 @@ Larger mappings may be created, as appropriate for the mode in iohgatp, by speci The function may invoke the get_ppn function to request pages to build the page table. The function returns the address, in test memory space, where the leaf entry was inserted. - 4. **`uint64_t add_s_stage_pte(iosatp_t satp, uint64_t va, pte_t pte, uint8_t add_level)`** This function is used to build the S-stage page table by adding non-leaf entries when needed @@ -190,7 +195,7 @@ and inserting the leaf entry at the requested level. The level value of 0 indica should be added at the last level possible for the VS-stage page table i.e. a 4K or a NAPOT 64K entry. Larger mappings may be created, as appropriate for the mode in satp, by specifying higher levels. The function may invoke the get_gppn function to request pages to build the page table. The function -maps the obtained gppn into the G-stage page table determined by iohgatp. The function returns the address, +maps the obtained gppn into the G-stage page table determined by iohgatp. The function returns the address, in test memory space, where the leaf entry was inserted. 6. **`uint64_t translate_gpa (iohgatp_t iohgatp, uint64_t gpa, uint64_t *spa)`** @@ -199,6 +204,7 @@ This function is used to translate a gpa to a spa. The function also returns the the translation as an address in test memory space. # Libtables test bench functions + These functions are invoked by the libtables functions to allocate memory for the table structures. These are provided by the test bench that invokes the libtables. @@ -209,6 +215,5 @@ a range of pages with the base page aligned to num_ppn. 2. **`uint64_t get_free_gppn(uint64_t num_gppn, iohgatp_t iohgatp)`** -This function is used to allocate a set of pages in the memory space of the guest associated with iohgatp. +This function is used to allocate a set of pages in the memory space of the guest associated with iohgatp. The function should provide a range of pages with the base page aligned to num_gppn. - diff --git a/iommu_ref_model/libiommu/Makefile b/iommu_ref_model/libiommu/Makefile index 683c0995..6edcb1c5 100644 --- a/iommu_ref_model/libiommu/Makefile +++ b/iommu_ref_model/libiommu/Makefile @@ -1,4 +1,4 @@ -CFLAGS := -g -Wall -Werror -Iinclude -fprofile-arcs -ftest-coverage +CFLAGS := -g -Wall -Werror -Iinclude -fprofile-arcs -ftest-coverage CC := gcc NAME := iommu SRCS = src/iommu_reg.c src/iommu_translate.c src/iommu_faults.c src/iommu_interrupt.c src/iommu_two_stage_trans.c src/iommu_second_stage_trans.c src/iommu_msi_trans.c src/iommu_device_context.c src/iommu_command_queue.c src/iommu_utils.c src/iommu_atc.c src/iommu_process_context.c src/iommu_ats.c src/iommu_hpm.c diff --git a/iommu_ref_model/libiommu/include/iommu_atc.h b/iommu_ref_model/libiommu/include/iommu_atc.h index 4c1d8a07..2cd952e8 100644 --- a/iommu_ref_model/libiommu/include/iommu_atc.h +++ b/iommu_ref_model/libiommu/include/iommu_atc.h @@ -29,14 +29,14 @@ typedef struct { // PPN and size uint64_t PPN; uint8_t S; - uint32_t lru; + uint32_t lru; uint8_t valid; } tlb_t; // Device directory cache typedef struct { device_context_t DC; uint32_t DID; - uint32_t lru; + uint32_t lru; uint8_t valid; } ddt_cache_t; // Process directory cache @@ -44,7 +44,7 @@ typedef struct { process_context_t PC; uint32_t DID; uint32_t PID; - uint32_t lru; + uint32_t lru; uint8_t valid; } pdt_cache_t; @@ -68,21 +68,20 @@ extern uint8_t lookup_ioatc_iotlb( uint64_t iova, uint8_t check_access_perms, uint8_t priv, uint8_t is_read, uint8_t is_write, uint8_t is_exec, - uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, + uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, uint32_t *cause, uint64_t *resp_pa, uint64_t *page_sz, pte_t *vs_pte, gpte_t *g_pte); -extern uint8_t +extern uint8_t lookup_ioatc_dc(uint32_t device_id, device_context_t *DC); -extern void +extern void cache_ioatc_dc(uint32_t device_id, device_context_t *DC); -extern uint8_t +extern uint8_t lookup_ioatc_pc(uint32_t device_id, uint32_t process_id, process_context_t *PC); extern void cache_ioatc_pc(uint32_t device_id, uint32_t process_id, process_context_t *PC); #endif // __IOMMU_ATC_H__ - diff --git a/iommu_ref_model/libiommu/include/iommu_ats.h b/iommu_ref_model/libiommu/include/iommu_ats.h index 5970cbf3..a515dd62 100644 --- a/iommu_ref_model/libiommu/include/iommu_ats.h +++ b/iommu_ref_model/libiommu/include/iommu_ats.h @@ -48,19 +48,19 @@ typedef struct { //0000b |Success |All pages within the associated PRG were successfully made resident. //-----------+---------+-------------------------------------------------------------------- //0001b |Invalid |One or more pages within the associated PRG do not exist or requests -// |Request |access privilege(s) that cannot be granted. Unless the page mapping +// |Request |access privilege(s) that cannot be granted. Unless the page mapping // | |associated with the Function is altered, re-issuance of the associated -// | |request will never result in success. +// | |request will never result in success. //-----------+---------+-------------------------------------------------------------------- -//1110b:0010b|Unused |Unused Response Code values. A Function receiving such a message shall -// | |process it as if the message contained a Response Code of +//1110b:0010b|Unused |Unused Response Code values. A Function receiving such a message shall +// | |process it as if the message contained a Response Code of // | |Response Failure. //-----------+---------+-------------------------------------------------------------------- -//1111b | Response|One or more pages within the associated request group have -// | Failure |encountered/caused a catastrophic error. This response disables the -// | |Page Request Interface at the Function. Any pending page requests for -// | |other PRGs will be satisfied at the convenience of the host. The -// | |Function shall ignore any subsequent PRG Response Messages, pending +//1111b | Response|One or more pages within the associated request group have +// | Failure |encountered/caused a catastrophic error. This response disables the +// | |Page Request Interface at the Function. Any pending page requests for +// | |other PRGs will be satisfied at the convenience of the host. The +// | |Function shall ignore any subsequent PRG Response Messages, pending // | |re-enablement of the Page Request Interface. //-----------+---------+-------------------------------------------------------------------- #define SUCCESS 0x0UL diff --git a/iommu_ref_model/libiommu/include/iommu_command_queue.h b/iommu_ref_model/libiommu/include/iommu_command_queue.h index 3bae2bbe..2bae143e 100644 --- a/iommu_ref_model/libiommu/include/iommu_command_queue.h +++ b/iommu_ref_model/libiommu/include/iommu_command_queue.h @@ -94,11 +94,10 @@ void do_inval_ddt(uint8_t DV, uint32_t DID); void do_inval_pdt(uint32_t DID, uint32_t PID); void do_iotinval_vma(uint8_t GV, uint8_t AV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, uint64_t ADDR); void do_iotinval_gvma(uint8_t GV, uint8_t AV, uint32_t GSCID, uint64_t ADDR); -void do_ats_msg( uint8_t MSGCODE, uint8_t TAG, uint8_t DSV, uint8_t DSEG, uint16_t RID, +void do_ats_msg( uint8_t MSGCODE, uint8_t TAG, uint8_t DSV, uint8_t DSEG, uint16_t RID, uint8_t PV, uint32_t PID, uint64_t PAYLOAD); uint8_t do_iofence_c(uint8_t PR, uint8_t PW, uint8_t AV, uint8_t WIS_BIT, uint64_t ADDR, uint32_t DATA); void do_pending_iofence(); void queue_any_blocked_ats_inval_req(); extern uint8_t g_ats_inv_req_timeout; #endif // __IOMMU_COMMAND_QUEUE_H__ - diff --git a/iommu_ref_model/libiommu/include/iommu_data_structures.h b/iommu_ref_model/libiommu/include/iommu_data_structures.h index dfc7b47c..bd02474f 100644 --- a/iommu_ref_model/libiommu/include/iommu_data_structures.h +++ b/iommu_ref_model/libiommu/include/iommu_data_structures.h @@ -27,7 +27,7 @@ typedef union { // invalid requests. A "Page Request" message received from a device is responded to // with a "Page Request Group Response" message. Normally, a software handler // generates this response message. However, under some conditions the IOMMU itself - // may generate a response. + // may generate a response. uint64_t EN_PRI:1; // If the `EN_ATS` bit is 1 and the `T2GPA` bit is set to 1 the IOMMU returns a GPA @@ -37,7 +37,7 @@ typedef union { // in subsequent translated memory access transactions. Usually translated requests // use a SPA and need no further translation to be performed by the IOMMU. However // when `T2GPA` is 1, translated requests from a device use a GPA and are - // translated by the IOMMU using the G-stage page table to a SPA. The `T2GPA` + // translated by the IOMMU using the G-stage page table to a SPA. The `T2GPA` // control enables a hypervisor to contain DMA from a device, even if the device // misuses the ATS capability and attempts to access memory that is not associated // with the VM. @@ -69,8 +69,8 @@ typedef union { // "Page Request" had a PASID. uint64_t PRPR:1; - // The IOMMU supports the 1 setting of GADE and SADE bits if capabilities.AMO is 1. - // When capabilities.AMO is 0, these bits are reserved. If GADE is 1, the IOMMU + // The IOMMU supports the 1 setting of GADE and SADE bits if capabilities.AMO is 1. + // When capabilities.AMO is 0, these bits are reserved. If GADE is 1, the IOMMU // updates A and D bits in G-stage PTEs atomically. If GADE is 0, the IOMMU causes // a guest-page-fault corresponding to the original access type if A bit is 0 or if // the memory access is a store and the D bit is 0. @@ -157,9 +157,9 @@ typedef union { // IO SATP typedef union { struct { - uint64_t PPN:44; - uint64_t reserved:16; - uint64_t MODE:4; + uint64_t PPN:44; + uint64_t reserved:16; + uint64_t MODE:4; }; uint64_t raw; } iosatp_t; @@ -199,8 +199,8 @@ typedef union { // the guest OS to directly edit the PDT to associate a virtual-address space // identified by a VS-stage page table with a `process_id`. struct { - uint64_t PPN:44; - uint64_t reserved:16; + uint64_t PPN:44; + uint64_t reserved:16; // Encoding of `pdtp.MODE` field // |Value | Name | Description // | 0 | `Bare` | No translation or protection. First stage translation is @@ -216,7 +216,7 @@ typedef union { // | 4-13 | -- | Reserved // |14-15 | -- | Custome - uint64_t MODE:4; + uint64_t MODE:4; } pdtp; uint64_t raw; @@ -236,22 +236,22 @@ typedef union { #define MSIPTP_Flat 1 typedef union { struct { - uint64_t PPN:44; + uint64_t PPN:44; uint64_t reserved:16; - uint64_t MODE:4; + uint64_t MODE:4; }; uint64_t raw; } msiptp_t; -// The MSI address mask (msi_addr_mask) and pattern (msi_addr_pattern) fields are used to +// The MSI address mask (msi_addr_mask) and pattern (msi_addr_pattern) fields are used to // recognize certain memory writes from the device as being MSIs and to identify the 4-KiB // pages of virtual interrupt files in the guest physical address space of the relevant VM. -// An incoming 32-bit write made by a device is recognized as an MSI write to a virtual -// interrupt file if the destination guest physical page matches the supplied address -// pattern in all bit positions that are zeros in the supplied address mask. In detail, a +// An incoming 32-bit write made by a device is recognized as an MSI write to a virtual +// interrupt file if the destination guest physical page matches the supplied address +// pattern in all bit positions that are zeros in the supplied address mask. In detail, a // write to guest physical address A is recognized as an MSI to a virtual interrupt file if: // (A >> 12) & ~msi_addr_mask = (msi_addr_pattern & ~msi_addr_mask) -// where >> 12 represents shifting right by 12 bits, an ampersand (&) represents bitwise +// where >> 12 represents shifting right by 12 bits, an ampersand (&) represents bitwise // logical AND, and ~msi_addr_mask is the bitwise logical complement of the address mask. typedef union { struct { @@ -269,7 +269,7 @@ typedef union { } msi_addr_pattern_t; // In base-format the `DC` is 32-bytes. In extended-format the `DC` is 64-bytes. -// +// // Base-format device-context // bits: 63:0:'Translation-control (tc)' // bits: 127:64:'IO Hypervisor guest address translation and protection (iohgatp)' @@ -352,7 +352,7 @@ typedef union { uint64_t raw; } pc_fsc_t; -// A valid (`V==1`) non-leaf PDT entry holds the PPN of the +// A valid (`V==1`) non-leaf PDT entry holds the PPN of the // next-level PDT. typedef union { struct { diff --git a/iommu_ref_model/libiommu/include/iommu_fault.h b/iommu_ref_model/libiommu/include/iommu_fault.h index f4949ad6..49f6d9dd 100644 --- a/iommu_ref_model/libiommu/include/iommu_fault.h +++ b/iommu_ref_model/libiommu/include/iommu_fault.h @@ -7,7 +7,7 @@ // The TTYP field reports inbound transaction type // Fault record `TTYP` field encodings -// |TTYP | Description +// |TTYP | Description // |0 | None. Fault not caused by an inbound transaction. // |1 | Untranslated read for execute transaction // |2 | Untranslated read transaction @@ -17,7 +17,7 @@ // |6 | Translated read transaction // |7 | Translated write/AMO transaction // |8 | PCIe ATS Translation Request -// |9 | Message Request +// |9 | Message Request // |10 - 31| Reserved // |31 - 63| Reserved for custom use #define TTYPE_NONE 0 diff --git a/iommu_ref_model/libiommu/include/iommu_hpm.h b/iommu_ref_model/libiommu/include/iommu_hpm.h index 0361c293..a8119f88 100644 --- a/iommu_ref_model/libiommu/include/iommu_hpm.h +++ b/iommu_ref_model/libiommu/include/iommu_hpm.h @@ -26,6 +26,6 @@ #define S_VS_PT_WALKS 7 #define G_PT_WALKS 8 -void count_events(uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, +void count_events(uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, uint32_t DID, uint8_t GSCV, uint32_t GSCID, uint16_t eventID); #endif // __IOMMU_PMU_H__ diff --git a/iommu_ref_model/libiommu/include/iommu_ref_api.h b/iommu_ref_model/libiommu/include/iommu_ref_api.h index ea5db15d..d8768578 100644 --- a/iommu_ref_model/libiommu/include/iommu_ref_api.h +++ b/iommu_ref_model/libiommu/include/iommu_ref_api.h @@ -14,8 +14,8 @@ extern void write_register(uint16_t offset, uint8_t num_bytes, uint64_t data); #define FILL_IOATC_ATS_T2GPA 0x01 #define FILL_IOATC_ATS_ALWAYS 0x02 -extern int reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, - uint8_t num_vec_bits, uint8_t reset_iommu_mode, +extern int reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, + uint8_t num_vec_bits, uint8_t reset_iommu_mode, uint8_t max_iommu_mode, uint32_t max_devid_mask, uint8_t gxl_writeable, uint8_t fctl_be_writeable, uint8_t fill_ats_trans_in_ioatc, capabilities_t capabilities, diff --git a/iommu_ref_model/libiommu/include/iommu_registers.h b/iommu_ref_model/libiommu/include/iommu_registers.h index f0874939..ec16d30c 100644 --- a/iommu_ref_model/libiommu/include/iommu_registers.h +++ b/iommu_ref_model/libiommu/include/iommu_registers.h @@ -10,13 +10,13 @@ // the IOMMU. At reset, the register shall contain the IOMMU supported features. // Hypervisor may provide an SW emulated IOMMU to allow the guest to manage // the VS-stage page tables for fine grained control on memory accessed by guest -// controlled devices. +// controlled devices. // A hypervisor that provides such an emulated IOMMU to the guest may retain -// control of the G-stage page tables and clear the `SvNx4` fields of the +// control of the G-stage page tables and clear the `SvNx4` fields of the // emulated `capabilities` register. // A hypervisor that provides such an emulated IOMMU to the guest may retain // control of the MSI page tables used to direct MSI to guest interrupt files in -// an IMSIC or to a memory-resident-interrupt-file and clear the `MSI_FLAT` and +// an IMSIC or to a memory-resident-interrupt-file and clear the `MSI_FLAT` and // `MSI_MRIF` fields of the emulated `capabilities` register. typedef union { struct { @@ -120,10 +120,10 @@ typedef union { uint64_t iommu_mode: 4; // The IOMMU may be configured to be in following // modes: // !Value !Name ! Description - // !0 ! `Off` ! No inbound memory + // !0 ! `Off` ! No inbound memory // transactions are allowed // by the IOMMU. - // !1 ! `Bare` ! No translation or + // !1 ! `Bare` ! No translation or // protection. All inbound // memory accesses are passed // through. @@ -135,23 +135,23 @@ typedef union { // device-directory-table // !5-13 ! reserved ! Reserved for standard use. // !14-15 ! custom ! Designated for custom use. - uint64_t busy : 1; // A write to `ddtp` may require the IOMMU to - // perform many operations that may not occur + uint64_t busy : 1; // A write to `ddtp` may require the IOMMU to + // perform many operations that may not occur // synchronously to the write. When a write is // observed by the `ddtp`, the `busy` bit is set // to 1. When the `busy` bit is 1, behavior of - // additional writes to the `ddtp` is + // additional writes to the `ddtp` is // implementation defined. Some implementations // may ignore the second write and others may // perform the actions determined by the second // write. Software must verify that the `busy` // bit is 0 before writing to the `ddtp`. - - // If the `busy` bit reads 0 then the IOMMU has - // completed the operations associated with the + + // If the `busy` bit reads 0 then the IOMMU has + // completed the operations associated with the // previous write to `ddtp`. - - // An IOMMU that can complete these operations + + // An IOMMU that can complete these operations // synchronously may hard-wire this bit to 0. uint64_t reserved0: 5; // reserved for standard use. uint64_t ppn : 44; // Holds the `PPN` of the root page of the @@ -166,19 +166,19 @@ typedef union { struct { uint64_t log2szm1: 5; // The `LOG2SZ-1` field holds the number of // entries in command-queue as a log to base 2 - // minus 1. + // minus 1. // A value of 0 indicates a queue of 2 entries. - // Each IOMMU command is 16-bytes. + // Each IOMMU command is 16-bytes. // If the command-queue has 256 or fewer entries - // then the base address of the queue is always + // then the base address of the queue is always // aligned to 4-KiB. If the command-queue has more - // than 256 entries then the command-queue + // than 256 entries then the command-queue // base address must be naturally aligned to - // `2^LOG2SZ^ x 16`. + // `2^LOG2SZ^ x 16`. uint64_t reserved0: 5; // Reserved for standard use uint64_t ppn : 44; // Holds the `PPN` of the root page of the // in-memory command-queue used by software to - // queue commands to the IOMMU. + // queue commands to the IOMMU. uint64_t reserved1: 10; // Reserved for standard use }; uint64_t raw; @@ -198,8 +198,8 @@ typedef union { struct { uint32_t index; // Holds the `index` into the command-queue where // software queues the next command for IOMMU. Only - // `LOG2SZ:0` bits are writable when the queue is - // in enabled state (i.e., `cqsr.cqon == 1`). + // `LOG2SZ:0` bits are writable when the queue is + // in enabled state (i.e., `cqsr.cqon == 1`). }; uint32_t raw; } cqt_t; @@ -210,12 +210,12 @@ typedef union { uint64_t log2szm1: 5; // The `LOG2SZ-1` field holds the number of // entries in fault-queue as a log-to-base-2 // minus 1. A value of 0 indicates a queue of 2 - // entries. Each fault record is 32-bytes. + // entries. Each fault record is 32-bytes. // If the fault-queue has 128 or fewer entries then - // the base address of the queue is always aligned - // to 4-KiB. If the fault-queue has more than 128 - // entries then the fault-queue base address must - // be naturally aligned to `2^LOG2SZ^ x 32`. + // the base address of the queue is always aligned + // to 4-KiB. If the fault-queue has more than 128 + // entries then the fault-queue base address must + // be naturally aligned to `2^LOG2SZ^ x 32`. uint64_t reserved0: 5; // Reserved for standard use uint64_t ppn : 44; // Holds the `PPN` of the root page of the // in-memory fault-queue used by IOMMU to queue @@ -236,7 +236,7 @@ typedef union { }; uint32_t raw; } fqh_t; -// This 32-bits register (RO) holds the index into the fault-queue where the +// This 32-bits register (RO) holds the index into the fault-queue where the // IOMMU queues the next fault record. typedef union { struct { @@ -252,8 +252,8 @@ typedef union { struct { uint64_t log2szm1: 5; // The `LOG2SZ-1` field holds the number of entries // in page-request-queue as a log-to-base-2 minus 1. - // A value of 0 indicates a queue of 2 entries. - // Each page-request is 16-bytes. If the + // A value of 0 indicates a queue of 2 entries. + // Each page-request is 16-bytes. If the // page-request-queue has 256 or fewer entries // then the base address of the queue is always // aligned to 4-KiB. @@ -287,92 +287,92 @@ typedef union { // This 32-bits register (RW) is used to control the operations and report the // status of the command-queue. typedef union { - struct { + struct { uint32_t cqen :1; // The command-queue-enable bit enables the command- // queue when set to 1. Changing `cqen` from 0 to 1 // sets the `cqh` and `cqt` to 0. The command-queue // may take some time to be active following setting // the `cqen` to 1. When the command queue is active, // the `cqon` bit reads 1. - // - // When `cqen` is changed from 1 to 0, the command - // queue may stay active till the commands already - // fetched from the command-queue are being processed - // and/or there are outstanding implicit loads from - // the command-queue. When the command-queue turns - // off, the `cqon` bit reads 0, `cqh` is set to 0, - // `cqt` is set to 0 and the `cqcsr` bits `cmd_ill`, + // + // When `cqen` is changed from 1 to 0, the command + // queue may stay active till the commands already + // fetched from the command-queue are being processed + // and/or there are outstanding implicit loads from + // the command-queue. When the command-queue turns + // off, the `cqon` bit reads 0, `cqh` is set to 0, + // `cqt` is set to 0 and the `cqcsr` bits `cmd_ill`, // `cmd_to`, `cqmf`, `fence_w_ip` are set to 0. - // - // When the `cqon` bit reads 0, the IOMMU guarantees - // that no implicit memory accesses to the command - // queue are in-flight and the command-queue will not + // + // When the `cqon` bit reads 0, the IOMMU guarantees + // that no implicit memory accesses to the command + // queue are in-flight and the command-queue will not // generate new implicit loads to the queue memory. - uint32_t cie :1; // Command-queue-interrupt-enable bit enables - // generation of interrupts from command-queue when + uint32_t cie :1; // Command-queue-interrupt-enable bit enables + // generation of interrupts from command-queue when // set to 1. uint32_t rsvd0 :6; // Reserved for standard use uint32_t cqmf :1; // If command-queue access leads to a memory fault then - // the command-queue-memory-fault bit is set to 1 and - // the command-queue stalls until this bit is cleared. - // When `cqmf` is set to 1, an interrupt is generated - // if an interrupt is not already pending - // (i.e., `ipsr.cip == 1`) and not masked - // (i.e. `cqsr.cie == 0`). To re-enable command - // processing, software should clear this bit by - // writing 1. - uint32_t cmd_to :1; // If the execution of a command leads to a - // timeout (e.g. a command to invalidate device ATC - // may timeout waiting for a completion), then the - // command-queue sets the `cmd_to` bit and stops + // the command-queue-memory-fault bit is set to 1 and + // the command-queue stalls until this bit is cleared. + // When `cqmf` is set to 1, an interrupt is generated + // if an interrupt is not already pending + // (i.e., `ipsr.cip == 1`) and not masked + // (i.e. `cqsr.cie == 0`). To re-enable command + // processing, software should clear this bit by + // writing 1. + uint32_t cmd_to :1; // If the execution of a command leads to a + // timeout (e.g. a command to invalidate device ATC + // may timeout waiting for a completion), then the + // command-queue sets the `cmd_to` bit and stops // processing from the command-queue. When `cmd_to` is - // set to 1 an interrupt is generated if an interrupt - // is not already pending (i.e., `ipsr.cip == 1`) and - // not masked (i.e. `cqsr.cie == 0`). To re-enable - // command processing software should clear this bit - // by writing 1. + // set to 1 an interrupt is generated if an interrupt + // is not already pending (i.e., `ipsr.cip == 1`) and + // not masked (i.e. `cqsr.cie == 0`). To re-enable + // command processing software should clear this bit + // by writing 1. uint32_t cmd_ill :1; // If an illegal or unsupported command is fetched and - // decoded by the command-queue then the command-queue + // decoded by the command-queue then the command-queue // sets the `cmd_ill` bit and stops processing from the - // command-queue. When `cmd_ill` is set to 1, - // an interrupt is generated if not already pending - // (i.e. `ipsr.cip == 1`) and not masked - // (i.e. `cqsr.cie == 0`). To re-enable command - // processing software should clear this bit by - // writing 1. - uint32_t fence_w_ip :1; // An IOMMU that supports only wired interrupts sets - // `fence_w_ip` bit is set to indicate completion of a - // `IOFENCE.C` command. An interrupt on setting - // `fence_w_ip` if not already pending - // (i.e. `ipsr.cip == 1`) and not masked - // (i.e. `cqsr.cie == 0`) and `fence_w_ip` is 0. + // command-queue. When `cmd_ill` is set to 1, + // an interrupt is generated if not already pending + // (i.e. `ipsr.cip == 1`) and not masked + // (i.e. `cqsr.cie == 0`). To re-enable command + // processing software should clear this bit by + // writing 1. + uint32_t fence_w_ip :1; // An IOMMU that supports only wired interrupts sets + // `fence_w_ip` bit is set to indicate completion of a + // `IOFENCE.C` command. An interrupt on setting + // `fence_w_ip` if not already pending + // (i.e. `ipsr.cip == 1`) and not masked + // (i.e. `cqsr.cie == 0`) and `fence_w_ip` is 0. // To re-enable interrupts on `IOFENCE.C` completion // software should clear this bit by writing 1. - // This bit is reserved if the IOMMU uses MSI. + // This bit is reserved if the IOMMU uses MSI. uint32_t rsvd1 :4; // Reserved for standard use uint32_t cqon :1; // The command-queue is active if `cqon` is 1. - // IOMMU behavior on changing cqb when busy is 1 or - // `cqon` is 1 is implementation defined. The software - // recommended sequence to change `cqb` is to first - // disable the command-queue by clearing cqen and - // waiting for both `busy` and `cqon` to be 0 before + // IOMMU behavior on changing cqb when busy is 1 or + // `cqon` is 1 is implementation defined. The software + // recommended sequence to change `cqb` is to first + // disable the command-queue by clearing cqen and + // waiting for both `busy` and `cqon` to be 0 before // changing the `cqb`. uint32_t busy :1; // A write to `cqcsr` may require the IOMMU to perform - // many operations that may not occur synchronously - // to the write. When a write is observed by the + // many operations that may not occur synchronously + // to the write. When a write is observed by the // `cqcsr`, the `busy` bit is set to 1. // - // When the `busy` bit is 1, behavior of additional - // writes to the `cqcsr` is implementation defined. + // When the `busy` bit is 1, behavior of additional + // writes to the `cqcsr` is implementation defined. // Some implementations may ignore the second write and - // others may perform the actions determined by the + // others may perform the actions determined by the // second write. // - // Software must verify that the busy bit is 0 before - // writing to the `cqcsr`. An IOMMU that can complete + // Software must verify that the busy bit is 0 before + // writing to the `cqcsr`. An IOMMU that can complete // controls synchronously may hard-wire this bit to 0. // - // An IOMMU that can complete these operations + // An IOMMU that can complete these operations // synchronously may hard-wire this bit to 0. uint32_t rsvd2 :10; // Reserved for standard use uint32_t custom :4; // _Designated for custom use._ @@ -471,9 +471,9 @@ typedef union { uint64_t raw; } icvec_t; -// The tr_req_iova is a 64-bit WARL register used to +// The tr_req_iova is a 64-bit WARL register used to // implement a translation-request interface for -// debug. This register is present when +// debug. This register is present when // capabilities.DBG == 1. typedef union { struct { @@ -482,41 +482,41 @@ typedef union { }; uint64_t raw; } tr_req_iova_t; -// The tr_req_ctrl is a 64-bit WARL register used to +// The tr_req_ctrl is a 64-bit WARL register used to // implement a translation-request interface for -// debug. This register is present when +// debug. This register is present when // capabilities.DBG == 1. typedef union { struct { - uint64_t go_busy:1; // This bit is set to indicate a valid request - // has been setup in the tr_req_iova/tr_req_ctrl + uint64_t go_busy:1; // This bit is set to indicate a valid request + // has been setup in the tr_req_iova/tr_req_ctrl // registers for the IOMMU to translate. - // The IOMMU indicates completion of the requested - // translation by clearing this bit to 0. On - // completion, the results of the translation are + // The IOMMU indicates completion of the requested + // translation by clearing this bit to 0. On + // completion, the results of the translation are // in tr_response register. - uint64_t Priv:1; // When set to 1 the requests needs Privileged Mode + uint64_t Priv:1; // When set to 1 the requests needs Privileged Mode // access for this translation. - uint64_t Exe:1; // When set to 1 the request needs execute access + uint64_t Exe:1; // When set to 1 the request needs execute access // for this translation. - uint64_t NW:1; // When set to 1 the request only needs read-only + uint64_t NW:1; // When set to 1 the request only needs read-only // access for this translation. uint64_t reserved0:8; // Reserved for standard use - uint64_t PID:20; // When PV is 1 this field provides the process_id for + uint64_t PID:20; // When PV is 1 this field provides the process_id for // this translation request. uint64_t PV:1; // When set to 1 the PID field of the register is valid. uint64_t reserved:3; // Reserved for standard use uint64_t custom:4; // Designated for custom use - uint64_t DID:24; // This field provides the device_id for this + uint64_t DID:24; // This field provides the device_id for this // translation request. }; uint64_t raw; } tr_req_ctrl_t; -// The tr_response is a 64-bit RO register used to hold -// the results of a translation requested using the -// translation-request interface. This register is present +// The tr_response is a 64-bit RO register used to hold +// the results of a translation requested using the +// translation-request interface. This register is present // when capabilities.DBG == 1 typedef union { struct { @@ -542,7 +542,7 @@ typedef union { // If the S bit is 0, then the size of the translation is 4 KiB - a page. // If the S bit is 1, then the translation resulted in a super-page, and // the size of the super-page is encoded in the PPN itself. If scanning - // from bit position 0 to bit position 43, the first bit with a value + // from bit position 0 to bit position 43, the first bit with a value // of 0 at position X, then the super-page size is 2X+1 * 4 KiB. // If X is not 0, then all bits at position 0 through X-1 are each // encoded with a value of 1. diff --git a/iommu_ref_model/libiommu/include/iommu_req_rsp.h b/iommu_ref_model/libiommu/include/iommu_req_rsp.h index e9814071..9461fe74 100644 --- a/iommu_ref_model/libiommu/include/iommu_req_rsp.h +++ b/iommu_ref_model/libiommu/include/iommu_req_rsp.h @@ -9,9 +9,9 @@ typedef enum { // 00 - Untranslated - IOMMU may treat the address as either virtual or physical. // 01 - Trans. Req. - The IOMMU will return the translation of the address // contained in the address field of the request as a read - // completion. - // 10 - Translated - The address in the transaction has been translated by an IOMMU. - // If the Function associated with the device_id is allowed to + // completion. + // 10 - Translated - The address in the transaction has been translated by an IOMMU. + // If the Function associated with the device_id is allowed to // present physical addresses to the system memory, then the IOMMU // might not translate this address. If the Function is not allowed // to present physical addresses, then the TA may treat this as an UR. @@ -48,22 +48,22 @@ typedef enum { // This Completion Status has a nominal meaning of “success”. SUCCESS = 0, - // A status that applies to a posted or non-posted Request - // that specifies some action or access to some space that - // is not supported by the Completer. + // A status that applies to a posted or non-posted Request + // that specifies some action or access to some space that + // is not supported by the Completer. // OR - // A status indication returned with a Completion for a + // A status indication returned with a Completion for a // non-posted Request that suffered an Unsupported Request // at the Completer. UNSUPPORTED_REQUEST = 1, - // A status that applies to a posted or non-posted Request - // that the Completer is permanently unable to complete - // successfully, due to a violation of the Completer’s + // A status that applies to a posted or non-posted Request + // that the Completer is permanently unable to complete + // successfully, due to a violation of the Completer’s // programming model or to an unrecoverable error associated // with the Completer. // OR - // A status indication returned with a Completion for a + // A status indication returned with a Completion for a // non-posted Request that suffered a Completer Abort at the // Completer. COMPLETER_ABORT = 4 diff --git a/iommu_ref_model/libiommu/include/iommu_translate.h b/iommu_ref_model/libiommu/include/iommu_translate.h index e9a096c6..4d6fa37b 100644 --- a/iommu_ref_model/libiommu/include/iommu_translate.h +++ b/iommu_ref_model/libiommu/include/iommu_translate.h @@ -81,13 +81,13 @@ typedef union { } msipte_t; -extern uint8_t -locate_device_context(device_context_t *DC, uint32_t device_id, uint8_t pid_valid, +extern uint8_t +locate_device_context(device_context_t *DC, uint32_t device_id, uint8_t pid_valid, uint32_t process_id, uint32_t *cause); -extern uint8_t -locate_process_context(process_context_t *PC, device_context_t *DC, - uint32_t device_id, uint32_t process_id, uint32_t *cause, +extern uint8_t +locate_process_context(process_context_t *PC, device_context_t *DC, + uint32_t device_id, uint32_t process_id, uint32_t *cause, uint64_t *iotval2, uint8_t TTYP); extern uint8_t @@ -97,12 +97,12 @@ two_stage_address_translation( uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, iosatp_t iosatp, uint8_t priv, uint8_t SUM, uint8_t SADE, uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL, - uint32_t *cause, uint64_t *iotval2, uint64_t *pa, + uint32_t *cause, uint64_t *iotval2, uint64_t *pa, uint64_t *page_sz, pte_t *vs_pte); extern uint8_t second_stage_address_translation( - uint64_t gpa, uint8_t check_access_perms, uint32_t DID, + uint64_t gpa, uint8_t check_access_perms, uint32_t DID, uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL, @@ -110,9 +110,9 @@ second_stage_address_translation( extern uint8_t msi_address_translation( - uint64_t gpa, uint8_t is_exec, device_context_t *DC, + uint64_t gpa, uint8_t is_exec, device_context_t *DC, uint8_t *is_msi, uint8_t *is_mrif, uint32_t *mrif_nid, uint64_t *dest_mrif_addr, - uint32_t *cause, uint64_t *iotval2, uint64_t *pa, + uint32_t *cause, uint64_t *iotval2, uint64_t *pa, uint64_t *page_sz, gpte_t *g_pte, uint8_t check_access_perms ); #endif // __IOMMU_TRANSLATE_H__ diff --git a/iommu_ref_model/libiommu/src/iommu_atc.c b/iommu_ref_model/libiommu/src/iommu_atc.c index 72cfb7b1..d8b0319e 100644 --- a/iommu_ref_model/libiommu/src/iommu_atc.c +++ b/iommu_ref_model/libiommu/src/iommu_atc.c @@ -16,10 +16,10 @@ cache_ioatc_dc( uint32_t device_id, device_context_t *DC) { uint8_t i, replace; uint32_t lru = 0xFFFFFFFF; - + for ( i = 0; i < DDT_CACHE_SIZE; i++ ) { if ( ddt_cache[i].valid == 0 ) { - replace = i; + replace = i; break; } } @@ -56,10 +56,10 @@ cache_ioatc_pc( uint32_t device_id, uint32_t process_id, process_context_t *PC) { uint8_t i, replace = 0; uint32_t lru = 0xFFFFFFFF; - + for ( i = 0; i < PDT_CACHE_SIZE; i++ ) { if ( pdt_cache[i].valid == 0 ) { - replace = i; + replace = i; break; } } @@ -82,7 +82,7 @@ lookup_ioatc_pc( uint32_t device_id, uint32_t process_id, process_context_t *PC) { uint8_t i; for ( i = 0; i < PDT_CACHE_SIZE; i++ ) { - if ( pdt_cache[i].valid == 1 && + if ( pdt_cache[i].valid == 1 && pdt_cache[i].DID == device_id && pdt_cache[i].PID == process_id ) { *PC = pdt_cache[i].PC; @@ -103,7 +103,7 @@ cache_ioatc_iotlb( for ( i = 0; i < TLB_SIZE; i++ ) { if ( tlb[i].valid == 0 ) { - replace = i; + replace = i; break; } } @@ -146,7 +146,7 @@ uint8_t lookup_ioatc_iotlb( uint64_t iova, uint8_t check_access_perms, uint8_t priv, uint8_t is_read, uint8_t is_write, uint8_t is_exec, - uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, + uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, uint32_t *cause, uint64_t *resp_pa, uint64_t *page_sz, pte_t *vs_pte, gpte_t *g_pte) { @@ -155,8 +155,8 @@ lookup_ioatc_iotlb( hit = 0xFF; for ( i = 0; i < TLB_SIZE; i++ ) { - if ( tlb[i].valid == 1 && - tlb[i].GV == GV && tlb[i].GSCID == GSCID && + if ( tlb[i].valid == 1 && + tlb[i].GV == GV && tlb[i].GSCID == GSCID && tlb[i].PSCV == PSCV && tlb[i].PSCID == PSCID && match_address_range(vpn, tlb[i].vpn, tlb[i].S) ) { hit = i; @@ -182,12 +182,12 @@ lookup_ioatc_iotlb( if ( (is_exec && (tlb[hit].G_X == 0)) || (is_read && (tlb[hit].G_R == 0)) || (is_write && (tlb[hit].G_W == 0)) ) { - // More commonly, implementations contain address-translation caches that - // map guest virtual addresses directly to supervisor physical addresses, - // removing a level of indirection. + // More commonly, implementations contain address-translation caches that + // map guest virtual addresses directly to supervisor physical addresses, + // removing a level of indirection. // If a G-stage permission fault is detected then such caches may not have - // GPA to report in the iotval2. A common technique is to treat it as a - // TLB miss and trigger a page walk such that the GPA can be reported if + // GPA to report in the iotval2. A common technique is to treat it as a + // TLB miss and trigger a page walk such that the GPA can be reported if // the fault is actually detected again by the G-stage page tables tlb[hit].valid = 0; return IOATC_MISS; diff --git a/iommu_ref_model/libiommu/src/iommu_ats.c b/iommu_ref_model/libiommu/src/iommu_ats.c index 470c70bb..c3a118c4 100644 --- a/iommu_ref_model/libiommu/src/iommu_ats.c +++ b/iommu_ref_model/libiommu/src/iommu_ats.c @@ -9,7 +9,7 @@ extern uint8_t g_iofence_wait_pending_inv; uint8_t allocate_itag( - uint8_t DSV, uint8_t DSEG, uint16_t RID, uint8_t *itag) { + uint8_t DSV, uint8_t DSEG, uint16_t RID, uint8_t *itag) { uint8_t i; for ( i = 0; i < MAX_ITAGS; i++ ) if ( itag_tracker[i].busy == 0 ) break; @@ -29,7 +29,7 @@ uint8_t any_ats_invalidation_requests_pending() { uint8_t i; for ( i = 0; i < MAX_ITAGS; i++ ) - if ( itag_tracker[i].busy == 1 ) + if ( itag_tracker[i].busy == 1 ) return 1; return 0; } @@ -40,7 +40,7 @@ do_pending_iofence_inval_reqs() { itags_busy = 0; // Check if there are more pending invalidations for ( i = 0; i < MAX_ITAGS; i++ ) { - if ( itag_tracker[i].busy == 1 ) + if ( itag_tracker[i].busy == 1 ) itags_busy = 1; } // No more pending invalidations - continue any pending IOFENCE.C @@ -65,14 +65,14 @@ handle_invalidation_completion( cc = get_bits(34, 32, inv_cc->PAYLOAD); for ( i = 0; i < MAX_ITAGS; i++ ) { if ( itag_vector & (1UL << i) ) { - if ( itag_tracker[i].busy == 0 ) + if ( itag_tracker[i].busy == 0 ) return 1; // Unexpected completion if ( (itag_tracker[i].DSV == 1) && (inv_cc->DSV != 1 || inv_cc->DSEG != itag_tracker[i].DSEG) ) return 1; // Unexpected completion if ( itag_tracker[i].RID != inv_cc->RID ) return 1; // Unexpected completion - itag_tracker[i].num_rsp_rcvd = + itag_tracker[i].num_rsp_rcvd = (itag_tracker[i].num_rsp_rcvd + 1) & 0x07; if ( itag_tracker[i].num_rsp_rcvd == cc ) { itag_tracker[i].busy = 0; @@ -162,9 +162,9 @@ handle_page_request( } // To process a "Page Request" or "Stop Marker" message, the IOMMU first // locates the device-context to determine if ATS and PRI are enabled for - // the requestor. + // the requestor. if ( locate_device_context(&DC, device_id, pr->PV, pr->PID, &cause) ) { - report_fault(cause, PAGE_REQ_MSG_CODE, 0, PCIE_MESSAGE_REQUEST, 0, + report_fault(cause, PAGE_REQ_MSG_CODE, 0, PCIE_MESSAGE_REQUEST, 0, device_id, pr->PV, pr->PID, pr->PRIV); response_code = RESPONSE_FAILURE; goto send_prgr; @@ -179,17 +179,17 @@ handle_page_request( response_code = INVALID_REQUEST; goto send_prgr; } - // If ATS and PRI are enabled, i.e. EN_ATS and EN_PRI are both set to 1, - // the IOMMU queues the message into an in-memory queue called the page - // request-queue (PQ) (See Section 3.3). + // If ATS and PRI are enabled, i.e. EN_ATS and EN_PRI are both set to 1, + // the IOMMU queues the message into an in-memory queue called the page + // request-queue (PQ) (See Section 3.3). // When PRI is enabled for a device, the IOMMU may still be unable to report - // "Page Request" or "Stop Marker" messages through the PQ due to error - // conditions such as the queue being disabled, queue being full, or the + // "Page Request" or "Stop Marker" messages through the PQ due to error + // conditions such as the queue being disabled, queue being full, or the // IOMMU encountering access faults when attempting to access queue memory. - // The page-request-queue enable bit enables the - // page-request-queue when set to 1. - // The page-request-queue is active if pqon reads 1. + // The page-request-queue enable bit enables the + // page-request-queue when set to 1. + // The page-request-queue is active if pqon reads 1. // The IOMMU may respond to “Page Request” messages received // when page-request-queue is off or in the process of being turned // off, as specified in Section 2.8. @@ -199,7 +199,7 @@ handle_page_request( } // The pqmf bit is set to 1 if the IOMMU encounters an access fault - // when storing a page-request to the page-request queue. + // when storing a page-request to the page-request queue. // The "Page Request" message that caused the pqmf or pqof error and // all subsequent page-request messages are discarded till software // clears the pqof and/or pqmf bits by writing 1 to it. @@ -227,37 +227,37 @@ handle_page_request( goto send_prgr; } - // Page-request queue is an in-memory queue data structure used to report - // PCIe ATS “Page Request” and "Stop Marker" messages to software. The base - // PPN of this in-memory queue and the size of the queue is configured into - // a memory-mapped register called page-request queue base (pqb). Each Page - // Request record is 16 bytes. The tail of the queue resides in a IOMMU - // controlled read-only memory-mapped register called pqt. The pqt holds an - // index into the queue where the next page-request message will be written + // Page-request queue is an in-memory queue data structure used to report + // PCIe ATS “Page Request” and "Stop Marker" messages to software. The base + // PPN of this in-memory queue and the size of the queue is configured into + // a memory-mapped register called page-request queue base (pqb). Each Page + // Request record is 16 bytes. The tail of the queue resides in a IOMMU + // controlled read-only memory-mapped register called pqt. The pqt holds an + // index into the queue where the next page-request message will be written // by the IOMMU. Subsequent to writing the message, the IOMMU advances the pqt by 1. - // The head of the queue resides in a software controlled read/write memory-mapped - // register called pqh. The pqh holds an index into the queue where the next - // page-request message will be received by software. Subsequent to processing - // the message(s) software advances the pqh by the count of the number of messages + // The head of the queue resides in a software controlled read/write memory-mapped + // register called pqh. The pqh holds an index into the queue where the next + // page-request message will be received by software. Subsequent to processing + // the message(s) software advances the pqh by the count of the number of messages // processed. // If pqh == pqt, the page-request queue is empty. // If pqt == (pqh - 1) the page-request queue is full. - // The IOMMU may be unable to report "Page Request" messages through the queue - // due to error conditions such as the queue being disabled, queue being full, or - // the IOMMU encountering access faults when attempting to access queue memory. A - // memory-mapped page-request queue control and status register (pqcsr) is used to - // hold information about such faults. On a page queue full condition the - // page-request-queue overflow (pqof) bit is set in pqcsr. If the IOMMU encountered - // a fault in accessing the queue memory, page-request-queue memory access fault + // The IOMMU may be unable to report "Page Request" messages through the queue + // due to error conditions such as the queue being disabled, queue being full, or + // the IOMMU encountering access faults when attempting to access queue memory. A + // memory-mapped page-request queue control and status register (pqcsr) is used to + // hold information about such faults. On a page queue full condition the + // page-request-queue overflow (pqof) bit is set in pqcsr. If the IOMMU encountered + // a fault in accessing the queue memory, page-request-queue memory access fault // (pqmf) bit in pqcsr. While either error bits are set in pqcsr, the IOMMU discards // all subsequent "Page Request" messages; including the message that caused the error - // bits to be set. "Page request" messages that do not require a response, i.e. those + // bits to be set. "Page request" messages that do not require a response, i.e. those // with the "Last Request in PRG" field is 0, are silently discarded. "Page request" - // messages that require a response, i.e. those with "Last Request in PRG" field set - // to 1 and are not Stop Marker messages, may be auto-completed by an IOMMU generated + // messages that require a response, i.e. those with "Last Request in PRG" field set + // to 1 and are not Stop Marker messages, may be auto-completed by an IOMMU generated // “Page Request Group Response” message as specified in Section 2.8. // When an error bit is in the pqcsr changes state from 0 to 1 or when a new message - // is produced in the queue, page-request-queue interrupt pending (pip) bit is set + // is produced in the queue, page-request-queue interrupt pending (pip) bit is set // in the pqcsr pqh = g_reg_file.pqh.index; pqt = g_reg_file.pqt.index; @@ -291,21 +291,21 @@ handle_page_request( return; send_prgr: - // If EN_PRI is set to 0, or EN_ATS is set to 0, or if the IOMMU is unable to - // locate the DC to determine the EN_PRI configuration, or the request could not + // If EN_PRI is set to 0, or EN_ATS is set to 0, or if the IOMMU is unable to + // locate the DC to determine the EN_PRI configuration, or the request could not // be queued into PQ then the IOMMU behavior depends on the type of "Page Request". - // * If the "Page Request" does not require a response, i.e. the "Last Request in - // PRG" field of the message is set to 0, then such message are silently discarded. - // "Stop Marker" messages do not require a response and are always silently - // discarded on such errors. - // * If the "Page Request" needs a response, then the IOMMU itself may generate a + // * If the "Page Request" does not require a response, i.e. the "Last Request in + // PRG" field of the message is set to 0, then such message are silently discarded. + // "Stop Marker" messages do not require a response and are always silently + // discarded on such errors. + // * If the "Page Request" needs a response, then the IOMMU itself may generate a // "Page Request Group Response" message to the device. // The payload of a "Page Request" is as follows // +0 | +1 | +2 | +3 | // | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0| // 08h| Page Address [63:32] | // 0Ch| Page Address [31:12] | PRGI |L W R| - // When the IOMMU generates the response, the status field of the response depends + // When the IOMMU generates the response, the status field of the response depends // on the cause of the error. // The status is set to Response Failure if the following faults are encountered: // * All inbound transactions disallowed (cause = 256) @@ -316,8 +316,8 @@ handle_page_request( // * Page-request queue encountered a memory access fault (pqcsr.pqmf == 1) // The status is set to Invalid Request if the following faults are encountered: // * Transaction type disallowed (cause = 260) - // The status is set to Success if no other faults were encountered but the - // "Page Request" could not be queued due to the page-request queue being full + // The status is set to Success if no other faults were encountered but the + // "Page Request" could not be queued due to the page-request queue being full // (pqh == pqt - 1) or had a overflow (pqcsr.pqof == 1). R = get_bits(0, 0, pr->PAYLOAD); W = get_bits(1, 1, pr->PAYLOAD); @@ -334,11 +334,11 @@ handle_page_request( prgr.PRIV = 0; prgr.EXEC_REQ = 0; - // For IOMMU generated "Page Request Group Response" messages that have status - // Invalid Request or Success, the PRG-response-PASID-required (PRPR) bit when + // For IOMMU generated "Page Request Group Response" messages that have status + // Invalid Request or Success, the PRG-response-PASID-required (PRPR) bit when // set to 1 indicates that the IOMMU response message should include a PASID if - // the associated "Page Request" had a PASID. For IOMMU generated "Page Request - // Group Response" with response code set to Response Failure, if the "Page Request" + // the associated "Page Request" had a PASID. For IOMMU generated "Page Request + // Group Response" with response code set to Response Failure, if the "Page Request" // had a PASID then response is generated with a PASID. if ( response_code == INVALID_REQUEST || response_code == SUCCESS ) { if ( PRPR == 1 ) { @@ -358,10 +358,9 @@ handle_page_request( // 0Ch| Destination device ID | Resp |RSVD | PRGI | // | | Code | // 08h| Reserved | - prgr.PAYLOAD = ((uint64_t)pr->RID << 48UL) | - ((uint64_t)response_code << 44UL) | + prgr.PAYLOAD = ((uint64_t)pr->RID << 48UL) | + ((uint64_t)response_code << 44UL) | ((uint64_t)PRGI << 32UL); send_msg_iommu_to_hb(&prgr); return; } - diff --git a/iommu_ref_model/libiommu/src/iommu_command_queue.c b/iommu_ref_model/libiommu/src/iommu_command_queue.c index d25d6565..83c46621 100644 --- a/iommu_ref_model/libiommu/src/iommu_command_queue.c +++ b/iommu_ref_model/libiommu/src/iommu_command_queue.c @@ -6,12 +6,12 @@ uint8_t g_command_queue_stall_for_itag = 0; uint8_t g_ats_inv_req_timeout = 0; uint8_t g_iofence_wait_pending_inv = 0; -uint8_t g_iofence_pending_PR, g_iofence_pending_PW, g_iofence_pending_AV, g_iofence_pending_WSI_BIT; -uint64_t g_iofence_pending_ADDR; +uint8_t g_iofence_pending_PR, g_iofence_pending_PW, g_iofence_pending_AV, g_iofence_pending_WSI_BIT; +uint64_t g_iofence_pending_ADDR; uint32_t g_iofence_pending_DATA; -uint8_t g_pending_inval_req_DSV; -uint8_t g_pending_inval_req_DSEG; +uint8_t g_pending_inval_req_DSV; +uint8_t g_pending_inval_req_DSEG; uint16_t g_pending_inval_req_RID; uint8_t g_pending_inval_req_PV; uint32_t g_pending_inval_req_PID; @@ -24,28 +24,28 @@ process_commands( uint64_t a; command_t command; - // Command queue is used by software to queue commands to be processed by + // Command queue is used by software to queue commands to be processed by // the IOMMU. Each command is 16 bytes. - // The PPN of the base of this in-memory queue and the size of the queue + // The PPN of the base of this in-memory queue and the size of the queue // is configured into a memorymapped register called command-queue base (cqb). // The tail of the command-queue resides in a software controlled read/write // memory-mapped register called command-queue tail (cqt). The cqt is an index - // into the next command queue entry that software will write. Subsequent to + // into the next command queue entry that software will write. Subsequent to // writing the command(s), software advances the cqt by the count of the number - // of commands written. The head of the command-queue resides in a read-only + // of commands written. The head of the command-queue resides in a read-only // memory-mapped IOMMU controlled register called command-queue head (cqh). The - // cqh is an index into the command queue that IOMMU should process next. - // + // cqh is an index into the command queue that IOMMU should process next. + // - // If command-queue access leads to a memory fault then the - // command-queue-memory-fault cqmf bit is set to 1 + // If command-queue access leads to a memory fault then the + // command-queue-memory-fault cqmf bit is set to 1 // If the execution of a command leads to a timeout (e.g. a command to invalidate - // device ATC may timeout waiting for a completion), then the command-queue + // device ATC may timeout waiting for a completion), then the command-queue // sets the cmd_to bit. - // If an illegal or unsupported command is fetched and decoded by the + // If an illegal or unsupported command is fetched and decoded by the // command-queue then the command-queue sets the cmd_ill bit - // If any of these bits are set then CQ stops processing from the - // command-queue. + // If any of these bits are set then CQ stops processing from the + // command-queue. // The command-queue is active if cqon is 1. // Sometimes the command queue may stall due to unavailability of internal // resources - e.g. ITAG trackers @@ -57,7 +57,7 @@ process_commands( (g_iofence_wait_pending_inv != 0) ) return; - // If cqh == cqt, the command-queue is empty. + // If cqh == cqt, the command-queue is empty. // If cqt == (cqh - 1) the command-queue is full. if ( g_reg_file.cqh.index == g_reg_file.cqt.index ) return; @@ -69,7 +69,7 @@ process_commands( // command-queue-memory-fault bit is set to 1 and the command // queue stalls until this bit is cleared. When cqmf is set to 1, an // interrupt is generated if an interrupt is not already pending (i.e., - // ipsr.cip == 1) and not masked (i.e. cqsr.cie == 0). To reenable + // ipsr.cip == 1) and not masked (i.e. cqsr.cie == 0). To reenable // command processing, software should clear this bit by writing 1 if ( g_reg_file.cqcsr.cqmf == 0 ) { g_reg_file.cqcsr.cqmf = 1; @@ -79,28 +79,28 @@ process_commands( return; } - // IOMMU commands are grouped into a major command group determined by the - // opcode and within each group the func3 field specifies the function invoked - // by that command. The opcode defines the format of the operand fields. One + // IOMMU commands are grouped into a major command group determined by the + // opcode and within each group the func3 field specifies the function invoked + // by that command. The opcode defines the format of the operand fields. One // or more of those fields may be used by the specific function invoked. // A command is determined to be illegal if it uses a reserved encoding or if a // reserved bit is set to 1. A command is unsupported if it is defined but not - // implemented as determined by the IOMMU capabilities register. + // implemented as determined by the IOMMU capabilities register. switch ( command.any.opcode ) { case IOTINVAL: - if ( command.iotinval.rsvd != 0 || command.iotinval.rsvd1 != 0 || - command.iotinval.rsvd2 != 0 || command.iotinval.rsvd3 != 0 || + if ( command.iotinval.rsvd != 0 || command.iotinval.rsvd1 != 0 || + command.iotinval.rsvd2 != 0 || command.iotinval.rsvd3 != 0 || command.iotinval.rsvd4 != 0 ) goto command_illegal; switch ( command.any.func3 ) { case VMA: - do_iotinval_vma(command.iotinval.gv, command.iotinval.av, - command.iotinval.pscv, command.iotinval.gscid, + do_iotinval_vma(command.iotinval.gv, command.iotinval.av, + command.iotinval.pscv, command.iotinval.gscid, command.iotinval.pscid, command.iotinval.addr_63_12); break; case GVMA: // Setting PSCV to 1 with IOTINVAL.GVMA is illegal. if ( command.iotinval.pscv != 0 ) goto command_illegal; - do_iotinval_gvma(command.iotinval.gv, command.iotinval.av, + do_iotinval_gvma(command.iotinval.gv, command.iotinval.av, command.iotinval.gscid, command.iotinval.addr_63_12); break; default: goto command_illegal; @@ -108,7 +108,7 @@ process_commands( break; case IODIR: if ( command.iodir.rsvd != 0 || command.iodir.rsvd1 != 0 || - command.iodir.rsvd2 != 0 || command.iodir.rsvd3 != 0 ) + command.iodir.rsvd2 != 0 || command.iodir.rsvd3 != 0 ) goto command_illegal; switch ( command.any.func3 ) { case INVAL_DDT: @@ -117,7 +117,7 @@ process_commands( if ( command.iodir.pid != 0 ) goto command_illegal; // When DV operand is 1, the value of the DID operand must not // be wider than that supported by the ddtp.iommu_mode. - if ( command.iodir.dv && + if ( command.iodir.dv && (command.iodir.did & ~g_max_devid_mask) ) { goto command_illegal; } @@ -135,12 +135,12 @@ process_commands( goto command_illegal; // The PID operand of IODIR.INVAL_PDT must not be wider than // the width supported by the IOMMU (see Section 5.3) - if ( g_reg_file.capabilities.pd20 == 0 && + if ( g_reg_file.capabilities.pd20 == 0 && command.iodir.pid > ((1UL << 17) - 1) ) { goto command_illegal; } - if ( g_reg_file.capabilities.pd20 == 0 && - g_reg_file.capabilities.pd17 == 0 && + if ( g_reg_file.capabilities.pd20 == 0 && + g_reg_file.capabilities.pd17 == 0 && command.iodir.pid > ((1UL << 8) - 1) ) { goto command_illegal; } @@ -150,18 +150,18 @@ process_commands( } break; case IOFENCE: - if ( command.iofence.reserved != 0 || command.iofence.reserved1 != 0 ) + if ( command.iofence.reserved != 0 || command.iofence.reserved1 != 0 ) goto command_illegal; - // The wired-signaled-interrupt (WSI) bit when set to 1 + // The wired-signaled-interrupt (WSI) bit when set to 1 // causes a wired-interrupt from the command // queue to be generated on completion of IOFENCE.C. This // bit is reserved if the IOMMU supports MSI. - if ( g_reg_file.fctl.wsi == 0 && command.iofence.wsi == 1) + if ( g_reg_file.fctl.wsi == 0 && command.iofence.wsi == 1) goto command_illegal; switch ( command.any.func3 ) { case IOFENCE_C: - if ( do_iofence_c(command.iofence.pr, command.iofence.pw, - command.iofence.av, command.iofence.wsi, + if ( do_iofence_c(command.iofence.pr, command.iofence.pw, + command.iofence.av, command.iofence.wsi, (command.iofence.addr_63_2 << 2UL), command.iofence.data) ) { // If IOFENCE encountered a memory fault or timeout // then do not advance the CQH @@ -178,12 +178,12 @@ process_commands( switch ( command.any.func3 ) { case INVAL: // Allocate a ITAG for the request - if ( allocate_itag(command.ats.dsv, command.ats.dseg, - command.ats.rid, &itag) ) { + if ( allocate_itag(command.ats.dsv, command.ats.dseg, + command.ats.rid, &itag) ) { // No ITAG available, This command stays pending // but since the reference implementation only // has one deep pending command buffer the CQ - // is now stall till a completion or a timeout + // is now stall till a completion or a timeout // frees up pending ITAGs. g_pending_inval_req_DSV = command.ats.dsv; g_pending_inval_req_DSEG = command.ats.dseg; @@ -194,12 +194,12 @@ process_commands( g_command_queue_stall_for_itag = 1; } else { // ITAG allocated successfully, send invalidate request - do_ats_msg(INVAL_REQ_MSG_CODE, itag, command.ats.dsv, command.ats.dseg, + do_ats_msg(INVAL_REQ_MSG_CODE, itag, command.ats.dsv, command.ats.dseg, command.ats.rid, command.ats.pv, command.ats.pid, command.ats.payload); } break; case PRGR: - do_ats_msg(PRGR_MSG_CODE, 0, command.ats.dsv, command.ats.dseg, + do_ats_msg(PRGR_MSG_CODE, 0, command.ats.dsv, command.ats.dseg, command.ats.rid, command.ats.pv, command.ats.pid, command.ats.payload); break; default: goto command_illegal; @@ -211,7 +211,7 @@ process_commands( // controlled register called command-queue head (`cqh`). The `cqh` is an index // into the command queue that IOMMU should process next. Subsequent to reading // each command the IOMMU may advance the `cqh` by 1. - g_reg_file.cqh.index = + g_reg_file.cqh.index = (g_reg_file.cqh.index + 1) & ((1UL << (g_reg_file.cqb.log2szm1 + 1)) - 1); return; @@ -220,7 +220,7 @@ process_commands( // the command-queue then the command-queue sets the cmd_ill // bit and stops processing from the command-queue. When cmd_ill // is set to 1, an interrupt is generated if not already pending (i.e. - // ipsr.cip == 1) and not masked (i.e. cqsr.cie == 0). To reenable + // ipsr.cip == 1) and not masked (i.e. cqsr.cie == 0). To reenable // command processing software should clear this bit by writing 1 if ( g_reg_file.cqcsr.cmd_ill == 0 ) { g_reg_file.cqcsr.cmd_ill = 1; @@ -232,13 +232,13 @@ void do_inval_ddt( uint8_t DV, uint32_t DID) { uint8_t i; - // IOMMU operations cause implicit reads to DDT and/or PDT. - // To reduce latency of such reads, the IOMMU may cache entries from - // the DDT and/or PDT in IOMMU directory caches. These caches may not + // IOMMU operations cause implicit reads to DDT and/or PDT. + // To reduce latency of such reads, the IOMMU may cache entries from + // the DDT and/or PDT in IOMMU directory caches. These caches may not // observe modifications performed by software to these data structures // in memory. - // The IOMMU DDT cache invalidation command, `IODIR.INVAL_DDT` - // synchronize updates to DDT with the operation of the IOMMU and + // The IOMMU DDT cache invalidation command, `IODIR.INVAL_DDT` + // synchronize updates to DDT with the operation of the IOMMU and // flushes the matching cached entries. // The `DV` operand indicates if the device ID (`DID`) operand is valid. // `IODIR.INVAL_DDT` guarantees that any previous stores made by a RISC-V hart to @@ -250,7 +250,7 @@ do_inval_ddt( for ( i = 0; i < DDT_CACHE_SIZE; i++ ) { if ( ddt_cache[i].valid == 0 ) continue; if ( DV == 0 ) ddt_cache[i].valid = 0; - if ( DV == 1 && (ddt_cache[i].DID == DID) ) + if ( DV == 1 && (ddt_cache[i].DID == DID) ) ddt_cache[i].valid = 0; } return; @@ -260,9 +260,9 @@ do_inval_pdt( uint32_t DID, uint32_t PID) { int i; - // IOMMU operations cause implicit reads to DDT and/or PDT. - // To reduce latency of such reads, the IOMMU may cache entries from - // the DDT and/or PDT in IOMMU directory caches. These caches may not + // IOMMU operations cause implicit reads to DDT and/or PDT. + // To reduce latency of such reads, the IOMMU may cache entries from + // the DDT and/or PDT in IOMMU directory caches. These caches may not // observe modifications performed by software to these data structures // in memory. // The IOMMU PDT cache invalidation command, `IODIR.INVAL_PDT` synchronize @@ -274,34 +274,34 @@ do_inval_pdt( // The command invalidates cached leaf PDT entry for the specified `PID` and `DID`. for ( i = 0; i < PDT_CACHE_SIZE; i++ ) - if ( pdt_cache[i].DID == DID && pdt_cache[i].PID == PID && pdt_cache[i].valid == 1) + if ( pdt_cache[i].DID == DID && pdt_cache[i].PID == PID && pdt_cache[i].valid == 1) pdt_cache[i].valid = 0; return; } -void +void do_iotinval_vma( uint8_t GV, uint8_t AV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, uint64_t ADDR_63_12) { - // IOMMU operations cause implicit reads to PDT, first-stage and second-stage - // page tables. To reduce latency of such reads, the IOMMU may cache entries - // from the first and/or second-stage page tables in the - // IOMMU-address-translation-cache (IOATC). These caches may not observe + // IOMMU operations cause implicit reads to PDT, first-stage and second-stage + // page tables. To reduce latency of such reads, the IOMMU may cache entries + // from the first and/or second-stage page tables in the + // IOMMU-address-translation-cache (IOATC). These caches may not observe // modifications performed by software to these data structures in memory. - // The IOMMU translation-table cache invalidation commands, IOTINVAL.VMA - // and IOTINVAL.GVMA synchronize updates to in-memory S/VS-stage and G-stage + // The IOMMU translation-table cache invalidation commands, IOTINVAL.VMA + // and IOTINVAL.GVMA synchronize updates to in-memory S/VS-stage and G-stage // page table data structures with the operation of the IOMMU and invalidate // the matching IOATC entries. - // The GV operand indicates if the Guest-Soft-Context ID (GSCID) operand is + // The GV operand indicates if the Guest-Soft-Context ID (GSCID) operand is // valid. The PSCV operand indicates if the Process Soft-Context ID (PSCID) // operand is valid. Setting PSCV to 1 is allowed only for IOTINVAL.VMA. The // AV operand indicates if the address (ADDR) operand is valid. When GV is 0, - // the translations associated with the host (i.e. those where the + // the translations associated with the host (i.e. those where the // second-stage translation is not active) are operated on. - // IOTINVAL.VMA ensures that previous stores made to the first-stage page - // tables by the harts are observed by the IOMMU before all subsequent + // IOTINVAL.VMA ensures that previous stores made to the first-stage page + // tables by the harts are observed by the IOMMU before all subsequent // implicit reads from IOMMU to the corresponding firststage page tables. - // + // // .`IOTINVAL.VMA` operands and operations // |`GV`|`AV`|`PSCV`| Operation // |0 |0 |0 | Invalidates all address-translation cache entries, including @@ -311,8 +311,8 @@ do_iotinval_vma( // host address space identified by `PSCID` operand, except for // entries containing global mappings. // |0 |1 |0 | Invalidates all address-translation cache entries that - // contain leaf page table entries, including those that contain - // global mappings, corresponding to the IOVA in `ADDR` operand, + // contain leaf page table entries, including those that contain + // global mappings, corresponding to the IOVA in `ADDR` operand, // for all host address spaces. // |0 |1 |1 | Invalidates all address-translation cache entries that // contain leaf page table entries corresponding to the IOVA in @@ -326,8 +326,8 @@ do_iotinval_vma( // for the VM address space identified by `PSCID` and `GSCID` // operands, except for entries containing global mappings. // |1 |1 |0 | Invalidates all address-translation cache entries that - // contain leaf page table entries, including those that contain - // global mappings, corresponding to the IOVA in `ADDR` operand, + // contain leaf page table entries, including those that contain + // global mappings, corresponding to the IOVA in `ADDR` operand, // for all VM address spaces associated with the `GSCID` operand. // |1 |1 |1 | Invalidates all address-translation cache entries that // contain leaf page table entries corresponding to the IOVA in @@ -345,7 +345,7 @@ do_iotinval_vma( if ( (PSCV == 0) || (PSCV == 1 && tlb[i].PSCV == 1 && tlb[i].PSCID == PSCID) ) pscid_match = 1; - if ( (PSCV == 0) || + if ( (PSCV == 0) || (PSCV == 1 && tlb[i].G == 0) ) global_match = 1; if ( (AV == 0) || @@ -362,23 +362,23 @@ do_iotinval_gvma( uint8_t i, gscid_match, addr_match; // Conceptually, an implementation might contain two address-translation - // caches: one that maps guest virtual addresses to guest physical addresses, - // and another that maps guest physical addresses to supervisor physical - // addresses. IOTINVAL.GVMA need not flush the former cache, but it must - // flush entries from the latter cache that match the IOTINVAL.GVMA’s + // caches: one that maps guest virtual addresses to guest physical addresses, + // and another that maps guest physical addresses to supervisor physical + // addresses. IOTINVAL.GVMA need not flush the former cache, but it must + // flush entries from the latter cache that match the IOTINVAL.GVMA’s // address and GSCID arguments. - // More commonly, implementations contain address-translation caches - // that map guest virtual addresses directly to supervisor physical - // addresses, removing a level of indirection. For such implementations, + // More commonly, implementations contain address-translation caches + // that map guest virtual addresses directly to supervisor physical + // addresses, removing a level of indirection. For such implementations, // any entry whose guest virtual address maps to a guest physical address that - // matches the IOTINVAL.GVMA’s address and GSCID arguments must be flushed. - // Selectively flushing entries in this fashion requires tagging them with - // the guest physical address, which is costly, and so a common technique - // is to flush all entries that match the IOTINVAL.GVMA’s GSCID argument, + // matches the IOTINVAL.GVMA’s address and GSCID arguments must be flushed. + // Selectively flushing entries in this fashion requires tagging them with + // the guest physical address, which is costly, and so a common technique + // is to flush all entries that match the IOTINVAL.GVMA’s GSCID argument, // regardless of the address argument. - // IOTINVAL.GVMA ensures that previous stores made to the G-stage page - // tables are observed before all subsequent implicit reads from IOMMU - // to the corresponding G-stage page tables. Setting PSCV to 1 with + // IOTINVAL.GVMA ensures that previous stores made to the G-stage page + // tables are observed before all subsequent implicit reads from IOMMU + // to the corresponding G-stage page tables. Setting PSCV to 1 with // IOTINVAL.GVMA is illegal. // .`IOTINVAL.GVMA` operands and operations // | `GV` | `AV` | Operation @@ -397,10 +397,10 @@ do_iotinval_gvma( (GV == 1 && tlb[i].GV == 1 && tlb[i].GSCID == GSCID) ) gscid_match = 1; // If the cache holds a VA -> SPA translation i.e. PSCV == 1 then invalidate - // it. If PSCV is 0 then it holds a GPA. If AV is 0 then all entries are + // it. If PSCV is 0 then it holds a GPA. If AV is 0 then all entries are // eligible else match the address if ( (tlb[i].PSCV == 1) || (AV == 0) || - (tlb[i].PSCV == 0 && AV == 1 && match_address_range(ADDR_63_12, tlb[i].vpn, tlb[i].S)) ) + (tlb[i].PSCV == 0 && AV == 1 && match_address_range(ADDR_63_12, tlb[i].vpn, tlb[i].S)) ) addr_match = 1; if ( gscid_match && addr_match ) tlb[i].valid = 0; @@ -409,24 +409,24 @@ do_iotinval_gvma( } void do_ats_msg( - uint8_t MSGCODE, uint8_t TAG, uint8_t DSV, uint8_t DSEG, uint16_t RID, + uint8_t MSGCODE, uint8_t TAG, uint8_t DSV, uint8_t DSEG, uint16_t RID, uint8_t PV, uint32_t PID, uint64_t PAYLOAD) { ats_msg_t msg; - // The ATS.INVAL command instructs the IOMMU to send a “Invalidation Request” message - // to the PCIe device function identified by RID. An “Invalidation Request” message - // is used to clear a specific subset of the address range from the address translation - // cache in a device function. The ATS.INVAL command completes when an “Invalidation - // Completion” response message is received from the device or a protocol defined - // timeout occurs while waiting for a response. The IOMMU may advance the cqh and fetch + // The ATS.INVAL command instructs the IOMMU to send a “Invalidation Request” message + // to the PCIe device function identified by RID. An “Invalidation Request” message + // is used to clear a specific subset of the address range from the address translation + // cache in a device function. The ATS.INVAL command completes when an “Invalidation + // Completion” response message is received from the device or a protocol defined + // timeout occurs while waiting for a response. The IOMMU may advance the cqh and fetch // more commands from CQ while a response is awaited. - // The ATS.PRGR command instructs the IOMMU to send a “Page Request Group Response” - // message to the PCIe device function identified by the RID. The “Page Request Group - // Response” message is used by system hardware and/or software to communicate with the + // The ATS.PRGR command instructs the IOMMU to send a “Page Request Group Response” + // message to the PCIe device function identified by the RID. The “Page Request Group + // Response” message is used by system hardware and/or software to communicate with the // device functions page-request interface to signal completion of a “Page Request”, or // the catastrophic failure of the interface.If the PV operand is set to 1, the message - // is generated with a PASID with the PASID field set to the PID operand. The PAYLOAD + // is generated with a PASID with the PASID field set to the PID operand. The PAYLOAD // operand of the command is used to form the message body. - // If the DSV operand is 1, then a valid destination segment number is specified by + // If the DSV operand is 1, then a valid destination segment number is specified by // the DSEG operand. msg.MSGCODE = MSGCODE; msg.TAG = TAG; @@ -447,8 +447,8 @@ do_iofence_c( uint8_t status; // The IOMMU fetches commands from the CQ in order but the IOMMU may execute the fetched - // commands out of order. The IOMMU advancing cqh is not a guarantee that the commands - // fetched by the IOMMU have been executed or committed. A IOFENCE.C command guarantees + // commands out of order. The IOMMU advancing cqh is not a guarantee that the commands + // fetched by the IOMMU have been executed or committed. A IOFENCE.C command guarantees // that all previous commands fetched from the CQ have been completed and committed. g_iofence_wait_pending_inv = 1; if ( any_ats_invalidation_requests_pending() ) { @@ -458,8 +458,8 @@ do_iofence_c( g_iofence_pending_PR = PR; g_iofence_pending_PW = PW; g_iofence_pending_AV = AV; - g_iofence_pending_WSI_BIT = WSI_BIT; - g_iofence_pending_ADDR = ADDR; + g_iofence_pending_WSI_BIT = WSI_BIT; + g_iofence_pending_ADDR = ADDR; g_iofence_pending_DATA = DATA; return 1; } @@ -475,9 +475,9 @@ do_iofence_c( return 1; } // The commands may be used to order memory accesses from I/O devices connected to the IOMMU - // as viewed by the IOMMU, other RISC-V harts, and external devices or co-processors. The - // PR and PW bits can be used to request that the IOMMU ensure that all previous requests - // from devices that have already been processed by the IOMMU be committed to a global + // as viewed by the IOMMU, other RISC-V harts, and external devices or co-processors. The + // PR and PW bits can be used to request that the IOMMU ensure that all previous requests + // from devices that have already been processed by the IOMMU be committed to a global // ordering point such that they can be observed by all RISC-V harts and IOMMUs in the machine. if ( PR == 1 || PW == 1 ) iommu_to_hb_do_global_observability_sync(PR, PW); @@ -488,8 +488,8 @@ do_iofence_c( g_reg_file.cqcsr.fence_w_ip = 1; generate_interrupt(COMMAND_QUEUE); } - // The AV command operand indicates if ADDR[63:2] operand and DATA operands are valid. - // If AV=1, the IOMMU writes DATA to memory at a 4-byte aligned address ADDR[63:2] * 4 as + // The AV command operand indicates if ADDR[63:2] operand and DATA operands are valid. + // If AV=1, the IOMMU writes DATA to memory at a 4-byte aligned address ADDR[63:2] * 4 as // a 4-byte store. if ( AV == 1 ) { status = write_memory((char *)&DATA, ADDR, 4); @@ -506,26 +506,26 @@ do_iofence_c( // Retry a pending IOFENCE if all invalidations received void do_pending_iofence() { - if ( do_iofence_c(g_iofence_pending_PR, g_iofence_pending_PW, g_iofence_pending_AV, + if ( do_iofence_c(g_iofence_pending_PR, g_iofence_pending_PW, g_iofence_pending_AV, g_iofence_pending_WSI_BIT, g_iofence_pending_ADDR, g_iofence_pending_DATA) == 0 ) { // If not still pending then advance the CQH - g_reg_file.cqh.index = + g_reg_file.cqh.index = (g_reg_file.cqh.index + 1) & ((1UL << (g_reg_file.cqb.log2szm1 + 1)) - 1); } return; } -void +void queue_any_blocked_ats_inval_req() { uint8_t itag; if ( g_command_queue_stall_for_itag == 1 ) { // Allocate a ITAG for the request - if ( allocate_itag(g_pending_inval_req_DSV, g_pending_inval_req_DSEG, + if ( allocate_itag(g_pending_inval_req_DSV, g_pending_inval_req_DSEG, g_pending_inval_req_RID, &itag) ) return; // ITAG allocated successfully, send invalidate request - do_ats_msg(INVAL_REQ_MSG_CODE, itag, g_pending_inval_req_DSV, - g_pending_inval_req_DSEG, g_pending_inval_req_RID, - g_pending_inval_req_PV, g_pending_inval_req_PID, + do_ats_msg(INVAL_REQ_MSG_CODE, itag, g_pending_inval_req_DSV, + g_pending_inval_req_DSEG, g_pending_inval_req_RID, + g_pending_inval_req_PV, g_pending_inval_req_PID, g_pending_inval_req_PAYLOAD); // Remove the command queue stall g_command_queue_stall_for_itag = 0; diff --git a/iommu_ref_model/libiommu/src/iommu_device_context.c b/iommu_ref_model/libiommu/src/iommu_device_context.c index 22e2e01f..d8cb223c 100644 --- a/iommu_ref_model/libiommu/src/iommu_device_context.c +++ b/iommu_ref_model/libiommu/src/iommu_device_context.c @@ -8,7 +8,7 @@ uint8_t do_device_context_configuration_checks(device_context_t *DC); uint8_t locate_device_context( - device_context_t *DC, uint32_t device_id, + device_context_t *DC, uint32_t device_id, uint8_t pid_valid, uint32_t process_id, uint32_t *cause) { uint64_t a; uint8_t i, LEVELS, status, DC_SIZE; @@ -62,8 +62,8 @@ locate_device_context( //ddtp--->+--+ +->+--+ +->+--+ ddtp--->+--+ +->+--+ ddtp--->+--+ // - // The DDT used to locate the DC may be configured to be a 1, 2, or 3 level - // radix-table depending on the maximum width of the device_id supported. + // The DDT used to locate the DC may be configured to be a 1, 2, or 3 level + // radix-table depending on the maximum width of the device_id supported. // The partitioning of the device_id to obtain the device directory indexes // (DDI) to traverse the DDT radix-tree table are as follows: // If `capabilities.MSI_FLAT` is 0 then the IOMMU uses base-format device @@ -87,7 +87,7 @@ locate_device_context( if ( lookup_ioatc_dc(device_id, DC) == IOATC_HIT ) return 0; - // The process to locate the Device-context for transaction + // The process to locate the Device-context for transaction // using its `device_id` is as follows: // 1. Let `a` be `ddtp.PPN x 2^12^` and let `i = LEVELS - 1`. When // `ddtp.iommu_mode` is `3LVL`, `LEVELS` is three. When `ddtp.iommu_mode` is @@ -175,7 +175,7 @@ locate_device_context( cache_ioatc_dc(device_id, DC); return 0; } -uint8_t +uint8_t do_device_context_configuration_checks( device_context_t *DC) { @@ -226,14 +226,14 @@ do_device_context_configuration_checks( // a. `capabilities.PD20` is 0 and `DC.fsc.pdtp.MODE` is `PD20` // b. `capabilities.PD17` is 0 and `DC.fsc.pdtp.MODE` is `PD17` // c. `capabilities.PD8` is 0 and `DC.fsc.pdtp.MODE` is `PD8` - if ( (DC->tc.PDTV == 1) && + if ( (DC->tc.PDTV == 1) && ((DC->fsc.pdtp.MODE != PDTP_Bare) && (DC->fsc.pdtp.MODE != PD20) && (DC->fsc.pdtp.MODE != PD17) && (DC->fsc.pdtp.MODE != PD8)) ) { return 1; } - if ( (DC->tc.PDTV == 1) && + if ( (DC->tc.PDTV == 1) && (((DC->fsc.pdtp.MODE == PD20) && (g_reg_file.capabilities.pd20 == 0)) || ((DC->fsc.pdtp.MODE == PD17) && (g_reg_file.capabilities.pd17 == 0)) || ((DC->fsc.pdtp.MODE == PD8) && (g_reg_file.capabilities.pd8 == 0))) ) { @@ -241,14 +241,14 @@ do_device_context_configuration_checks( } // 9. `DC.tc.PDTV` is 0 and `DC.fsc.iosatp.MODE` encoding is not valid // encoding as determined by <> - if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 0) && + if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 0) && (DC->fsc.iosatp.MODE != IOSATP_Bare) && (DC->fsc.iosatp.MODE != IOSATP_Sv39) && (DC->fsc.iosatp.MODE != IOSATP_Sv48) && (DC->fsc.iosatp.MODE != IOSATP_Sv57) ) { return 1; } - if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 1) && + if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 1) && (DC->fsc.iosatp.MODE != IOSATP_Bare) && (DC->fsc.iosatp.MODE != IOSATP_Sv32) ) { return 1; @@ -258,7 +258,7 @@ do_device_context_configuration_checks( // .. `capabilities.Sv39` is 0 and `DC.fsc.iosatp.MODE` is `Sv39` // .. `capabilities.Sv48` is 0 and `DC.fsc.iosatp.MODE` is `Sv48` // .. `capabilities.Sv57` is 0 and `DC.fsc.iosatp.MODE` is `Sv57` - if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 0) && + if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 0) && (((DC->fsc.iosatp.MODE == IOSATP_Sv39) && (g_reg_file.capabilities.Sv39 == 0)) || ((DC->fsc.iosatp.MODE == IOSATP_Sv48) && (g_reg_file.capabilities.Sv48 == 0)) || ((DC->fsc.iosatp.MODE == IOSATP_Sv57) && (g_reg_file.capabilities.Sv57 == 0))) ) { @@ -267,7 +267,7 @@ do_device_context_configuration_checks( //11. `DC.tc.PDTV` is 0 and and `DC.tc.SXL` is 1 `DC.fsc.iosatp.MODE` is not one of the // supported modes // .. `capabilities.Sv32` is 0 and `DC.fsc.iosatp.MODE` is `Sv32` - if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 1) && + if ( (DC->tc.PDTV == 0) && (DC->tc.SXL == 1) && ((DC->fsc.iosatp.MODE == IOSATP_Sv32) && (g_reg_file.capabilities.Sv32 == 0)) ) { return 1; } @@ -277,14 +277,14 @@ do_device_context_configuration_checks( } //13. `DC.iohgatp.MODE` encoding is not a valid encoding as determined // by <> - if ( (DC->tc.PDTV == 0) && (g_reg_file.fctl.gxl == 0) && + if ( (DC->tc.PDTV == 0) && (g_reg_file.fctl.gxl == 0) && (DC->iohgatp.MODE != IOHGATP_Bare) && (DC->iohgatp.MODE != IOHGATP_Sv39x4) && (DC->iohgatp.MODE != IOHGATP_Sv48x4) && (DC->iohgatp.MODE != IOHGATP_Sv57x4) ) { return 1; } - if ( (DC->tc.PDTV == 0) && (g_reg_file.fctl.gxl == 1) && + if ( (DC->tc.PDTV == 0) && (g_reg_file.fctl.gxl == 1) && (DC->iohgatp.MODE != IOHGATP_Bare) && (DC->iohgatp.MODE != IOHGATP_Sv32x4) ) { return 1; @@ -293,7 +293,7 @@ do_device_context_configuration_checks( // a. `capabilities.Sv39x4` is 0 and `DC.iohgatp.MODE` is `Sv39x4` // b. `capabilities.Sv48x4` is 0 and `DC.iohgatp.MODE` is `Sv48x4` // c. `capabilities.Sv57x4` is 0 and `DC.iohgatp.MODE` is `Sv57x4` - if ( (g_reg_file.fctl.gxl == 0) && + if ( (g_reg_file.fctl.gxl == 0) && (((DC->iohgatp.MODE == IOHGATP_Sv39x4) && (g_reg_file.capabilities.Sv39x4 == 0)) || ((DC->iohgatp.MODE == IOHGATP_Sv48x4) && (g_reg_file.capabilities.Sv48x4 == 0)) || ((DC->iohgatp.MODE == IOHGATP_Sv57x4) && (g_reg_file.capabilities.Sv57x4 == 0))) ) { @@ -301,13 +301,13 @@ do_device_context_configuration_checks( } //15. `fctl.GXL` is 1 and `DC.iohgatp.MODE` is not a supported mode // a. `capabilities.Sv32x4` is 0 and `DC.iohgatp.MODE` is `Sv32x4` - if ( (g_reg_file.fctl.gxl == 1) && + if ( (g_reg_file.fctl.gxl == 1) && ((DC->iohgatp.MODE == IOHGATP_Sv32x4) && (g_reg_file.capabilities.Sv32x4 == 0)) ) { return 1; } //16. `capabilities.MSI_FLAT` is 1 and `DC.msiptp.MODE` is not `Bare` // and not `Flat` - if ( (g_reg_file.capabilities.msi_flat == 1) && + if ( (g_reg_file.capabilities.msi_flat == 1) && ((DC->msiptp.MODE != MSIPTP_Off) && (DC->msiptp.MODE != MSIPTP_Flat)) ) { return 1; } diff --git a/iommu_ref_model/libiommu/src/iommu_faults.c b/iommu_ref_model/libiommu/src/iommu_faults.c index b7248f05..35a5d207 100644 --- a/iommu_ref_model/libiommu/src/iommu_faults.c +++ b/iommu_ref_model/libiommu/src/iommu_faults.c @@ -5,7 +5,7 @@ #include "iommu.h" -void +void report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, uint8_t dtf, uint32_t device_id, uint8_t pid_valid, uint32_t process_id, uint8_t priv_req) { fault_rec_t frec; @@ -15,8 +15,8 @@ report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, ui uint64_t frec_addr; uint8_t status; - // The fault-queue enable bit enables the fault-queue when set to 1. - // The fault-queue is active if fqon reads 1. + // The fault-queue enable bit enables the fault-queue when set to 1. + // The fault-queue is active if fqon reads 1. if ( g_reg_file.fqcsr.fqon == 0 || g_reg_file.fqcsr.fqen == 0 ) return; @@ -38,10 +38,10 @@ report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, ui if ( g_reg_file.fqcsr.fqof == 1 ) return; - // Setting the disable-translation-fault - DTF - bit to 1 disables reporting of - // faults encountered in the address translation process. Setting DTF to 1 does not - // disable error responses from being generated to the device in response to faulting - // transactions. Setting DTF to 1 does not disable reporting of faults from the IOMMU + // Setting the disable-translation-fault - DTF - bit to 1 disables reporting of + // faults encountered in the address translation process. Setting DTF to 1 does not + // disable error responses from being generated to the device in response to faulting + // transactions. Setting DTF to 1 does not disable reporting of faults from the IOMMU // that are not related to the address translation process. The faults that are not // reported when DTF is 1 are listed in Table 8 // |CAUSE | Description | Reported if `DTF` is 1? @@ -78,16 +78,16 @@ report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, ui // |274 | S/VS/G-stage PT data corruption | No // The `CAUSE` encodings 274 through 2047 are reserved for future standard use and // the encodings 2048 through 4095 are designated for custom use. - if ( (dtf == 1) && (cause != 256) && (cause != 257) && - (cause != 258) && (cause != 259) && (cause != 268) && + if ( (dtf == 1) && (cause != 256) && (cause != 257) && + (cause != 258) && (cause != 259) && (cause != 268) && (cause != 272) && (cause != 273) ) { return; } - // DID holds the device_id of the transaction. + // DID holds the device_id of the transaction. // If PV is 0, then PID and PRIV are 0. If PV is 1, the PID - // holds a process_id of the transaction and if the privilege - // of the transaction was Supervisor then PRIV bit is 1 else its 0. + // holds a process_id of the transaction and if the privilege + // of the transaction was Supervisor then PRIV bit is 1 else its 0. frec.DID = device_id; if ( pid_valid ) { frec.PID = process_id; @@ -107,14 +107,14 @@ report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, ui // Fault/Event queue is an in-memory queue data structure used to report events // and faults raised when processing transactions. Each fault record is 32 bytes. - // The PPN of the base of this in-memory queue and the size of the queue is + // The PPN of the base of this in-memory queue and the size of the queue is // configured into a memorymapped register called fault-queue base (fqb). - // The tail of the fault-queue resides in a IOMMU controlled read-only - // memory-mapped register called fqt. The fqt is an index into the next fault + // The tail of the fault-queue resides in a IOMMU controlled read-only + // memory-mapped register called fqt. The fqt is an index into the next fault // record that IOMMU will write in the fault-queue. // Subsequent to writing the record, the IOMMU advances the fqt by 1. The head of - // the fault-queue resides in a read/write memory-mapped software controlled - // register called fqh. The fqh is an index into the next fault record that SW + // the fault-queue resides in a read/write memory-mapped software controlled + // register called fqh. The fqh is an index into the next fault record that SW // should process next. Subsequent to processing fault record(s) software advances // the fqh by the count of the number of fault records processed. If fqh == fqt, the // fault-queue is empty. If fqt == (fqh - 1) the fault-queue is full. @@ -126,15 +126,15 @@ report_fault(uint16_t cause, uint64_t iotval, uint64_t iotval2, uint8_t TTYP, ui generate_interrupt(FAULT_QUEUE); return; } - // The IOMMU may be unable to report faults through the fault-queue due to error - // conditions such as the fault-queue being full or the IOMMU encountering access - // faults when attempting to access the queue memory. A memory-mapped fault control + // The IOMMU may be unable to report faults through the fault-queue due to error + // conditions such as the fault-queue being full or the IOMMU encountering access + // faults when attempting to access the queue memory. A memory-mapped fault control // and status register (fqcsr) holds information about such faults. If the fault-queue // full condition is detected the IOMMU sets a fault-queue overflow (fqof) - // bit in fqcsr. If the IOMMU encounters a fault in accessing the fault-queue memory, + // bit in fqcsr. If the IOMMU encounters a fault in accessing the fault-queue memory, // the IOMMU sets a fault-queue memory access fault (fqmf) bit in fqcsr. While either // error bits are set in fqcsr, the IOMMU discards the record that led to the fault - // and all further fault records. When an error bit is in the fqcsr changes state + // and all further fault records. When an error bit is in the fqcsr changes state // from 0 to 1 or when a new fault record is produced in the fault-queue, fault // interrupt pending (fip) bit is set in the fqcsr. frec_addr = ((fqb * 4096) | (fqt * 32)); diff --git a/iommu_ref_model/libiommu/src/iommu_hpm.c b/iommu_ref_model/libiommu/src/iommu_hpm.c index 48c52f34..41dce349 100644 --- a/iommu_ref_model/libiommu/src/iommu_hpm.c +++ b/iommu_ref_model/libiommu/src/iommu_hpm.c @@ -5,7 +5,7 @@ #include "iommu.h" void count_events( - uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, + uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, uint32_t DID, uint8_t GSCV, uint32_t GSCID, uint16_t eventID) { uint8_t i; uint32_t mask; @@ -16,30 +16,30 @@ count_events( if ( g_reg_file.capabilities.hpm == 0 ) return; for ( i = 0; i < g_num_hpm; i++ ) { - // The performance-monitoring counter inhibits is a 32-bits WARL - // register where that contains bits to inhibit the corresponding - // counters from counting. Bit X when set inhibits counting in + // The performance-monitoring counter inhibits is a 32-bits WARL + // register where that contains bits to inhibit the corresponding + // counters from counting. Bit X when set inhibits counting in // iohpmctrX and bit 0 inhibits counting in iohpmcycles. if ( g_reg_file.iocountinh.raw & (1UL << i) ) continue; // Counter is not inhibited check if it matches - // These performance-monitoring event registers are 64-bit RW - // registers. When a transaction processed by the IOMMU causes an + // These performance-monitoring event registers are 64-bit RW + // registers. When a transaction processed by the IOMMU causes an // event that is programmed to count in a counter then the counter is - // incremented. In addition to matching events the event selector may - // be programmed with additional filters based on device_id, process_id, - // GSCID, and PSCID such that the counter is incremented conditionally - // based on the transaction matching these additional filters. When such - // device_id based filtering is used, the match may be configured to be - // a precise match or a partial match. A partial match allows a + // incremented. In addition to matching events the event selector may + // be programmed with additional filters based on device_id, process_id, + // GSCID, and PSCID such that the counter is incremented conditionally + // based on the transaction matching these additional filters. When such + // device_id based filtering is used, the match may be configured to be + // a precise match or a partial match. A partial match allows a // transactions with a range of IDs to be counted by the counter. if ( g_reg_file.iohpmevt[i].eventID != eventID ) continue; - // When filtering by device_id or GSCID is selected and the event supports - // ID based filtering, the DMASK field can be used to configure a partial - // match. When DMASK is set to 1, partial matching of the DID_GSCID is - // performed for the transaction. The lower bits of the DID_GSCID all the - // way to the first low order 0 bit (including the 0 bit position itself) + // When filtering by device_id or GSCID is selected and the event supports + // ID based filtering, the DMASK field can be used to configure a partial + // match. When DMASK is set to 1, partial matching of the DID_GSCID is + // performed for the transaction. The lower bits of the DID_GSCID all the + // way to the first low order 0 bit (including the 0 bit position itself) // are masked. // The following example illustrates the use of DMASK and filtering by `device_id`. // | *DMASK* | *DID_GSCID* | *Comment* @@ -54,10 +54,10 @@ count_events( mask = (g_reg_file.iohpmevt[i].dmask == 1) ? mask : 0xFFFFFF; // IDT - Filter ID Type: This field indicates the type of ID to - // filter on. + // filter on. if ( g_reg_file.iohpmevt[i].idt == 0 ) { - // When 0, the DID_GSCID field holds a device_id and the - // PID_PSCID field holds a process_id. + // When 0, the DID_GSCID field holds a device_id and the + // PID_PSCID field holds a process_id. if ( g_reg_file.iohpmevt[i].pv_pscv == 1 ) { if ( PV == 0 ) continue; if ( g_reg_file.iohpmevt[i].pid_pscid != PID ) continue; @@ -69,7 +69,7 @@ count_events( } } else { // g_reg_file.iohpmevt[i].idt == 1 - // When 1, the DID_GSCID field holds a GSCID and PID_PSCID + // When 1, the DID_GSCID field holds a GSCID and PID_PSCID // field holds a PSCID. if ( g_reg_file.iohpmevt[i].pv_pscv == 1 ) { if ( PSCV == 0 ) continue; @@ -85,17 +85,17 @@ count_events( count = count & ((g_hpmctr_bits == 64) ? -1LL : ((1LL << g_hpmctr_bits) - 1)); if ( g_reg_file.iohpmctr[i].counter > count ) { g_reg_file.iohpmctr[i].counter = count; - // The OF bit is set when the corresponding iohpmctr* overflows, - // and remains set until cleared by software. Since iohpmctr* - // values are unsigned values, overflow is defined as unsigned - // overflow. Note that there is no loss of information after an - // overflow since the counter wraps around and keeps counting - // while the sticky OF bit remains set. If an iohpmctr* overflows - // while the associated OF bit is zero, then a HPM Counter Overflow - // interrupt is generated. If the OF bit is one, then no interrupt - // request is generated. Consequently the OF bit also functions as + // The OF bit is set when the corresponding iohpmctr* overflows, + // and remains set until cleared by software. Since iohpmctr* + // values are unsigned values, overflow is defined as unsigned + // overflow. Note that there is no loss of information after an + // overflow since the counter wraps around and keeps counting + // while the sticky OF bit remains set. If an iohpmctr* overflows + // while the associated OF bit is zero, then a HPM Counter Overflow + // interrupt is generated. If the OF bit is one, then no interrupt + // request is generated. Consequently the OF bit also functions as // a count overflow interrupt disable for the associated iohpmctr*. - // A pending HPM Counter Overflow interrupt (OR of all iohpmctr* + // A pending HPM Counter Overflow interrupt (OR of all iohpmctr* // overflows) is and reported through ipsr register. if ( g_reg_file.iohpmevt[i].of == 0 ) { g_reg_file.iohpmevt[i].of = 1; diff --git a/iommu_ref_model/libiommu/src/iommu_interrupt.c b/iommu_ref_model/libiommu/src/iommu_interrupt.c index 993aa896..2436de12 100644 --- a/iommu_ref_model/libiommu/src/iommu_interrupt.c +++ b/iommu_ref_model/libiommu/src/iommu_interrupt.c @@ -4,7 +4,7 @@ // Author: ved@rivosinc.com #include "iommu.h" -void +void generate_interrupt( uint8_t unit) { @@ -14,58 +14,58 @@ generate_interrupt( uint8_t vec, status; // Interrupt pending status register (ipsr) - // This 32-bits register (RW1C) reports the pending interrupts - // which require software service. Each interrupt-pending bit + // This 32-bits register (RW1C) reports the pending interrupts + // which require software service. Each interrupt-pending bit // in the register corresponds to a interrupt source in the IOMMU. When an - // interrupt-pending bit in the register is set to 1 the IOMMU will not - // signal another interrupt from that source till software clears that + // interrupt-pending bit in the register is set to 1 the IOMMU will not + // signal another interrupt from that source till software clears that // interrupt-pending bit by writing 1 to clear it. // Interrupt-cause-to-vector register (icvec) - // Interrupt-cause-to-vector register maps a cause to a vector. All causes + // Interrupt-cause-to-vector register maps a cause to a vector. All causes // can be mapped to same vector or a cause can be given a unique vector. switch ( unit ) { case FAULT_QUEUE: // The fault-queue-interrupt-pending - if ( g_reg_file.ipsr.fip == 1) + if ( g_reg_file.ipsr.fip == 1) return; - if ( g_reg_file.fqcsr.fie == 0) + if ( g_reg_file.fqcsr.fie == 0) return; vec = g_reg_file.icvec.fiv; g_reg_file.ipsr.fip = 1; break; case PAGE_QUEUE: - if ( g_reg_file.ipsr.pip == 1) + if ( g_reg_file.ipsr.pip == 1) return; - if ( g_reg_file.pqcsr.pie == 0) + if ( g_reg_file.pqcsr.pie == 0) return; vec = g_reg_file.icvec.piv; g_reg_file.ipsr.pip = 1; break; case COMMAND_QUEUE: - if ( g_reg_file.ipsr.cip == 1) + if ( g_reg_file.ipsr.cip == 1) return; - if ( g_reg_file.cqcsr.cie == 0) + if ( g_reg_file.cqcsr.cie == 0) return; vec = g_reg_file.icvec.civ; g_reg_file.ipsr.cip = 1; break; default: // HPM - if ( g_reg_file.ipsr.pmip == 1) + if ( g_reg_file.ipsr.pmip == 1) return; vec = g_reg_file.icvec.pmiv; g_reg_file.ipsr.pmip = 1; break; } - // The vector is used: - // 1. By an IOMMU that generates interrupts as MSI, to index into MSI - // configuration table (msi_cfg_tbl) to determine the MSI to generate. An + // The vector is used: + // 1. By an IOMMU that generates interrupts as MSI, to index into MSI + // configuration table (msi_cfg_tbl) to determine the MSI to generate. An // IOMMU is capable of generating interrupts as a MSI if capabilities.IGS==MSI // or if capabilities.IGS==BOTH. When capabilities.IGS==BOTH the IOMMU may be // configured to generate interrupts as MSI by setting fctl.WSI to 0. - // 2. By an IOMMU that generates wire based interrupts, to determine the wire - // to signal the interrupt. An IOMMU is capable of generating wire based - // interrupts if capabilities.IGS==WSI or if capabilities.IGS==BOTH. When - // capabilities.IGS==BOTH the IOMMU may be configured to generate wire based + // 2. By an IOMMU that generates wire based interrupts, to determine the wire + // to signal the interrupt. An IOMMU is capable of generating wire based + // interrupts if capabilities.IGS==WSI or if capabilities.IGS==BOTH. When + // capabilities.IGS==BOTH the IOMMU may be configured to generate wire based // interrupts by setting fctl.WSI to 1. if ( g_reg_file.fctl.wsi == 0 ) { msi_addr.raw = g_reg_file.msi_cfg_tbl[vec].msi_addr.raw; @@ -78,8 +78,8 @@ generate_interrupt( return; status = write_memory((char *)&msi_data, msi_addr.raw, 4); if ( status & ACCESS_FAULT ) { - // If an access fault is detected on a MSI write using msi_addr_x, - // then the IOMMU reports a "IOMMU MSI write access fault" (cause 273) fault, + // If an access fault is detected on a MSI write using msi_addr_x, + // then the IOMMU reports a "IOMMU MSI write access fault" (cause 273) fault, // with TTYP set to 0 and iotval set to the value of msi_addr_x. report_fault(273, msi_addr.raw, 0, TTYPE_NONE, 0, 0, 0, 0, 0); } diff --git a/iommu_ref_model/libiommu/src/iommu_msi_trans.c b/iommu_ref_model/libiommu/src/iommu_msi_trans.c index 703dd31d..a18da3a0 100644 --- a/iommu_ref_model/libiommu/src/iommu_msi_trans.c +++ b/iommu_ref_model/libiommu/src/iommu_msi_trans.c @@ -18,9 +18,9 @@ extract(uint64_t data, uint64_t mask) { } uint8_t msi_address_translation( - uint64_t gpa, uint8_t is_exec, device_context_t *DC, + uint64_t gpa, uint8_t is_exec, device_context_t *DC, uint8_t *is_msi, uint8_t *is_mrif, uint32_t *mrif_nid, uint64_t *dest_mrif_addr, - uint32_t *cause, uint64_t *iotval2, uint64_t *pa, + uint32_t *cause, uint64_t *iotval2, uint64_t *pa, uint64_t *page_sz, gpte_t *g_pte, uint8_t check_access_perms ) { uint64_t A, m, I; @@ -29,7 +29,7 @@ msi_address_translation( *iotval2 = 0; *is_msi = 0; - + if ( DC->msiptp.MODE == MSIPTP_Off ) return 0; @@ -40,16 +40,16 @@ msi_address_translation( // using the process outlined in <>. // 3. Determine if the address `A` is an access to a virtual interrupt file as // specified in <> - *is_msi = (((A >> 12) & ~DC->msi_addr_mask.mask) == + *is_msi = (((A >> 12) & ~DC->msi_addr_mask.mask) == ((DC->msi_addr_pattern.pattern & ~DC->msi_addr_mask.mask))); // 4. If the address is not determined to be that of a virtual interrupt file then // stop this process and instead use the regular translation data structures to // do the address translation. - if ( *is_msi == 0 ) + if ( *is_msi == 0 ) return 0; - // 5. Extract an interrupt file number `I` from `A` as + // 5. Extract an interrupt file number `I` from `A` as // `I = extract(A >> 12, DC.msi_addr_mask)`. The bit extract function `extract(x, y)` // discards all bits from `x` whose matching bits in the same positions in the // mask `y` are zeros, and packs the remaining bits from `x` contiguously at the @@ -105,7 +105,7 @@ msi_address_translation( //13. If `msipte.M == 3` the PTE is translate R/W mode PTE and the translation // process is as follows: - // a. If any bits or encoding that are reserved for future standard use are + // a. If any bits or encoding that are reserved for future standard use are // set within msipte, stop and report "MSI PTE misconfigured" (cause = 263). // b. Compute the translated address as `msipte.PPN << 12 | A[11:0]`. if ( msipte.M == 3 ) { diff --git a/iommu_ref_model/libiommu/src/iommu_process_context.c b/iommu_ref_model/libiommu/src/iommu_process_context.c index 6b0d9d6d..6a9c5eea 100644 --- a/iommu_ref_model/libiommu/src/iommu_process_context.c +++ b/iommu_ref_model/libiommu/src/iommu_process_context.c @@ -7,7 +7,7 @@ uint8_t locate_process_context( - process_context_t *PC, device_context_t *DC, uint32_t device_id, uint32_t process_id, + process_context_t *PC, device_context_t *DC, uint32_t device_id, uint32_t process_id, uint32_t *cause, uint64_t *iotval2, uint8_t TTYP) { uint64_t a, gst_page_sz; uint8_t i, LEVELS, status, gst_fault; @@ -15,14 +15,14 @@ locate_process_context( pdte_t pdte; uint16_t PDI[3]; - // The device-context provides the PDT root page PPN (pdtp.ppn). + // The device-context provides the PDT root page PPN (pdtp.ppn). // When DC.iohgatp.mode is not Bare, pdtp.PPN as well as pdte.PPN // are Guest Physical Addresses (GPA) which must be translated into - // System Physical Addresses (SPA) using the G-stage page table + // System Physical Addresses (SPA) using the G-stage page table // determined by DC.iohgatp. - // The PDT may be configured to be a 1, 2, or 3 level radix table - // depending on the maximum width of the process_id supported for + // The PDT may be configured to be a 1, 2, or 3 level radix table + // depending on the maximum width of the process_id supported for // that device. The partitioning of the process_id to obtain the process // directory indices (PDI) to traverse the PDT radix-tree table are as follows: PDI[0] = get_bits(7, 0, process_id); @@ -54,15 +54,15 @@ locate_process_context( // | | | | | | | | | | | | | | | // pdtp--->+--+ +->+--+ +->+--+ pdtp--->+--+ +->+--+ pdtp--->+--+ - // The process to locate the Process-context for a transaction + // The process to locate the Process-context for a transaction // using its process_id is as follows: // Determine if there is a cached device context if ( lookup_ioatc_pc(device_id, process_id, PC) == IOATC_HIT ) return 0; - // 1. Let a be pdtp.PPN x 2^12 and let i = LEVELS - 1. When pdtp.MODE - // is PD20, LEVELS is three. When pdtp.MODE is PD17, LEVELS is two. + // 1. Let a be pdtp.PPN x 2^12 and let i = LEVELS - 1. When pdtp.MODE + // is PD20, LEVELS is three. When pdtp.MODE is PD17, LEVELS is two. // When pdtp.MODE is PD8, LEVELS is one. a = DC->fsc.pdtp.PPN * PAGESIZE; if ( DC->fsc.pdtp.MODE == PD20 ) LEVELS = 3; @@ -73,12 +73,12 @@ locate_process_context( step_2: a = a + ((i == 0) ? (PDI[i] * 16) : (PDI[i] * 8)); // 2. If `DC.iohgatp.mode != Bare`, then `a` is a GPA. Invoke the process - // to translate `a` to a SPA as an implicit memory access. If faults + // to translate `a` to a SPA as an implicit memory access. If faults // occur during G-stage address translation of `a` then stop and the fault // detected by the G-stage address translation process. The translated `a` // is used in subsequent steps. if ( ( gst_fault = second_stage_address_translation(a, 1, device_id, 1, 0, 0, 1, process_id, - 0, 0, ((DC->iohgatp.MODE == IOHGATP_Bare) ? 0 : 1), + 0, 0, ((DC->iohgatp.MODE == IOHGATP_Bare) ? 0 : 1), DC->iohgatp.GSCID, DC->iohgatp, DC->tc.GADE, DC->tc.SXL, &a, &gst_page_sz, &g_pte) ) ) { if ( gst_fault == GST_PAGE_FAULT ) { @@ -162,7 +162,7 @@ locate_process_context( } //11. If any bits or encoding that are reserved for future standard use are set // within `PC`, stop and report "PDT entry misconfigured" (cause = 267). - if ( PC->ta.reserved0 != 0 || PC->ta.reserved1 != 0 || + if ( PC->ta.reserved0 != 0 || PC->ta.reserved1 != 0 || PC->fsc.iosatp.reserved != 0 || ((PC->fsc.iosatp.MODE != IOSATP_Bare) && (PC->fsc.iosatp.MODE != IOSATP_Sv32) && @@ -171,7 +171,7 @@ locate_process_context( (PC->fsc.iosatp.MODE != IOSATP_Sv57)) ) { *cause = 267; // PDT entry not misconfigured return 1; - } + } //12. If any of the following conditions are true then stop and report // "PDT entry misconfigured" (cause = 267). // a. `capabilities.Sv32` is 0 and `PC.fsc.MODE` is `Sv32` @@ -189,5 +189,3 @@ locate_process_context( cache_ioatc_pc(device_id, process_id, PC); return 0; } - - diff --git a/iommu_ref_model/libiommu/src/iommu_reg.c b/iommu_ref_model/libiommu/src/iommu_reg.c index 4a42be7e..6425897d 100644 --- a/iommu_ref_model/libiommu/src/iommu_reg.c +++ b/iommu_ref_model/libiommu/src/iommu_reg.c @@ -20,10 +20,10 @@ uint8_t g_max_iommu_mode; uint8_t g_fill_ats_trans_in_ioatc; uint32_t g_max_devid_mask; -uint8_t +uint8_t is_access_valid( uint16_t offset, uint8_t num_bytes) { - // The IOMMU behavior for register accesses where the + // The IOMMU behavior for register accesses where the // address is not aligned to the size of the access or // if the access spans multiple registers is undefined if ( (num_bytes != 4 && num_bytes != 8) || // only 4B & 8B registers in IOMMU @@ -34,7 +34,7 @@ is_access_valid( } return 1; } -uint32_t +uint32_t get_iocountovf() { iocountovf_t iocountovf_temp; uint8_t i; @@ -45,7 +45,7 @@ get_iocountovf() { return iocountovf_temp.raw; } -uint64_t +uint64_t read_register( uint16_t offset, uint8_t num_bytes) { @@ -61,7 +61,7 @@ read_register( return ( num_bytes == 4 ) ? g_reg_file.regs4[offset/4] : g_reg_file.regs8[offset/8]; } -void +void write_register( uint16_t offset, uint8_t num_bytes, uint64_t data) { @@ -85,7 +85,7 @@ write_register( iohpmevt_t iohpmevt_temp; msi_addr_t msi_addr_temp; msi_vec_ctrl_t msi_vec_ctrl_temp; - hb_to_iommu_req_t req; + hb_to_iommu_req_t req; iommu_to_hb_rsp_t rsp; uint64_t pa_mask = ((1UL << (g_reg_file.capabilities.pas)) - 1); uint64_t ppn_mask = pa_mask >> 12; @@ -95,10 +95,10 @@ write_register( return; } - // If its a 4B write to a 8B register then merge the new + // If its a 4B write to a 8B register then merge the new // write data with current data in register file if ( (g_offset_to_size[offset] == 8) && (num_bytes == 4) ) { - // read the old 8B + // read the old 8B data8 = g_reg_file.regs8[(offset & ~0x7)/8]; if ( (offset & 0x7) != 0 ) { // write to high half - replace high half @@ -131,22 +131,22 @@ write_register( icvec_temp.raw = data4; msi_addr_temp.raw = data8; msi_vec_ctrl_temp.raw = data4; - + switch (offset) { case CAPABILITIES_OFFSET: // This register is read only return; case FCTRL_OFFSET: - // This register must be readable in any + // This register must be readable in any // implementation. An implementation may allow one or more - // fields in the register to be writable to support enabling + // fields in the register to be writable to support enabling // or disabling the feature controlled by that field. - // If software enables or disables a feature when + // If software enables or disables a feature when // the IOMMU is not OFF (i.e. ddtp.iommu_mode == Off) // then the IOMMU behavior is UNSPECIFIED. - // If software enables or disables a feature when the + // If software enables or disables a feature when the // IOMMU in-memory queues are enabled (i.e. - // cqcsr.cqon/cqen == 1, fqcsr.fqon/cqen == 1, or + // cqcsr.cqon/cqen == 1, fqcsr.fqon/cqen == 1, or // pqcsr.pqon/pqen == 1) then the IOMMU // behavior is UNSPECIFIED. // FCTRL is writeable if IOMMU is bi-endian @@ -178,7 +178,7 @@ write_register( case DDTP_OFFSET: // If DDTP is busy the discard the write // A write to ddtp may require the IOMMU to perform - // many operations that may not occur synchronously to + // many operations that may not occur synchronously to // the write. When a write is observed by the ddtp, the // busy bit is set to 1. When the busy bit is 1, behavior of // additional writes to the ddtp is implementation @@ -193,7 +193,7 @@ write_register( // synchronously may hard-wire this bit to 0 if ( g_reg_file.ddtp.busy ) return; - // If a illegal value written to ddtp.iommu_mode then + // If a illegal value written to ddtp.iommu_mode then // retain the current legal value if ( ((ddtp_temp.iommu_mode == Off) || (ddtp_temp.iommu_mode == DDT_Bare) || @@ -225,7 +225,7 @@ write_register( // This register is read only break; case CQT_OFFSET: - g_reg_file.cqt.index = cqt_temp.index & + g_reg_file.cqt.index = cqt_temp.index & ((1UL << (g_reg_file.cqb.log2szm1 + 1)) - 1); break; case FQB_OFFSET: @@ -248,7 +248,7 @@ write_register( g_reg_file.fqh.index = 0; break; case FQH_OFFSET: - g_reg_file.fqh.index = fqh_temp.index & + g_reg_file.fqh.index = fqh_temp.index & ((1UL << (g_reg_file.fqb.log2szm1 + 1)) - 1); break; case FQT_OFFSET: @@ -280,7 +280,7 @@ write_register( // This register is read-only 0 if capabilities.ATS is 0. if ( g_reg_file.capabilities.ats == 0 ) break; - g_reg_file.pqh.index = pqh_temp.index & + g_reg_file.pqh.index = pqh_temp.index & ((1UL << (g_reg_file.pqb.log2szm1 + 1)) - 1); break; case PQT_OFFSET: @@ -288,21 +288,21 @@ write_register( break; case CQCSR_OFFSET: // A write to `cqcsr` may require the IOMMU to perform - // many operations that may not occur synchronously - // to the write. When a write is observed by the + // many operations that may not occur synchronously + // to the write. When a write is observed by the // `cqcsr`, the `busy` bit is set to 1. - // When the `busy` bit is 1, behavior of additional - // writes to the `cqcsr` is implementation defined. + // When the `busy` bit is 1, behavior of additional + // writes to the `cqcsr` is implementation defined. // Some implementations may ignore the second write and - // others may perform the actions determined by the + // others may perform the actions determined by the // second write. - // Software must verify that the busy bit is 0 before - // writing to the `cqcsr`. An IOMMU that can complete + // Software must verify that the busy bit is 0 before + // writing to the `cqcsr`. An IOMMU that can complete // controls synchronously may hard-wire this bit to 0. - // An IOMMU that can complete these operations + // An IOMMU that can complete these operations // synchronously may hard-wire this bit to 0. // The reference model discards the write if ( g_reg_file.cqcsr.busy ) @@ -317,16 +317,16 @@ write_register( // following setting the `cqen` to 1. During // this delay the `busy` bit is 1. When the command // queue is active, the `cqon` bit reads 1. - // When `cqen` is changed from 1 to 0, the command - // queue may stay active till the commands already - // fetched from the command-queue are being processed - // and/or there are outstanding implicit loads from - // the command-queue. When the command-queue turns + // When `cqen` is changed from 1 to 0, the command + // queue may stay active till the commands already + // fetched from the command-queue are being processed + // and/or there are outstanding implicit loads from + // the command-queue. When the command-queue turns // off, the `cqon` bit reads 0. - // When the `cqon` bit reads 0, the IOMMU guarantees - // that no implicit memory accesses to the command - // queue are in-flight and the command-queue will not - // generate new implicit loads to the queue memory. + // When the `cqon` bit reads 0, the IOMMU guarantees + // that no implicit memory accesses to the command + // queue are in-flight and the command-queue will not + // generate new implicit loads to the queue memory. if ( g_reg_file.cqcsr.cqen != cqcsr_temp.cqen ) { // cqen going from 0->1 or 1->0 if ( cqcsr_temp.cqen == 1 ) { @@ -345,8 +345,8 @@ write_register( g_reg_file.cqcsr.cqen = 0; } } - // Command-queue-interrupt-enable bit enables - // generation of interrupts from command-queue when + // Command-queue-interrupt-enable bit enables + // generation of interrupts from command-queue when // set to 1. g_reg_file.cqcsr.cie = cqcsr_temp.cie; @@ -360,19 +360,19 @@ write_register( g_reg_file.cqcsr.busy = 0; return; case FQCSR_OFFSET: - // Write to `fqcsr` may require the IOMMU to perform - // many operations that may not occur synchronously to + // Write to `fqcsr` may require the IOMMU to perform + // many operations that may not occur synchronously to // the write. - // When a write is observed by the fqcsr, the `busy` - // bit is set to 1. When the `busy` bit is 1, behavior - // of additional writes to the `fqcsr` are - // implementation defined. Some implementations may - // ignore the second write and others may perform the + // When a write is observed by the fqcsr, the `busy` + // bit is set to 1. When the `busy` bit is 1, behavior + // of additional writes to the `fqcsr` are + // implementation defined. Some implementations may + // ignore the second write and others may perform the // actions determined by the second write. - // Software should ensure that the `busy` bit is 0 - // before writing to the `fqcsr`. - // An IOMMU that can complete controls synchronously - // may hard-wire this bit to 0. + // Software should ensure that the `busy` bit is 0 + // before writing to the `fqcsr`. + // An IOMMU that can complete controls synchronously + // may hard-wire this bit to 0. if ( g_reg_file.fqcsr.busy ) return; // First set the busy bit @@ -408,8 +408,8 @@ write_register( g_reg_file.fqcsr.fqen = 0; } } - // Fault-queue-interrupt-enable bit enables - // generation of interrupts from command-queue when + // Fault-queue-interrupt-enable bit enables + // generation of interrupts from command-queue when // set to 1. g_reg_file.fqcsr.fie = fqcsr_temp.fie; // Update the RW1C bits - clear if written to 1 @@ -421,19 +421,19 @@ write_register( g_reg_file.fqcsr.busy = 0; break; case PQCSR_OFFSET: - // Write to `pqcsr` may require the IOMMU to perform - // many operations that may not occur synchronously to + // Write to `pqcsr` may require the IOMMU to perform + // many operations that may not occur synchronously to // the write. - // When a write is observed by the `pqcsr`, the `busy` - // bit is set to 1. When the `busy` bit is 1, behavior - // of additional writes to the `fqcsr` are - // implementation defined. Some implementations may - // ignore the second write and others may perform the + // When a write is observed by the `pqcsr`, the `busy` + // bit is set to 1. When the `busy` bit is 1, behavior + // of additional writes to the `fqcsr` are + // implementation defined. Some implementations may + // ignore the second write and others may perform the // actions determined by the second write. - // Software should ensure that the `busy` bit is 0 - // before writing to the `fqcsr`. - // An IOMMU that can complete controls synchronously - // may hard-wire this bit to 0. + // Software should ensure that the `busy` bit is 0 + // before writing to the `fqcsr`. + // An IOMMU that can complete controls synchronously + // may hard-wire this bit to 0. if ( g_reg_file.pqcsr.busy ) { return; } @@ -475,8 +475,8 @@ write_register( g_reg_file.pqcsr.pqen = 0; } } - // page-request-queue-interrupt-enable bit enables - // generation of interrupts from page-request-queue when + // page-request-queue-interrupt-enable bit enables + // generation of interrupts from page-request-queue when // set to 1. g_reg_file.pqcsr.pie = pqcsr_temp.pie; // Update the RW1C bits - clear if written to 1 @@ -488,11 +488,11 @@ write_register( g_reg_file.pqcsr.busy = 0; break; case IPSR_OFFSET: - // This 32-bits register (RW1C) reports the pending - // interrupts which require software service. Each + // This 32-bits register (RW1C) reports the pending + // interrupts which require software service. Each // interrupt-pending bit in the register corresponds to - // a interrupt source in the IOMMU. When an - // interrupt-pending bit in the register is set to 1 the + // a interrupt source in the IOMMU. When an + // interrupt-pending bit in the register is set to 1 the // IOMMU will not signal another interrupt from that source till // software clears that interrupt-pending bit by writing 1 to clear it. // Update the RW1C bits - clear if written to 1 @@ -500,7 +500,7 @@ write_register( // the bit from 1->0. If the conditions to set that bit are still present // (See <>) or if they occur after the bit is cleared then that // bit transitions again from 0->1. - // Clear cip and pend interrupt again if there are unacknowledge + // Clear cip and pend interrupt again if there are unacknowledge // interrupts from CQ and if CQ interrupts are enabled if ( ipsr_temp.cip == 1 ) g_reg_file.ipsr.cip = 0; @@ -508,12 +508,12 @@ write_register( if ( (g_reg_file.cqcsr.cmd_to || g_reg_file.cqcsr.cmd_ill || g_reg_file.cqcsr.cqmf || - g_reg_file.cqcsr.fence_w_ip) && + g_reg_file.cqcsr.fence_w_ip) && (g_reg_file.cqcsr.cie == 1) ) { generate_interrupt(COMMAND_QUEUE); } } - // Clear fip and pend interrupt again If there are unacknowledge + // Clear fip and pend interrupt again If there are unacknowledge // interrupts from FQ and if FQ interrupts are enabled if ( ipsr_temp.fip == 1 ) g_reg_file.ipsr.fip = 0; @@ -525,7 +525,7 @@ write_register( } } - // Clear pip and pend interrupt again If there are unacknowledge + // Clear pip and pend interrupt again If there are unacknowledge // interrupts from PQ and if PQ interrupts are enabled if ( ipsr_temp.pip == 1 ) g_reg_file.ipsr.pip = 0; @@ -552,7 +552,7 @@ write_register( case IOHPMCYCLES_OFFSET: // This register is read-only 0 if capabilities.HPM is 0 if ( g_reg_file.capabilities.hpm == 1 ) { - g_reg_file.iohpmcycles.counter = + g_reg_file.iohpmcycles.counter = iohpmcycles_temp.counter & ((g_hpmctr_bits > 63) ? ((1UL << 63) - 1) : ((1UL << g_hpmctr_bits) - 1)); g_reg_file.iohpmcycles.of = iohpmcycles_temp.of; @@ -590,7 +590,7 @@ write_register( case IOHPMCTR30_OFFSET: case IOHPMCTR31_OFFSET: // These register are read-only 0 if capabilities.HPM is 0 - if ( g_reg_file.capabilities.hpm == 1 ) { + if ( g_reg_file.capabilities.hpm == 1 ) { ctr_num = ((offset - IOHPMCTR1_OFFSET)/8) + 1; // Writes discarded to non implemented HPM counters if ( ctr_num <= (g_num_hpm - 1) ) { @@ -632,7 +632,7 @@ write_register( case IOHPMEVT30_OFFSET: case IOHPMEVT31_OFFSET: // These register are read-only 0 if capabilities.HPM is 0 - if ( g_reg_file.capabilities.hpm == 1 ) { + if ( g_reg_file.capabilities.hpm == 1 ) { ctr_num = ((offset - IOHPMEVT1_OFFSET)/8); iohpmevt_temp.eventID &= g_eventID_mask; // Writes discarded to non implemented HPM counters @@ -649,9 +649,9 @@ write_register( // * IOMMU configurations such as ddtp.iommu_mode, etc. are modified. // The reference model ignores writes // The `tr_req_iova` is a 64-bit WARL register used to implement a - // translation-request interface for debug. This register is present when + // translation-request interface for debug. This register is present when // `capabilities.DBG == 1`. - if ( g_reg_file.capabilities.dbg == 1 ) { + if ( g_reg_file.capabilities.dbg == 1 ) { if ( g_reg_file.tr_req_ctrl.go_busy == 0 ) { g_reg_file.tr_req_iova.raw = data8 & ~0xFFF; } @@ -663,9 +663,9 @@ write_register( // * IOMMU configurations such as ddtp.iommu_mode, etc. are modified. // The reference model ignores writes // The `tr_req_ctrl` is a 64-bit WARL register used to implement a - // translation-request interface for debug. This register is present when + // translation-request interface for debug. This register is present when // `capabilities.DBG == 1`. - if ( g_reg_file.capabilities.dbg == 1 ) { + if ( g_reg_file.capabilities.dbg == 1 ) { if ( g_reg_file.tr_req_ctrl.go_busy == 0 ) { g_reg_file.tr_req_ctrl.raw = data8; g_reg_file.tr_req_ctrl.reserved = 0; @@ -702,19 +702,19 @@ write_register( // (`pmiv`) is the vector number assigned to the // performance-monitoring-interrupt. This field is // read-only 0 if `capabilities.HPM` is 0. - if ( g_reg_file.capabilities.hpm == 0 ) { + if ( g_reg_file.capabilities.hpm == 0 ) { icvec_temp.pmiv = 0; } // The page-request-queue-interrupt-vector (`piv`) // is the vector number assigned to the // page-request-queue-interrupt. This field is // read-only 0 if `capabilities.ATS` is 0. - if ( g_reg_file.capabilities.ats == 0 ) { + if ( g_reg_file.capabilities.ats == 0 ) { icvec_temp.piv = 0; } - // If an implementation only supports a single vector then all - // bits of this register may be hardwired to 0 (WARL). Likewise - // if only two vectors are supported then only bit 0 for each + // If an implementation only supports a single vector then all + // bits of this register may be hardwired to 0 (WARL). Likewise + // if only two vectors are supported then only bit 0 for each // cause could be writable. g_reg_file.icvec.pmiv = icvec_temp.pmiv & ((1UL << g_num_vec_bits) - 1); g_reg_file.icvec.piv = icvec_temp.piv & ((1UL << g_num_vec_bits) - 1); @@ -737,18 +737,18 @@ write_register( case MSI_ADDR_13_OFFSET: case MSI_ADDR_14_OFFSET: case MSI_ADDR_15_OFFSET: - // IOMMU that supports MSI implements a MSI configuration table - // that is indexed by the vector from icvec to determine a MSI table entry. - // Each MSI table entry for interrupt vector x has three registers msi_addr_x, - // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field - // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 - // then MSI configuration table entries 2^V to 15 are read-only 0. These registers - // are read-only 0 if the IOMMU does not support MSI + // IOMMU that supports MSI implements a MSI configuration table + // that is indexed by the vector from icvec to determine a MSI table entry. + // Each MSI table entry for interrupt vector x has three registers msi_addr_x, + // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field + // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 + // then MSI configuration table entries 2^V to 15 are read-only 0. These registers + // are read-only 0 if the IOMMU does not support MSI // (i.e., if capabilities.IGS == WSI). if ( g_reg_file.capabilities.igs == WSI ) break; x = (offset - MSI_ADDR_0_OFFSET) / 16; - if ( x >= (1UL << g_num_vec_bits) ) + if ( x >= (1UL << g_num_vec_bits) ) break; msi_addr_temp.addr = msi_addr_temp.addr & (pa_mask >> 2); g_reg_file.msi_cfg_tbl[x].msi_addr.addr = msi_addr_temp.addr; @@ -769,18 +769,18 @@ write_register( case MSI_DATA_13_OFFSET: case MSI_DATA_14_OFFSET: case MSI_DATA_15_OFFSET: - // IOMMU that supports MSI implements a MSI configuration table - // that is indexed by the vector from icvec to determine a MSI table entry. - // Each MSI table entry for interrupt vector x has three registers msi_addr_x, - // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field - // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 - // then MSI configuration table entries 2^V to 15 are read-only 0. These registers - // are read-only 0 if the IOMMU does not support MSI + // IOMMU that supports MSI implements a MSI configuration table + // that is indexed by the vector from icvec to determine a MSI table entry. + // Each MSI table entry for interrupt vector x has three registers msi_addr_x, + // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field + // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 + // then MSI configuration table entries 2^V to 15 are read-only 0. These registers + // are read-only 0 if the IOMMU does not support MSI // (i.e., if capabilities.IGS == WSI). if ( g_reg_file.capabilities.igs == WSI ) break; x = (offset - MSI_ADDR_0_OFFSET) / 16; - if ( x >= (1UL << g_num_vec_bits) ) + if ( x >= (1UL << g_num_vec_bits) ) break; g_reg_file.msi_cfg_tbl[x].msi_data = data4; break; @@ -800,27 +800,27 @@ write_register( case MSI_VEC_CTRL_13_OFFSET: case MSI_VEC_CTRL_14_OFFSET: case MSI_VEC_CTRL_15_OFFSET: - // IOMMU that supports MSI implements a MSI configuration table - // that is indexed by the vector from icvec to determine a MSI table entry. - // Each MSI table entry for interrupt vector x has three registers msi_addr_x, - // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field - // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 - // then MSI configuration table entries 2^V to 15 are read-only 0. These registers - // are read-only 0 if the IOMMU does not support MSI + // IOMMU that supports MSI implements a MSI configuration table + // that is indexed by the vector from icvec to determine a MSI table entry. + // Each MSI table entry for interrupt vector x has three registers msi_addr_x, + // msi_data_x, and msi_vec_ctrl_x. If number of writable bits in each field + // of icvec is V, then x is a number between 0 and 2V - 1. If V is less than 4 + // then MSI configuration table entries 2^V to 15 are read-only 0. These registers + // are read-only 0 if the IOMMU does not support MSI // (i.e., if capabilities.IGS == WSI). if ( g_reg_file.capabilities.igs == WSI ) break; x = (offset - MSI_ADDR_0_OFFSET) / 16; - if ( x >= (1UL << g_num_vec_bits) ) + if ( x >= (1UL << g_num_vec_bits) ) break; g_reg_file.msi_cfg_tbl[x].msi_vec_ctrl.m = msi_vec_ctrl_temp.m; break; } return; } -int -reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, - uint8_t num_vec_bits, uint8_t reset_iommu_mode, +int +reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, + uint8_t num_vec_bits, uint8_t reset_iommu_mode, uint8_t max_iommu_mode, uint32_t max_devid_mask, uint8_t gxl_writeable, uint8_t fctl_be_writeable, uint8_t fill_ats_trans_in_ioatc, capabilities_t capabilities, @@ -831,20 +831,20 @@ reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, if ( capabilities.pas > 56 ) return -1; // Only one of MSI, WSI, or BOTH supported - if ( capabilities.igs != MSI && - capabilities.igs != WSI && + if ( capabilities.igs != MSI && + capabilities.igs != WSI && capabilities.igs != IGS_BOTH ) return -1; // If IGS_BOTH is not supported then WSI must be 0 // if MSI is only supported mode else it must be 1 - if ( capabilities.igs != IGS_BOTH && + if ( capabilities.igs != IGS_BOTH && ((capabilities.igs == MSI && fctl.wsi != 0) || (capabilities.igs == WSI && fctl.wsi == 0)) ) return -1; // Only 15-bit event ID supported // Mask must be 0 when hpm not supported if ( g_eventID_mask != 0 && capabilities.hpm == 0 ) - return -1; + return -1; // vectors is a number between 1 and 15 if ( num_vec_bits > 4 ) return -1; @@ -857,7 +857,7 @@ reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, if ( (hpmctr_bits < 1 || hpmctr_bits > 64) && (capabilities.hpm == 1) ) return -1; - if ( hpmctr_bits != 0 && capabilities.hpm == 0 ) + if ( hpmctr_bits != 0 && capabilities.hpm == 0 ) return -1; // Reset value for ddtp.iommu_mode field must be either Off or Bare if ( reset_iommu_mode != Off && reset_iommu_mode != DDT_Bare ) @@ -873,9 +873,9 @@ reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, g_max_iommu_mode = max_iommu_mode; g_max_devid_mask = max_devid_mask; g_fill_ats_trans_in_ioatc = fill_ats_trans_in_ioatc; - + // Initialize registers that have resets to 0 - // The reset default value is 0 for the following registers. + // The reset default value is 0 for the following registers. // Section 4.2 - Reset value is implementation-defined for all // other registers and/or fields. // - fctl @@ -892,7 +892,7 @@ reset_iommu(uint8_t num_hpm, uint8_t hpmctr_bits, uint16_t eventID_mask, g_reg_file.capabilities = capabilities; g_reg_file.fctl = fctl; - // Reset value for ddtp.iommu_mode field must be either Off or Bare. + // Reset value for ddtp.iommu_mode field must be either Off or Bare. // The reset value for ddtp.busy field must be 0. g_reg_file.ddtp.iommu_mode = reset_iommu_mode; diff --git a/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c b/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c index 0649e909..4fbe3129 100644 --- a/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c +++ b/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c @@ -6,7 +6,7 @@ #include "iommu.h" uint8_t second_stage_address_translation( - uint64_t gpa, uint8_t check_access_perms, uint32_t DID, + uint64_t gpa, uint8_t check_access_perms, uint32_t DID, uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL, @@ -32,19 +32,19 @@ second_stage_address_translation( gpte->N = 0; gpte->PBMT = PMA; // Indicate G-stage page size as largest possible page size - if ( g_reg_file.capabilities.Sv57x4 == 1 ) + if ( g_reg_file.capabilities.Sv57x4 == 1 ) *gst_page_sz = 512UL * 512UL * 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv48x4 == 1 ) + else if ( g_reg_file.capabilities.Sv48x4 == 1 ) *gst_page_sz = 512UL * 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv39x4 == 1 ) + else if ( g_reg_file.capabilities.Sv39x4 == 1 ) *gst_page_sz = 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv32x4 == 1 ) + else if ( g_reg_file.capabilities.Sv32x4 == 1 ) *gst_page_sz = 2UL * 512UL * PAGESIZE; goto step_8; } - // 1. Let a be satp.ppn × PAGESIZE, and let i = LEVELS − 1. PAGESIZE is 2^12. (For Sv32, - // LEVELS=2, For Sv39 LEVELS=3, For Sv48 LEVELS=4, For Sv57 LEVELS=5.) The satp register + // 1. Let a be satp.ppn × PAGESIZE, and let i = LEVELS − 1. PAGESIZE is 2^12. (For Sv32, + // LEVELS=2, For Sv39 LEVELS=3, For Sv48 LEVELS=4, For Sv57 LEVELS=5.) The satp register // must be active, i.e., the effective privilege mode must be S-mode or U-mode. if ( iohgatp.MODE == IOHGATP_Sv32x4 && g_reg_file.fctl.gxl == 1 ) { vpn[0] = get_bits(21, 12, gpa); @@ -88,14 +88,14 @@ second_stage_address_translation( // set beyond bit 33. gpa_upper_bits = get_bits(63, 34, gpa); } - // Address bits 63:MAX_GPA must all be zeros, or else a + // Address bits 63:MAX_GPA must all be zeros, or else a // guest-page-fault exception occurs. if ( gpa_upper_bits != 0 ) return GST_PAGE_FAULT; i = LEVELS - 1; // The root page table as determined by `iohgatp.PPN` is 16 KiB and must be aligned - // to a 16-KiB boundary. If the root page table is not aligned to 16 KiB as + // to a 16-KiB boundary. If the root page table is not aligned to 16 KiB as // required, then all entries in that G-stage root page table appear to an IOMMU as // `UNSPECIFIED` and any address an IOMMU may compute and use for accessing an // entry in the root page table is also `UNSPECIFIED`. @@ -105,9 +105,9 @@ second_stage_address_translation( // Count G stage page walks count_events(PV, PID, PSCV, PSCID, DID, GV, GSCID, G_PT_WALKS); - // 2. Let gpte be the value of the PTE at address a+gpa.vpn[i]×PTESIZE. (For + // 2. Let gpte be the value of the PTE at address a+gpa.vpn[i]×PTESIZE. (For // Sv32x4 PTESIZE=4. and for all other modes PTESIZE=8). If accessing pte - // violates a PMA or PMP check, raise an access-fault exception + // violates a PMA or PMP check, raise an access-fault exception // corresponding to the original access type. // If the address is beyond the maximum physical address width of the machine // then an access fault occurs @@ -117,10 +117,10 @@ second_stage_address_translation( if ( status & ACCESS_FAULT ) return GST_ACCESS_FAULT; if ( status & DATA_CORRUPTION) return GST_DATA_CORRUPTION; - // 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or + // 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or // encodings that are reserved for future standard use are set within pte, // stop and raise a page-fault exception to the original access type. - if ( (gpte->V == 0) || (gpte->R == 0 && gpte->W == 1) || + if ( (gpte->V == 0) || (gpte->R == 0 && gpte->W == 1) || ((gpte->PBMT != 0) && (g_reg_file.capabilities.Svpbmt == 0)) || (gpte->PBMT == 3) || (gpte->reserved != 0) ) @@ -128,10 +128,10 @@ second_stage_address_translation( // NAPOT PTEs behave identically to non-NAPOT PTEs within the address-translation // algorithm in Section 4.3.2, except that: - // a. If the encoding in pte is valid according to Table 5.1, then instead of - // returning the original value of pte, implicit reads of a NAPOT PTE - // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced - // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved + // a. If the encoding in pte is valid according to Table 5.1, then instead of + // returning the original value of pte, implicit reads of a NAPOT PTE + // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced + // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved // according to Table 5.1, then a page-fault exception must be raised. // i pte.ppn[i] Description pte.napot bits // 0 x xxxx xxx1 Reserved − @@ -141,16 +141,16 @@ second_stage_address_translation( // 0 x xxxx 0xxx Reserved − // ≥ 1 x xxxx xxxx Reserved − // b. Implicit reads of NAPOT page table entries may create address-translation - // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which - // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], - // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for + // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which + // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], + // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for // the address space identified in satp as loaded by step 0. if ( i != 0 && gpte->N ) return GST_PAGE_FAULT; - // 4. Otherwise, the PTE is valid. If gpte.r = 1 or gpte.x = 1, go to step 5. - // Otherwise, this PTE is a pointer to the next level of the page table. - // Let i = i − 1. If i < 0, stop and raise a page-fault exception - // corresponding to the original access type. Otherwise, let + // 4. Otherwise, the PTE is valid. If gpte.r = 1 or gpte.x = 1, go to step 5. + // Otherwise, this PTE is a pointer to the next level of the page table. + // Let i = i − 1. If i < 0, stop and raise a page-fault exception + // corresponding to the original access type. Otherwise, let // a = gpte.ppn × PAGESIZE and go to step 2. if ( gpte->R == 1 || gpte->X == 1 ) goto step_5; @@ -160,22 +160,22 @@ second_stage_address_translation( goto step_2; step_5: - // 5. A leaf PTE has been found. Determine if the requested memory access - // is allowed by the pte.r, pte.w, pte.x, and pte.u bits, given the current - // privilege mode and the value of the SUM and MXR fields of the mstatus - // register. If not, stop and raise a page-fault exception corresponding to + // 5. A leaf PTE has been found. Determine if the requested memory access + // is allowed by the pte.r, pte.w, pte.x, and pte.u bits, given the current + // privilege mode and the value of the SUM and MXR fields of the mstatus + // register. If not, stop and raise a page-fault exception corresponding to // the original access type. // g-stage page table specifc notes: - // when checking the U bit, the current privilege mode is always taken + // when checking the U bit, the current privilege mode is always taken // to be U-mode; - impiies that U must be always 1 to be legal // For PCIe ATS Translation Requests: - // If the translation could be successfully completed but the requested - // permissions are not present (Execute requested but no execute permission; - // no-write not requested and no write permission; no read permission) then a + // If the translation could be successfully completed but the requested + // permissions are not present (Execute requested but no execute permission; + // no-write not requested and no write permission; no read permission) then a // Success response is returned with the denied permission (R, W or X) set to 0 - // and the other permission bits set to value determined from the page tables. - // The X permission is granted only if the R permission is also granted. - // Execute-only translations are not compatible with PCIe ATS as PCIe requires + // and the other permission bits set to value determined from the page tables. + // The X permission is granted only if the R permission is also granted. + // Execute-only translations are not compatible with PCIe ATS as PCIe requires // read permission to be granted if the execute permission is granted. // No faults are caused here - the denied permissions will be reported back in // the ATS completion @@ -211,8 +211,8 @@ second_stage_address_translation( ppn[3] = get_bits(45, 37, gpte->raw); ppn[4] = get_bits(53, 46, gpte->raw); } - // 6. If i > 0 and gpte.ppn[i − 1 : 0] ̸= 0, this is a misaligned superpage; - // stop and raise a page-fault exception corresponding to the original + // 6. If i > 0 and gpte.ppn[i − 1 : 0] ̸= 0, this is a misaligned superpage; + // stop and raise a page-fault exception corresponding to the original // access type. *gst_page_sz = PAGESIZE; if ( i > 0 ) { @@ -225,17 +225,17 @@ second_stage_address_translation( *gst_page_sz *= 512UL; // 1GiB case 1: if ( ppn[0] ) return GST_PAGE_FAULT; *gst_page_sz *= 512UL; // 2MiB - if ( iohgatp.MODE == IOHGATP_Sv32x4 && + if ( iohgatp.MODE == IOHGATP_Sv32x4 && g_reg_file.fctl.gxl == 1 ) { *gst_page_sz *= 2UL; // 4MiB } } } - // a. If the encoding in pte is valid according to Table 5.1, then instead of - // returning the original value of pte, implicit reads of a NAPOT PTE - // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced - // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved + // a. If the encoding in pte is valid according to Table 5.1, then instead of + // returning the original value of pte, implicit reads of a NAPOT PTE + // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced + // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved // according to Table 5.1, then a page-fault exception must be raised. // i pte.ppn[i] Description pte.napot bits // 0 x xxxx xxx1 Reserved − @@ -247,7 +247,7 @@ second_stage_address_translation( if ( i == 0 && gpte->N && ((gpte->PPN & 0xF) != 0x8) ) return GST_PAGE_FAULT; - // 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0, + // 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0, // If `GADE` is 1, the IOMMU updates A and D bits in G-stage PTEs atomically. If // `GADE` is 0, the IOMMU causes a guest-page-fault corresponding to the original // access type if A bit is 0 or if the memory access is a store and the D bit is 0. @@ -257,7 +257,7 @@ second_stage_address_translation( // Perform the following steps atomically: // – Compare pte to the value of the PTE at address a + va.vpn[i] × PTESIZE. // – If the values match, set pte.a to 1 and, if the original memory access is a store, - // also set pte.d to 1. + // also set pte.d to 1. // – If the comparison fails, return to step 2 if ( (gpte->A == 1) && ( (gpte->D == 1) || (is_write == 0) || (gpte->W == 0) ) ) goto step_8; @@ -294,11 +294,11 @@ second_stage_address_translation( // 8. The translation is successful. // b. Implicit reads of NAPOT page table entries may create address-translation - // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which - // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], - // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for + // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which + // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], + // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for // the address space identified in satp as loaded by step 0. - if ( gpte->N ) + if ( gpte->N ) gpte->PPN = (gpte->PPN & ~0xF) | ((gpa / PAGESIZE) & 0xF); // The translated physical address is given as follows: diff --git a/iommu_ref_model/libiommu/src/iommu_translate.c b/iommu_ref_model/libiommu/src/iommu_translate.c index 6abb736c..76240a6e 100644 --- a/iommu_ref_model/libiommu/src/iommu_translate.c +++ b/iommu_ref_model/libiommu/src/iommu_translate.c @@ -5,7 +5,7 @@ #include "iommu.h" -void +void iommu_translate_iova( hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp_msg) { @@ -85,11 +85,11 @@ iommu_translate_iova( // a. Transaction type is a Translated request (read, write/AMO, read-for-execute) // or is a PCIe ATS Translation request. if ( g_reg_file.ddtp.iommu_mode == DDT_Bare ) { - if ( req->tr.at == ADDR_TYPE_TRANSLATED || + if ( req->tr.at == ADDR_TYPE_TRANSLATED || req->tr.at == ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; - } + } pa = req->tr.iova; page_sz = PAGESIZE; vs_pte.X = vs_pte.W = vs_pte.R = 1; @@ -120,14 +120,14 @@ iommu_translate_iova( // a. `ddtp.iommu_mode` is `2LVL` and `DDI[2]` is not 0 // b. `ddtp.iommu_mode` is `1LVL` and either `DDI[2]` is not 0 or `DDI[1]` is not 0 if ( g_reg_file.ddtp.iommu_mode == DDT_2LVL && DDI[2] != 0 ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; - } - + } + if ( g_reg_file.ddtp.iommu_mode == DDT_1LVL && (DDI[2] != 0 || DDI[1] != 0) ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; - } + } // 6. Use `device_id` to then locate the device-context (`DC`) as specified in // section 2.4.1 of IOMMU specification. @@ -144,29 +144,29 @@ iommu_translate_iova( // * Transaction has a valid `process_id` and `DC.tc.PDTV` is 1 and the // `process_id` is wider than supported by `pdtp.MODE`. // * Transaction type is not supported by the IOMMU. - if ( DC.tc.EN_ATS == 0 && ( req->tr.at == ADDR_TYPE_TRANSLATED || + if ( DC.tc.EN_ATS == 0 && ( req->tr.at == ADDR_TYPE_TRANSLATED || req->tr.at == ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST) ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; - } + } if ( req->pid_valid && DC.tc.PDTV == 0 ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; - } + } if ( req->pid_valid && DC.tc.PDTV == 1 ) { if ( DC.fsc.pdtp.MODE == PD17 && req->process_id > ((1UL << 17) - 1) ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; } if ( DC.fsc.pdtp.MODE == PD8 && (req->process_id > ((1UL << 8) - 1)) ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; } } - // 8. If request is a Translated request and DC.tc.T2GPA is 0 then the translation + // 8. If request is a Translated request and DC.tc.T2GPA is 0 then the translation // process is complete. Go to step 21 if ( (req->tr.at == ADDR_TYPE_TRANSLATED) && (DC.tc.T2GPA == 0) ) { pa = req->tr.iova; @@ -178,7 +178,7 @@ iommu_translate_iova( goto step_20; } - // 9. If request is a Translated request and DC.tc.T2GPA is 1 then the IOVA is a GPA. + // 9. If request is a Translated request and DC.tc.T2GPA is 1 then the IOVA is a GPA. // Go to step 17 with following page table information: // ◦ Let A bit the IOVA (the IOVA is a GPA) // ◦ Let iosatp.MODE be Bare @@ -191,12 +191,12 @@ iommu_translate_iova( goto step_17; } - //10. If `DC.tc.pdtv` is set to 0 then go to step 16 with the following + //10. If `DC.tc.pdtv` is set to 0 then go to step 16 with the following // page table information: // * Let `iosatp.MODE` be value in `DC.fsc.MODE` field // * Let `iosatp.PPN` be value in `DC.fsc.PPN` field // * Let `PSCID` be value in `DC.ta.PSCID` field - // * Let `iohgatp` be value in `DC.iohgatp` field + // * Let `iohgatp` be value in `DC.iohgatp` field // * If a G-stage page table is not active in the device-context // (`DC.iohgatp.mode` is `Bare`) then `iosatp` is a a S-stage page-table else // it is a VS-stage page table. @@ -238,11 +238,11 @@ iommu_translate_iova( if ( locate_process_context(&PC, &DC, req->device_id, req->process_id, &cause, &iotval2, TTYP) ) goto stop_and_report_fault; - // 15. if any of the following conditions hold then stop and report - // "Transaction type disallowed" (cause = 260). + // 15. if any of the following conditions hold then stop and report + // "Transaction type disallowed" (cause = 260). // a. The transaction requests supervisor privilege but PC.ta.ENS is not set. if ( PC.ta.ENS == 0 && req->pid_valid && req->priv_req ) { - cause = 260; // "Transaction type disallowed" + cause = 260; // "Transaction type disallowed" goto stop_and_report_fault; } @@ -250,7 +250,7 @@ iommu_translate_iova( // * Let `iosatp.MODE` be value in `PC.fsc.MODE` field // * Let `iosatp.PPN` be value in `PC.fsc.PPN` field // * Let `PSCID` be value in `PC.ta.PSCID` field - // * Let `iohgatp` be value in `DC.iohgatp` field + // * Let `iohgatp` be value in `DC.iohgatp` field // * If a G-stage page table is not active in the device-context // (`DC.iohgatp.mode` is `Bare`) then `iosatp` is a a S-stage page-table else // it is a VS-stage page table. @@ -275,7 +275,7 @@ iommu_translate_iova( PID = req->process_id; check_access_perms = ( TTYP != PCIE_ATS_TRANSLATION_REQUEST ) ? 1 : 0; if ( (ioatc_status = lookup_ioatc_iotlb(req->tr.iova, check_access_perms, priv, is_read, is_write, - is_exec, SUM, PSCV, PSCID, GV, GSCID, &cause, &pa, &page_sz, + is_exec, SUM, PSCV, PSCID, GV, GSCID, &cause, &pa, &page_sz, &vs_pte, &g_pte)) == IOATC_FAULT ) goto stop_and_report_fault; @@ -289,7 +289,7 @@ iommu_translate_iova( GV, GSCID, iohgatp, DC.tc.GADE, DC.tc.SXL, &cause, &iotval2, &gpa, &page_sz, &vs_pte) ) goto stop_and_report_fault; - + // 18. If MSI address translations using MSI page tables is enabled // (i.e., `DC.msiptp.MODE != Off`) then the MSI address translation process // specified in <> is invoked. If the GPA `A` is not determined to be @@ -306,7 +306,7 @@ iommu_translate_iova( // cite:[PRIV] to translate the GPA `A` to determine the SPA accessed by the // transaction. If a fault is detected by the address translation process then // stop and report the fault. - if ( (gst_fault = second_stage_address_translation(gpa, check_access_perms, DID, + if ( (gst_fault = second_stage_address_translation(gpa, check_access_perms, DID, is_read, is_write, is_exec, PV, PID, PSCV, PSCID, GV, GSCID, iohgatp, DC.tc.GADE, DC.tc.SXL, &pa, &gst_page_sz, &g_pte) ) ) { if ( gst_fault == GST_PAGE_FAULT ) goto guest_page_fault; @@ -315,7 +315,7 @@ iommu_translate_iova( } skip_gpa_trans: - // The page-based memory types (PBMT), if Svpbmt is supported, obtained + // The page-based memory types (PBMT), if Svpbmt is supported, obtained // from the IOMMU address translation page tables. When two-stage address // translation is performed the IOMMU provides the page-based memory type // as resolved between the G-stage and VS-stage page table @@ -339,12 +339,12 @@ iommu_translate_iova( // For Untranslated Requests cache the translations for future re-use cache_ioatc_iotlb(napot_iova, GV, PSCV, iohgatp.GSCID, PSCID, &vs_pte, &g_pte, napot_ppn, ((page_sz > PAGESIZE) ? 1 : 0)); - } + } if ( (TTYP == PCIE_ATS_TRANSLATION_REQUEST) && - ((DC.tc.T2GPA == 1 && ((g_fill_ats_trans_in_ioatc & FILL_IOATC_ATS_T2GPA) != 0) ) || + ((DC.tc.T2GPA == 1 && ((g_fill_ats_trans_in_ioatc & FILL_IOATC_ATS_T2GPA) != 0) ) || ((g_fill_ats_trans_in_ioatc & FILL_IOATC_ATS_ALWAYS) != 0)) ) { - // If in T2GPA mode, cache the final GPA->SPA translation as - // the translated requests may hit on this + // If in T2GPA mode, cache the final GPA->SPA translation as + // the translated requests may hit on this // If T2GPA is 0, then cache the IOVA->SPA translation if // IOMMU has been configured to do so cache_ioatc_iotlb((DC.tc.T2GPA == 1) ? napot_gpa : napot_iova, @@ -376,13 +376,13 @@ iommu_translate_iova( // the value in "Privilege Mode Requested" field as the permissions provided // correspond to those the privilege mode indicate in the request. // If Priv is Set, R, W, and Exe refer to permissions granted to entities operating - // in Privileged Mode in the requesting Function. If Priv is Clear, R, W, and Exe + // in Privileged Mode in the requesting Function. If Priv is Clear, R, W, and Exe // refer to permissions granted to entities operating in Non-Privileged Mode in the // requesting Function. - // Note: Since the Priv bit is Set only when the requesting Function Sets the - // Privileged Mode Requested bit, Functions that never set that bit should always + // Note: Since the Priv bit is Set only when the requesting Function Sets the + // Privileged Mode Requested bit, Functions that never set that bit should always // receive the Priv bit Clear and thus don’t need to cache it. - // An ATC that receives a translation with R=W=0b for one privilege level may not + // An ATC that receives a translation with R=W=0b for one privilege level may not // assume anything about what it might receive for the other privilege level. // * N field of the ATS translation completion is always set to 0. The device may // use other means to determine if the No-snoop flag should be set in the @@ -398,13 +398,13 @@ iommu_translate_iova( // * The AMA field is by default set to 000b. The IOMMU may support an // implementation specific method to provide other encodings. // If S is Set, then the translation applies to a range that is larger than - // 4096 bytes. If S = 1b, then bit 12 of the Translated Address is used to - // indicate whether or not the range is larger than 8192 bytes. If bit 12 + // 4096 bytes. If S = 1b, then bit 12 of the Translated Address is used to + // indicate whether or not the range is larger than 8192 bytes. If bit 12 // is 0b, then the range size is 8192 bytes, but it is larger than 8192 bytes - // if Set. If S = 1b and bit 12 = 1b, then bit 13 is used to determine if - // the range is la than 16384 bytes or not. If bit 13 is 0b, then the range - // size is 16384 bytes, but it is larger than 16384 bytes if Set. Low-order - // address bits are consumed in sequence to indicate the size of the range + // if Set. If S = 1b and bit 12 = 1b, then bit 13 is used to determine if + // the range is la than 16384 bytes or not. If bit 13 is 0b, then the range + // size is 16384 bytes, but it is larger than 16384 bytes if Set. Low-order + // address bits are consumed in sequence to indicate the size of the range // associated with the translation. // Address Bits |S |Translation // | | Range Size @@ -415,21 +415,21 @@ iommu_translate_iova( // x x x x x x x x x x x x 0 1 1 1 1 1 1 1 1 |1 | 2M // x x x x x x x x x x x 0 1 1 1 1 1 1 1 1 1 |1 | 4M // x 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 |1 | 1G - // If the translation could be successfully completed but the requested - // permissions are not present (Execute requested but no execute permission; - // no-write not requested and no write permission; no read permission) then a + // If the translation could be successfully completed but the requested + // permissions are not present (Execute requested but no execute permission; + // no-write not requested and no write permission; no read permission) then a // Success response is returned with the denied permission (R, W or X) set to 0 - // and the other permission bits set to value determined from the page tables. + // and the other permission bits set to value determined from the page tables. // The X permission is granted only if the R permission is also granted - // and execute permission was requested. - // Execute-only translations are not compatible with PCIe ATS as PCIe requires + // and execute permission was requested. + // Execute-only translations are not compatible with PCIe ATS as PCIe requires // read permission to be granted if the execute permission is granted. - // When a Success response is generated for a ATS translation request, no fault - // records are reported to software through the fault/event reporting mechanism; - // even when the response indicates no access was granted or some permissions + // When a Success response is generated for a ATS translation request, no fault + // records are reported to software through the fault/event reporting mechanism; + // even when the response indicates no access was granted or some permissions // were denied. - // If the translation request has an address determined to be an MSI address - // using the rules defined by the Section 2.1.3.6 but the MSI PTE is configured + // If the translation request has an address determined to be an MSI address + // using the rules defined by the Section 2.1.3.6 but the MSI PTE is configured // in MRIF mode then a Success response is generated with R, W, and U bit set to // 1. The U bit being set to 1 in the response instructs the device that it must // only use Untranslated requests to access the implied 4 KiB memory range @@ -453,12 +453,12 @@ iommu_translate_iova( rsp_msg->status = COMPLETER_ABORT; return; -data_corruption: +data_corruption: cause = 274; // First/second-stage PT data corruption goto stop_and_report_fault; -access_fault: - // Stop and raise a access-fault exception corresponding +access_fault: + // Stop and raise a access-fault exception corresponding // to the original access type. if ( is_exec ) cause = 1; // Instruction access fault else if ( is_read ) cause = 5; // Read access fault @@ -466,7 +466,7 @@ iommu_translate_iova( goto stop_and_report_fault; guest_page_fault: - // Stop and raise a page-fault exception corresponding + // Stop and raise a page-fault exception corresponding // to the original access type. if ( is_exec ) cause = 20; // Instruction guest page fault else if ( is_read ) cause = 21; // Read guest page fault diff --git a/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c b/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c index 7f7c2524..bbeda709 100644 --- a/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c +++ b/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c @@ -12,7 +12,7 @@ two_stage_address_translation( uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID, iosatp_t iosatp, uint8_t priv, uint8_t SUM, uint8_t SADE, uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL, - uint32_t *cause, uint64_t *iotval2, uint64_t *pa, + uint32_t *cause, uint64_t *iotval2, uint64_t *pa, uint64_t *page_sz, pte_t *pte) { uint16_t vpn[5]; @@ -25,15 +25,15 @@ two_stage_address_translation( uint64_t a, masked_upper_bits, mask; uint64_t gst_page_sz; uint64_t pa_mask = ((1UL << (g_reg_file.capabilities.pas)) - 1); - + // Indicate S/VS-stage page size as largest possible page size - if ( g_reg_file.capabilities.Sv57 == 1 ) + if ( g_reg_file.capabilities.Sv57 == 1 ) *page_sz = 512UL * 512UL * 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv48 == 1 ) + else if ( g_reg_file.capabilities.Sv48 == 1 ) *page_sz = 512UL * 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv39 == 1 ) + else if ( g_reg_file.capabilities.Sv39 == 1 ) *page_sz = 512UL * 512UL * PAGESIZE; - else if ( g_reg_file.capabilities.Sv32 == 1 ) + else if ( g_reg_file.capabilities.Sv32 == 1 ) *page_sz = 2UL * 512UL * PAGESIZE; *iotval2 = 0; @@ -51,8 +51,8 @@ two_stage_address_translation( goto step_8; } - // 1. Let a be satp.ppn × PAGESIZE, and let i = LEVELS − 1. PAGESIZE is 2^12. (For Sv32, - // LEVELS=2, For Sv39 LEVELS=3, For Sv48 LEVELS=4, For Sv57 LEVELS=5.) The satp register + // 1. Let a be satp.ppn × PAGESIZE, and let i = LEVELS − 1. PAGESIZE is 2^12. (For Sv32, + // LEVELS=2, For Sv39 LEVELS=3, For Sv48 LEVELS=4, For Sv57 LEVELS=5.) The satp register // must be active, i.e., the effective privilege mode must be S-mode or U-mode. if ( iosatp.MODE == IOSATP_Sv32 && SXL == 1 ) { vpn[0] = get_bits(21, 12, iova); @@ -95,8 +95,8 @@ two_stage_address_translation( mask = (1UL << (64 - 56)) - 1; masked_upper_bits = (iova >> 56) & mask; } - // Instruction fetch addresses and load and store effective addresses, - // which are 64 bits, must have bits 63: all equal to bit + // Instruction fetch addresses and load and store effective addresses, + // which are 64 bits, must have bits 63: all equal to bit // (VASIZE-1), or else a page-fault exception will occur - for SXL=0 // Do the address is canonical check - for SXL=0 // For SXL = 1 check bits 63:32 are all 0 @@ -106,9 +106,9 @@ two_stage_address_translation( i = LEVELS - 1; a = iosatp.PPN * PAGESIZE; step_2: - // 2. Let pte be the value of the PTE at address a+va.vpn[i]×PTESIZE. (For + // 2. Let pte be the value of the PTE at address a+va.vpn[i]×PTESIZE. (For // Sv32 PTESIZE=4. and for all other modes PTESIZE=8). If accessing pte - // violates a PMA or PMP check, raise an access-fault exception + // violates a PMA or PMP check, raise an access-fault exception // corresponding to the original access type. pte->raw = 0; a = a + vpn[i] * PTESIZE; @@ -138,10 +138,10 @@ two_stage_address_translation( if ( status & ACCESS_FAULT ) goto access_fault; if ( status & DATA_CORRUPTION) goto data_corruption; - // 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or + // 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or // encodings that are reserved for future standard use are set within pte, // stop and raise a page-fault exception to the original access type. - if ( (pte->V == 0) || (pte->R == 0 && pte->W == 1) || + if ( (pte->V == 0) || (pte->R == 0 && pte->W == 1) || ((pte->PBMT != 0) && (g_reg_file.capabilities.Svpbmt == 0)) || (pte->PBMT == 3) || (pte->reserved != 0) ) @@ -149,10 +149,10 @@ two_stage_address_translation( // NAPOT PTEs behave identically to non-NAPOT PTEs within the address-translation // algorithm in Section 4.3.2, except that: - // a. If the encoding in pte is valid according to Table 5.1, then instead of - // returning the original value of pte, implicit reads of a NAPOT PTE - // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced - // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved + // a. If the encoding in pte is valid according to Table 5.1, then instead of + // returning the original value of pte, implicit reads of a NAPOT PTE + // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced + // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved // according to Table 5.1, then a page-fault exception must be raised. // i pte.ppn[i] Description pte.napot bits // 0 x xxxx xxx1 Reserved − @@ -162,26 +162,26 @@ two_stage_address_translation( // 0 x xxxx 0xxx Reserved − // ≥ 1 x xxxx xxxx Reserved − // b. Implicit reads of NAPOT page table entries may create address-translation - // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which - // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], - // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for + // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which + // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], + // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for // the address space identified in satp as loaded by step 0. if ( i != 0 && pte->N ) goto page_fault; - // 4. Otherwise, the PTE is valid. If pte.r = 1 or pte.x = 1, go to step 5. - // Otherwise, this PTE is a pointer to the next level of the page table. - // Let i = i − 1. If i < 0, stop and raise a page-fault exception - // corresponding to the original access type. Otherwise, let + // 4. Otherwise, the PTE is valid. If pte.r = 1 or pte.x = 1, go to step 5. + // Otherwise, this PTE is a pointer to the next level of the page table. + // Let i = i − 1. If i < 0, stop and raise a page-fault exception + // corresponding to the original access type. Otherwise, let // a = pte.ppn × PAGESIZE and go to step 2. if ( pte->R == 1 || pte->X == 1 ) goto step_5; - // The G bit designates a global mapping. Global mappings are those that exist - // in all address spaces. For non-leaf PTEs, the global setting implies that + // The G bit designates a global mapping. Global mappings are those that exist + // in all address spaces. For non-leaf PTEs, the global setting implies that // all mappings in the subsequent levels of the page table are global. NL_G = NL_G & pte->G; - // For non-leaf PTEs, bits 62–61 are reserved for future standard use. Until - // their use is defined by a standard extension, they must be cleared by + // For non-leaf PTEs, bits 62–61 are reserved for future standard use. Until + // their use is defined by a standard extension, they must be cleared by // software for forward compatibility, or else a page-fault exception is raised. if ( pte->PBMT != 0 ) goto page_fault; @@ -191,19 +191,19 @@ two_stage_address_translation( goto step_2; step_5: - // 5. A leaf PTE has been found. Determine if the requested memory access - // is allowed by the pte.r, pte.w, pte.x, and pte.u bits, given the current - // privilege mode and the value of the SUM and MXR fields of the mstatus - // register. If not, stop and raise a page-fault exception corresponding to + // 5. A leaf PTE has been found. Determine if the requested memory access + // is allowed by the pte.r, pte.w, pte.x, and pte.u bits, given the current + // privilege mode and the value of the SUM and MXR fields of the mstatus + // register. If not, stop and raise a page-fault exception corresponding to // the original access type. // For PCIe ATS Translation Requests: - // If the translation could be successfully completed but the requested - // permissions are not present (Execute requested but no execute permission; - // no-write not requested and no write permission; no read permission) then a + // If the translation could be successfully completed but the requested + // permissions are not present (Execute requested but no execute permission; + // no-write not requested and no write permission; no read permission) then a // Success response is returned with the denied permission (R, W or X) set to 0 - // and the other permission bits set to value determined from the page tables. - // The X permission is granted only if the R permission is also granted. - // Execute-only translations are not compatible with PCIe ATS as PCIe requires + // and the other permission bits set to value determined from the page tables. + // The X permission is granted only if the R permission is also granted. + // Execute-only translations are not compatible with PCIe ATS as PCIe requires // read permission to be granted if the execute permission is granted. // No faults are caused here - the denied permissions will be reported back in // the ATS completion @@ -214,14 +214,14 @@ two_stage_address_translation( } if ( (priv == U_MODE) && (pte->U == 0) ) goto page_fault; - // When ENS is 1, supervisor privilege transactions that read with - // execute intent to pages mapped with U bit in PTE set to 1 will fault, + // When ENS is 1, supervisor privilege transactions that read with + // execute intent to pages mapped with U bit in PTE set to 1 will fault, // regardless of the state of SUM. if ( is_exec && (priv == S_MODE) && (pte->U == 1) ) goto page_fault; - // When ENS is 1, the SUM (permit Supervisor User Memory access) bit modifies - // the privilege with which supervisor privilege transactions access virtual - // memory. When SUM is 0, supervisor privilege transactions to pages mapped + // When ENS is 1, the SUM (permit Supervisor User Memory access) bit modifies + // the privilege with which supervisor privilege transactions access virtual + // memory. When SUM is 0, supervisor privilege transactions to pages mapped // with U-bit in PTE set to 1 will fault. if ( (priv == S_MODE) && !is_exec && SUM == 0 && pte->U == 1 ) goto page_fault; @@ -248,8 +248,8 @@ two_stage_address_translation( ppn[3] = get_bits(45, 37, pte->raw); ppn[4] = get_bits(53, 46, pte->raw); } - // 6. If i > 0 and pte.ppn[i − 1 : 0] = 0, this is a misaligned superpage; - // stop and raise a page-fault exception corresponding to the original + // 6. If i > 0 and pte.ppn[i − 1 : 0] = 0, this is a misaligned superpage; + // stop and raise a page-fault exception corresponding to the original // access type. *page_sz = PAGESIZE; if ( i > 0 ) { @@ -268,10 +268,10 @@ two_stage_address_translation( } } - // a. If the encoding in pte is valid according to Table 5.1, then instead of - // returning the original value of pte, implicit reads of a NAPOT PTE - // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced - // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved + // a. If the encoding in pte is valid according to Table 5.1, then instead of + // returning the original value of pte, implicit reads of a NAPOT PTE + // return a copy of pte in which pte.ppn[pte.napot bits − 1 : 0] is replaced + // by vpn[i][pte.napot bits − 1 : 0]. If the encoding in pte is reserved // according to Table 5.1, then a page-fault exception must be raised. // i pte.ppn[i] Description pte.napot bits // 0 x xxxx xxx1 Reserved − @@ -282,7 +282,7 @@ two_stage_address_translation( // ≥ 1 x xxxx xxxx Reserved − if ( i == 0 && pte->N && ((pte->PPN & 0xF) != 0x8) ) goto page_fault; - // 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0, + // 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0, // If SADE is 1, the IOMMU updates A and D bits in first-stage PTEs atomically. If // SADE is 0, the IOMMU causes a page-fault corresponding to the original access type // if the A bit is 0 or if the memory access is a store and the D bit is 0. @@ -290,7 +290,7 @@ two_stage_address_translation( // corresponding to the original access type. // Perform the following steps atomically: // – Compare pte to the value of the PTE at address a + va.vpn[i] × PTESIZE. - // – If the values match, set pte.a to 1 and, if the original memory access is a store, + // – If the values match, set pte.a to 1 and, if the original memory access is a store, // also set pte.d to 1. // – If the comparison fails, return to step 2 if ( (pte->A == 1) && ( (pte->D == 1) || (is_write == 0) || (pte->W == 0) ) ) goto step_8; @@ -328,15 +328,15 @@ two_stage_address_translation( // 8. The translation is successful. // b. Implicit reads of NAPOT page table entries may create address-translation - // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which - // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], - // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for + // cache entries mapping a + va.vpn[j] × PTESIZE to a copy of pte in which + // pte.ppn[pte.napot bits − 1 : 0] is replaced by vpn[0][pte.napot bits − 1 : 0], + // for any or all j such that j[8 : napot bits] = i[8 : napot bits], all for // the address space identified in satp as loaded by step 0. - if ( pte->N ) + if ( pte->N ) pte->PPN = (pte->PPN & ~0xF) | ((iova / PAGESIZE) & 0xF); - // The G bit designates a global mapping. Global mappings are those that exist - // in all address spaces. For non-leaf PTEs, the global setting implies that + // The G bit designates a global mapping. Global mappings are those that exist + // in all address spaces. For non-leaf PTEs, the global setting implies that // all mappings in the subsequent levels of the page table are global. pte->G = NL_G & pte->G; @@ -348,27 +348,27 @@ two_stage_address_translation( return 0; page_fault: - // Stop and raise a page-fault exception corresponding + // Stop and raise a page-fault exception corresponding // to the original access type. if ( is_exec ) *cause = 12; // Instruction page fault else if ( is_read ) *cause = 13; // Read page fault else *cause = 15; // Write/AMO page fault return 1; -access_fault: - // Stop and raise a access-fault exception corresponding +access_fault: + // Stop and raise a access-fault exception corresponding // to the original access type. if ( is_exec ) *cause = 1; // Instruction access fault else if ( is_read ) *cause = 5; // Read access fault else *cause = 7; // Write/AMO access fault return 1; -data_corruption: +data_corruption: *cause = 274; // First/Second-stage PT data corruption return 1; guest_page_fault: - // Stop and raise a page-fault exception corresponding + // Stop and raise a page-fault exception corresponding // to the original access type. if ( is_exec ) *cause = 20; // Instruction guest page fault else if ( is_read ) *cause = 21; // Read guest page fault diff --git a/iommu_ref_model/libtables/src/build_ddt.c b/iommu_ref_model/libtables/src/build_ddt.c index d4d8b292..824a5cdd 100644 --- a/iommu_ref_model/libtables/src/build_ddt.c +++ b/iommu_ref_model/libtables/src/build_ddt.c @@ -12,8 +12,8 @@ add_dev_context( uint8_t i, LEVELS, DC_SIZE; ddte_t ddte; uint16_t DDI[3]; - // The DDT used to locate the DC may be configured to be a 1, 2, or 3 level - // radix-table depending on the maximum width of the device_id supported. + // The DDT used to locate the DC may be configured to be a 1, 2, or 3 level + // radix-table depending on the maximum width of the device_id supported. // The partitioning of the device_id to obtain the device directory indexes // (DDI) to traverse the DDT radix-tree table are as follows: if ( g_reg_file.capabilities.msi_flat == 0 ) { diff --git a/iommu_ref_model/test/tbapi.c b/iommu_ref_model/test/tbapi.c index 721627d4..3e935795 100644 --- a/iommu_ref_model/test/tbapi.c +++ b/iommu_ref_model/test/tbapi.c @@ -9,7 +9,7 @@ #include "tables_api.h" #include "test_app.h" -uint8_t +uint8_t read_memory( uint64_t addr, uint8_t size, char *data){ if ( addr == access_viol_addr ) return ACCESS_FAULT; @@ -18,23 +18,23 @@ read_memory( return 0; } -uint8_t +uint8_t read_memory_for_AMO( uint64_t addr, uint8_t size, char *data) { // Same for now return read_memory(addr, size, data); } -uint8_t +uint8_t write_memory( char *data, uint64_t addr, uint32_t size) { if ( addr == access_viol_addr ) return ACCESS_FAULT; if ( addr == data_corruption_addr ) return DATA_CORRUPTION; memcpy(&memory[addr], data, size); return 0; -} +} -void +void iommu_to_hb_do_global_observability_sync( uint8_t PR, uint8_t PW){ pr_go_requested = PR; @@ -42,7 +42,7 @@ iommu_to_hb_do_global_observability_sync( return; } -void +void send_msg_iommu_to_hb( ats_msg_t *msg) { if ( exp_msg.MSGCODE != msg->MSGCODE || @@ -63,31 +63,31 @@ send_msg_iommu_to_hb( return; } -void +void get_attribs_from_req( hb_to_iommu_req_t *req, uint8_t *read, uint8_t *write, uint8_t *exec, uint8_t *priv) { *read = ( req->tr.read_writeAMO == READ ) ? 1 : 0; *write = ( req->tr.read_writeAMO == WRITE ) ? 1 : 0; - // The No Write flag, when Set, indicates that the Function is requesting read-only + // The No Write flag, when Set, indicates that the Function is requesting read-only // access for this translation. - // The TA (IOMMU) may ignore the No Write Flag, however, if the TA responds with a - // translation marked as read-only then the Function must not issue Memory Write + // The TA (IOMMU) may ignore the No Write Flag, however, if the TA responds with a + // translation marked as read-only then the Function must not issue Memory Write // transactions using that translation. In this case, the Function may issue another - // translation request with the No Write flag Clear, which may result in a new + // translation request with the No Write flag Clear, which may result in a new // translation completion with or without the W (Write) bit Set. // Upon receiving a Translation Request with the NW flag Clear, TAs are permitted to - // mark the associated pages dirty. Functions MUST not issue such Requests + // mark the associated pages dirty. Functions MUST not issue such Requests // unless they have been given explicit write permission. // Note ATS Translation requests are read - so read_writeAMO is READ for these requests - *write = ( (req->tr.at == ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST) && - (req->no_write == 0) ) ? 1 : *write; + *write = ( (req->tr.at == ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST) && + (req->no_write == 0) ) ? 1 : *write; - // If a Translation Request has a PASID, the Untranslated Address Field is an address + // If a Translation Request has a PASID, the Untranslated Address Field is an address // within the process address space indicated by the PASID field. - // If a Translation Request has a PASID with either the Privileged Mode Requested - // or Execute Requested bit Set, these may be used in constructing the Translation + // If a Translation Request has a PASID with either the Privileged Mode Requested + // or Execute Requested bit Set, these may be used in constructing the Translation // Completion Data Entry. The PASID Extended Capability indicates whether a Function // supports and is enabled to send and receive TLPs with the PASID. *exec = ( (*read && req->exec_req && diff --git a/iommu_ref_model/test/test_app.c b/iommu_ref_model/test/test_app.c index 44b9c8d9..db2d4b05 100644 --- a/iommu_ref_model/test/test_app.c +++ b/iommu_ref_model/test/test_app.c @@ -42,7 +42,7 @@ main(void) { cqt_t cqt; cqh_t cqh; command_t cmd; - hb_to_iommu_req_t req; + hb_to_iommu_req_t req; iommu_to_hb_rsp_t rsp; tr_req_iova_t tr_req_iova; tr_req_ctrl_t tr_req_ctrl; @@ -68,7 +68,7 @@ main(void) { cap.pas = 50; cap.pd20 = cap.pd17 = cap.pd8 = 1; - fail_if( ( reset_iommu(8, 40, 0xff, 3, Off, DDT_3LVL, 0xFFFFFF, 0, 0, + fail_if( ( reset_iommu(8, 40, 0xff, 3, Off, DDT_3LVL, 0xFFFFFF, 0, 0, (FILL_IOATC_ATS_T2GPA | FILL_IOATC_ATS_ALWAYS), cap, fctl) < 0 ) ); for ( i = MSI_ADDR_0_OFFSET; i <= MSI_ADDR_7_OFFSET; i += 16 ) { @@ -145,10 +145,10 @@ main(void) { priv_req, 0, at, 0xdeadbeef, 16, READ, &req, &rsp); if ( at == ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST ) { fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 260, 0) < 0 ) ); - } + } if ( at == ADDR_TYPE_TRANSLATED ) { fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 260, 0) < 0 ) ); - } + } if ( at == ADDR_TYPE_UNTRANSLATED ) { fail_if( ( check_rsp_and_faults(&req, &rsp, SUCCESS, 0, 0) < 0 ) ); } @@ -182,7 +182,7 @@ main(void) { START_TEST("Too wide device_id"); fail_if( ( enable_iommu(DDT_1LVL) < 0 ) ); - send_translation_request(0x000145, 0, 0x99, 0, 0, 0, 0, + send_translation_request(0x000145, 0, 0x99, 0, 0, 0, 0, UNTRANSLATED_REQUEST, 0, 1, READ, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 260, 0) < 0 ) ); pr.MSGCODE = PAGE_REQ_MSG_CODE; @@ -210,7 +210,7 @@ main(void) { fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); fail_if( ( enable_iommu(DDT_2LVL) < 0 ) ); - send_translation_request(0x012345, 0, 0x99, 0, 0, 0, 0, + send_translation_request(0x012345, 0, 0x99, 0, 0, 0, 0, UNTRANSLATED_REQUEST, 0, 1, READ, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 260, 0) < 0 ) ); @@ -508,8 +508,8 @@ main(void) { START_TEST("Device context invalid"); // Add a device 0x012345 to guest with GSCID=1 - DC_addr = add_device(0x012345, 1, 0, 0, 0, 0, 0, - 1, 1, 0, 0, 0, + DC_addr = add_device(0x012345, 1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, IOHGATP_Sv48x4, IOSATP_Bare, PDTP_Bare, MSIPTP_Flat, 1, 0xFFFFFFFFFF, 0x1000000000); (void)(DC_addr); @@ -827,7 +827,7 @@ main(void) { g_reg_file.capabilities.Sv57 = 1; - DC.tc.SXL = 1; + DC.tc.SXL = 1; DC.fsc.iosatp.MODE = IOSATP_Sv32; g_reg_file.capabilities.Sv32 = 0; write_memory((char *)&DC, DC_addr, 64); @@ -835,36 +835,36 @@ main(void) { priv_req, 0, at, 0xdeadbeef, 16, (no_write ^ 1), &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 259, 0) < 0 ) ); g_reg_file.capabilities.Sv32 = 1; - DC.tc.SXL = 0; + DC.tc.SXL = 0; DC.fsc.iosatp.MODE = temp; write_memory((char *)&DC, DC_addr, 64); - DC.tc.DPE = 1; + DC.tc.DPE = 1; write_memory((char *)&DC, DC_addr, 64); send_translation_request(0x012345, pid_valid, 0x99, no_write, exec_req, priv_req, 0, at, 0xdeadbeef, 16, (no_write ^ 1), &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 259, 0) < 0 ) ); - DC.tc.DPE = 0; + DC.tc.DPE = 0; write_memory((char *)&DC, DC_addr, 64); g_reg_file.fctl.gxl = 1; temp = DC.iohgatp.MODE; - DC.iohgatp.MODE = IOHGATP_Sv39x4; + DC.iohgatp.MODE = IOHGATP_Sv39x4; write_memory((char *)&DC, DC_addr, 64); send_translation_request(0x012345, pid_valid, 0x99, no_write, exec_req, priv_req, 0, at, 0xdeadbeef, 16, (no_write ^ 1), &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 259, 0) < 0 ) ); - DC.iohgatp.MODE = IOHGATP_Sv32x4; + DC.iohgatp.MODE = IOHGATP_Sv32x4; write_memory((char *)&DC, DC_addr, 64); g_reg_file.capabilities.Sv32x4 = 0; send_translation_request(0x012345, pid_valid, 0x99, no_write, exec_req, priv_req, 0, at, 0xdeadbeef, 16, (no_write ^ 1), &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 259, 0) < 0 ) ); - DC.iohgatp.MODE = temp; + DC.iohgatp.MODE = temp; write_memory((char *)&DC, DC_addr, 64); g_reg_file.capabilities.Sv32x4 = 1; g_reg_file.fctl.gxl = 0; @@ -1055,7 +1055,7 @@ main(void) { fail_if( ( iofence_data != 0x1234567812345678 ) ); fail_if( ( 0 != pr_go_requested ) ); - // fix the illegal commend + // fix the illegal commend cqb.raw = read_register(CQB_OFFSET, 8); cqh.raw = read_register(CQH_OFFSET, 4); read_memory(((cqb.ppn * PAGESIZE) | (cqh.index * 16)), 16, (char *)&cmd); @@ -1095,7 +1095,7 @@ main(void) { fail_if( ( (read_register(CQH_OFFSET, 4) + 1) != read_register(CQT_OFFSET, 4) ) ); // Clear the illegal write_register(CQCSR_OFFSET, 4, cqcsr.raw); - // fix the illegal commend + // fix the illegal commend cqb.raw = read_register(CQB_OFFSET, 8); cqh.raw = read_register(CQH_OFFSET, 4); read_memory(((cqb.ppn * PAGESIZE) | (cqh.index * 16)), 16, (char *)&cmd); @@ -1336,7 +1336,7 @@ main(void) { iotinval(GVMA, 1, 0, 0, DC.iohgatp.GSCID, 0, 0); for ( i = 0; i < 5; i++ ) { if ( (i == 4) && DC.iohgatp.MODE != IOHGATP_Sv57x4 ) continue; - if ( (i == 3) && DC.iohgatp.MODE != IOHGATP_Sv48x4 && + if ( (i == 3) && DC.iohgatp.MODE != IOHGATP_Sv48x4 && DC.iohgatp.MODE != IOHGATP_Sv57x4 ) continue; gpa = gpa | ((1 << (i * 9)) * PAGESIZE) | 2048; req.tr.iova = gpa; @@ -1344,9 +1344,9 @@ main(void) { gpte.PPN |= (1UL << (i * 9UL)); pte_addr = add_g_stage_pte(DC.iohgatp, gpa, gpte, i); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); - fail_if( ( rsp.trsp.S == 1 && i == 0 ) ); - fail_if( ( rsp.trsp.S == 0 && i != 0 ) ); + fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.trsp.S == 1 && i == 0 ) ); + fail_if( ( rsp.trsp.S == 0 && i != 0 ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 0 ) ); @@ -1360,10 +1360,10 @@ main(void) { temp = 0xFFF; } fail_if( ( ((rsp.trsp.PPN * PAGESIZE) & ~temp) != (gpte.PPN * PAGESIZE) ) ); - fail_if( ( ((temp + 1) != PAGESIZE) && i == 0 ) ); - fail_if( ( ((temp + 1) != 512UL * PAGESIZE) && i == 1 ) ); - fail_if( ( ((temp + 1) != 512UL * 512UL * PAGESIZE) && i == 2 ) ); - fail_if( ( ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) && i == 3 ) ); + fail_if( ( ((temp + 1) != PAGESIZE) && i == 0 ) ); + fail_if( ( ((temp + 1) != 512UL * PAGESIZE) && i == 1 ) ); + fail_if( ( ((temp + 1) != 512UL * 512UL * PAGESIZE) && i == 2 ) ); + fail_if( ( ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) && i == 3 ) ); // Test for walking past max levels if ( i == 0 ) { @@ -1373,7 +1373,7 @@ main(void) { write_memory((char *)&pte, pte_addr, 8); iotinval(VMA, 0, 0, 0, 0, 0, 0); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.R != 0 ) ); fail_if( ( rsp.trsp.W != 0 ) ); pte.X = 1; @@ -1400,7 +1400,7 @@ main(void) { gpa = 512UL * 512UL * PAGESIZE; req.tr.iova = gpa; iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 1 ) ); @@ -1410,10 +1410,10 @@ main(void) { fail_if( ( rsp.trsp.S != 1 ) ); temp = rsp.trsp.PPN ^ (rsp.trsp.PPN + 1); temp = temp * PAGESIZE | 0xFFF; - fail_if( ( i == 0 && ((temp + 1) != 2 * 512UL * PAGESIZE) ) ); - fail_if( ( i == 1 && ((temp + 1) != 512UL * 512UL * PAGESIZE) ) ); - fail_if( ( i == 2 && ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) ) ); - fail_if( ( i == 3 && ((temp + 1) != 512UL * 512UL * 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 0 && ((temp + 1) != 2 * 512UL * PAGESIZE) ) ); + fail_if( ( i == 1 && ((temp + 1) != 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 2 && ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 3 && ((temp + 1) != 512UL * 512UL * 512UL * 512UL * PAGESIZE) ) ); } END_TEST(); @@ -1543,23 +1543,23 @@ main(void) { req.tr.length = 64; req.tr.read_writeAMO = READ; iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); gpte.PPN = 512UL * 512UL * 512UL ; write_memory((char *)&gpte, gpte_addr, 8); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); iotinval(GVMA, 1, 0, 0, 1, 0, 0); iommu_translate_iova(&req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 21, ((gpa >> 2) << 2)) < 0 ) ); gpte.PPN = 512UL * 512UL * 512UL * 512UL; write_memory((char *)&gpte, gpte_addr, 8); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); iotinval(GVMA, 1, 1, 0, 1, 0, req.tr.iova); gpte.W = 0; write_memory((char *)&gpte, gpte_addr, 8); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); req.tr.read_writeAMO = WRITE; iommu_translate_iova(&req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, ((gpa >> 2) << 2)) < 0 ) ); @@ -1567,11 +1567,11 @@ main(void) { write_memory((char *)&gpte, gpte_addr, 8); iotinval(GVMA, 1, 1, 0, 1, 0, req.tr.iova); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); END_TEST(); START_TEST("S-stage translation sizes"); - DC_addr = add_device(0x012349, 1, 1, 1, 0, 0, 1, + DC_addr = add_device(0x012349, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, IOHGATP_Bare, IOSATP_Sv57, PDTP_Bare, MSIPTP_Flat, 1, 0xF0F00FF0FF, 0x1903020124); @@ -1611,7 +1611,7 @@ main(void) { iodir(INVAL_DDT, 1, 0x012349, 0); for ( i = 0; i < 5; i++ ) { if ( (i == 4) && DC.fsc.iosatp.MODE != IOSATP_Sv57 ) continue; - if ( (i == 3) && DC.fsc.iosatp.MODE != IOSATP_Sv48 && + if ( (i == 3) && DC.fsc.iosatp.MODE != IOSATP_Sv48 && DC.fsc.iosatp.MODE != IOSATP_Sv57 ) continue; gva = gva | ((1 << (i * 9)) * PAGESIZE) | 2048; req.tr.iova = gva; @@ -1619,9 +1619,9 @@ main(void) { pte.PPN |= (1UL << (i * 9UL)); pte_addr = add_s_stage_pte(DC.fsc.iosatp, gva, pte, i); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); - fail_if( ( rsp.trsp.S == 1 && i == 0 ) ); - fail_if( ( rsp.trsp.S == 0 && i != 0 ) ); + fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.trsp.S == 1 && i == 0 ) ); + fail_if( ( rsp.trsp.S == 0 && i != 0 ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 0 ) ); @@ -1635,11 +1635,11 @@ main(void) { temp = 0xFFF; } fail_if( ( ((rsp.trsp.PPN * PAGESIZE) & ~temp) != (pte.PPN * PAGESIZE) ) ); - fail_if( ( ((temp + 1) != PAGESIZE) && i == 0 ) ); - fail_if( ( ((temp + 1) != 512UL * PAGESIZE) && i == 1 ) ); - fail_if( ( ((temp + 1) != 512UL * 512UL * PAGESIZE) && i == 2 ) ); - fail_if( ( ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) && i == 3 ) ); - + fail_if( ( ((temp + 1) != PAGESIZE) && i == 0 ) ); + fail_if( ( ((temp + 1) != 512UL * PAGESIZE) && i == 1 ) ); + fail_if( ( ((temp + 1) != 512UL * 512UL * PAGESIZE) && i == 2 ) ); + fail_if( ( ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) && i == 3 ) ); + // Test for walking past max levels if ( i == 0 ) { pte.X = 0; @@ -1648,7 +1648,7 @@ main(void) { write_memory((char *)&pte, pte_addr, 8); iotinval(VMA, 0, 0, 0, 0, 0, 0); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.R != 0 ) ); fail_if( ( rsp.trsp.W != 0 ) ); pte.X = 1; @@ -1675,7 +1675,7 @@ main(void) { gva = 512UL * 512UL * PAGESIZE; req.tr.iova = gva; iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 1 ) ); @@ -1685,10 +1685,10 @@ main(void) { fail_if( ( rsp.trsp.S != 1 ) ); temp = rsp.trsp.PPN ^ (rsp.trsp.PPN + 1); temp = temp * PAGESIZE | 0xFFF; - fail_if( ( i == 0 && ((temp + 1) != 2 * 512UL * PAGESIZE) ) ); - fail_if( ( i == 1 && ((temp + 1) != 512UL * 512UL * PAGESIZE) ) ); - fail_if( ( i == 2 && ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) ) ); - fail_if( ( i == 3 && ((temp + 1) != 512UL * 512UL * 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 0 && ((temp + 1) != 2 * 512UL * PAGESIZE) ) ); + fail_if( ( i == 1 && ((temp + 1) != 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 2 && ((temp + 1) != 512UL * 512UL * 512UL * PAGESIZE) ) ); + fail_if( ( i == 3 && ((temp + 1) != 512UL * 512UL * 512UL * 512UL * PAGESIZE) ) ); } // IOTINVAL not allowed to set PSCV @@ -1720,11 +1720,11 @@ main(void) { } write_memory((char *)&DC, DC_addr, 64); iodir(INVAL_DDT, 1, 0x012349, 0); - - while ( i < 64 ) { + + while ( i < 64 ) { req.tr.iova = gva | 1ULL << i; iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.R != 0 ) ); fail_if( ( rsp.trsp.W != 0 ) ); i++; @@ -1895,13 +1895,13 @@ main(void) { // AV=0, PSCV=0 // Fill TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Corrupt PTE pte.PPN = 512UL * 512UL * 512UL ; write_memory((char *)&pte, pte_addr, 8); // Hit in TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Inv TLB iotinval(VMA, 0, 0, 0, 1, 10, 0); // Check fault observed - invalidate success @@ -1913,13 +1913,13 @@ main(void) { // AV=0, PSCV=1 iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Corrupt PTE pte.PPN = 512UL * 512UL * 512UL ; write_memory((char *)&pte, pte_addr, 8); // Hit in TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Inv TLB - globals dont get flushed iotinval(VMA, 0, 0, 1, 1, 10, 0); // Check fault observed - invalidate success @@ -1941,13 +1941,13 @@ main(void) { // AV=1, PSCV=0 // Fill TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Corrupt PTE pte.PPN = 512UL * 512UL * 512UL ; write_memory((char *)&pte, pte_addr, 8); // Hit in TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Inv TLB iotinval(VMA, 0, 1, 0, 1, 10, req.tr.iova); // Check fault observed - invalidate success @@ -1961,7 +1961,7 @@ main(void) { write_memory((char *)&pte, pte_addr, 8); // Fill TLB iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Fault from TLB pte.W = 1; write_memory((char *)&pte, pte_addr, 8); @@ -1971,11 +1971,11 @@ main(void) { // Inv TLB iotinval(VMA, 0, 0, 0, 1, 10, 0); iommu_translate_iova(&req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); END_TEST(); START_TEST("HPM filtering"); - + for ( i = 0; i < 32; i++ ) { write_register(IOHPMEVT1_OFFSET + (i * 8), 8, 0); write_register(IOHPMCTR1_OFFSET + (i * 8), 8, 0); @@ -2127,18 +2127,18 @@ main(void) { write_register(IOHPMCTR4_OFFSET, 8, 0xFFFFFFFFFFFFFFFF); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0 ) ); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0 ) ); // Inv TLB iotinval(VMA, 0, 0, 0, 1, 10, 0); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 1 ) ); // Inv TLB @@ -2149,11 +2149,11 @@ main(void) { write_register(IOHPMCTR4_OFFSET, 8, 0xFFFFFFFFFFFFFFFF); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0 ) ); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); // Inv TLB iotinval(VMA, 0, 0, 0, 1, 10, 0); @@ -2163,11 +2163,11 @@ main(void) { write_register(IOHPMCTR4_OFFSET, 8, 0xFFFFFFFFFFFFFFFF); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0xffffffffff )); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0xffffffffff )); @@ -2177,7 +2177,7 @@ main(void) { iotinval(VMA, 0, 0, 0, 1, 10, 0); send_translation_request(0x012349, 0, 10, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, READ, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR4_OFFSET, 8) != 0xffffffffff )); for ( i = 0; i < 32; i++ ) { @@ -2190,7 +2190,7 @@ main(void) { START_TEST("Process Directory Table walk"); // collapse fault queue write_register(FQH_OFFSET, 4, read_register(FQT_OFFSET, 4)); - DC_addr = add_device(0x112233, 0x1234, 0, 0, 0, 0, 0, + DC_addr = add_device(0x112233, 0x1234, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, IOHGATP_Sv48x4, IOSATP_Bare, PD20, MSIPTP_Flat, 1, 0xFFFFFFFFFF, 0x1000000000); @@ -2409,7 +2409,7 @@ main(void) { cqcsr.raw = read_register(CQCSR_OFFSET, 4); fail_if( ( cqcsr.cmd_ill != 1 ) ); - // fix the illegal commend + // fix the illegal commend cqb.raw = read_register(CQB_OFFSET, 8); cqh.raw = read_register(CQH_OFFSET, 4); read_memory(((cqb.ppn * PAGESIZE) | (cqh.index * 16)), 16, (char *)&cmd); @@ -2618,7 +2618,7 @@ main(void) { send_translation_request(0x112233, 1, 0xBABEC, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, WRITE, &req, &rsp); - fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, + fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, ((PC.fsc.iosatp.PPN * PAGESIZE) | 3)) < 0 ) ); gpte.V = 1; @@ -2627,7 +2627,7 @@ main(void) { send_translation_request(0x112233, 1, 0xBABEC, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, WRITE, &req, &rsp); - fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, + fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, ((PC.fsc.iosatp.PPN * PAGESIZE) | 3)) < 0 ) ); gpte.N = 0; gpte.PBMT = 1; @@ -2635,7 +2635,7 @@ main(void) { send_translation_request(0x112233, 1, 0xBABEC, 0, 0, 0, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, WRITE, &req, &rsp); - fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, + fail_if( ( check_rsp_and_faults(&req, &rsp, UNSUPPORTED_REQUEST, 23, ((PC.fsc.iosatp.PPN * PAGESIZE) | 3)) < 0 ) ); gpte.N = 0; gpte.PBMT = 0; @@ -2761,7 +2761,7 @@ main(void) { send_translation_request(0x112233, 1, 0x1000, 0, 0, 1, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, WRITE, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR1_OFFSET, 8) != 0 ) ); fail_if( ( read_register(IOHPMCTR2_OFFSET, 8) != 0 ) ); fail_if( ( read_register(IOHPMCTR3_OFFSET, 8) != 0 ) ); @@ -2775,7 +2775,7 @@ main(void) { send_translation_request(0x112233, 1, 0x1000, 0, 0, 1, 0, ADDR_TYPE_UNTRANSLATED, gva, 1, WRITE, &req, &rsp); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( read_register(IOHPMCTR1_OFFSET, 8) != 0 ) ); fail_if( ( read_register(IOHPMCTR2_OFFSET, 8) != 0 ) ); fail_if( ( read_register(IOHPMCTR3_OFFSET, 8) != 0 ) ); @@ -2917,7 +2917,7 @@ main(void) { 0, 0, ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST, 0x900000, 1, READ, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, SUCCESS, 0, 0) < 0 ) ); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 0 ) ); @@ -2930,7 +2930,7 @@ main(void) { 0, 0, ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST, 0x900000, 1, READ, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, SUCCESS, 0, 0) < 0 ) ); - fail_if( ( rsp.status != SUCCESS ) ); + fail_if( ( rsp.status != SUCCESS ) ); fail_if( ( rsp.trsp.U != 0 ) ); fail_if( ( rsp.trsp.R != 1 ) ); fail_if( ( rsp.trsp.W != 0 ) ); @@ -2960,7 +2960,7 @@ main(void) { ats_command(PRGR, 1, 0, 0xbabec, 0x43, 0x1234, 0xdeadbeeffeedbeef); fail_if( ( exp_msg_received == 0 ) ); END_TEST(); - + START_TEST("ATS page request"); // Invalid device_id pr.MSGCODE = PAGE_REQ_MSG_CODE; @@ -3047,7 +3047,7 @@ main(void) { message_received = 0; handle_page_request(&pr); fail_if( ( message_received == 1 ) ); - + // Create a overflow case pqb.raw = read_register(PQB_OFFSET, 8); write_register(PQH_OFFSET, 4, @@ -3193,7 +3193,7 @@ main(void) { fail_if( ( iofence_data != 0x1234567812345678 ) ); fail_if( ( pr_go_requested == 1 ) ); fail_if( ( pw_go_requested == 1 ) ); - + // Send a invalid completion with itag of first inval inv_cc.MSGCODE = INVAL_COMPL_MSG_CODE; inv_cc.TAG = 0; @@ -3528,9 +3528,9 @@ main(void) { send_translation_request(0x121679, 0, 0x0000, 0, 0, 0, 0, ADDR_TYPE_PCIE_ATS_TRANSLATION_REQUEST, gpa, 4, READ, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, SUCCESS, 0, 0) < 0 ) ); - fail_if( ( rsp.trsp.U != 1 ) ); - fail_if( ( rsp.trsp.R != 1 ) ); - fail_if( ( rsp.trsp.W != 1 ) ); + fail_if( ( rsp.trsp.U != 1 ) ); + fail_if( ( rsp.trsp.R != 1 ) ); + fail_if( ( rsp.trsp.W != 1 ) ); // Success send_translation_request(0x121679, 0, 0x0000, 0, @@ -3577,17 +3577,17 @@ main(void) { cmd.iotinval.rsvd2 == 0 && cmd.iotinval.rsvd3 == 0 && cmd.iotinval.rsvd4 == 0 ) { - if ( temp == 0 ) + if ( temp == 0 ) cmd.iotinval.func3 = 0x7; - if ( temp == 1 ) + if ( temp == 1 ) cmd.iotinval.rsvd = 1; - if ( temp == 2 ) + if ( temp == 2 ) cmd.iotinval.rsvd1 = 1; - if ( temp == 3 ) + if ( temp == 3 ) cmd.iotinval.rsvd2 = 1; - if ( temp == 4 ) + if ( temp == 4 ) cmd.iotinval.rsvd3 = 1; - if ( temp == 5 ) + if ( temp == 5 ) cmd.iotinval.rsvd4 = 1; if ( temp > 5 ) { cmd.iotinval.rsvd4 = 1; @@ -3602,13 +3602,13 @@ main(void) { if ( cmd.any.opcode == IOFENCE ) { if ( cmd.iofence.reserved == 0 && cmd.iofence.reserved1 == 0 ) { - if ( temp == 0 ) + if ( temp == 0 ) cmd.iofence.func3 = 0x7; - if ( temp == 1 ) + if ( temp == 1 ) cmd.iofence.reserved = 1; - if ( temp == 2 ) + if ( temp == 2 ) cmd.iofence.reserved1 = 1; - if ( temp > 2 ) { + if ( temp > 2 ) { cmd.iofence.reserved = 1; cmd.iofence.reserved1 = 1; } @@ -3619,13 +3619,13 @@ main(void) { if ( cmd.iodir.rsvd == 0 && cmd.iodir.rsvd1 == 0 && cmd.iodir.rsvd2 == 0 ) { - if ( temp == 0 ) + if ( temp == 0 ) cmd.iodir.func3 = 0x7; - if ( temp == 1 ) + if ( temp == 1 ) cmd.iodir.rsvd = 1; - if ( temp == 2 ) + if ( temp == 2 ) cmd.iodir.rsvd1 = 1; - if ( temp == 3 ) + if ( temp == 3 ) cmd.iodir.rsvd2 = 1; if ( temp > 3 ) { cmd.iodir.rsvd2 = 1; @@ -3635,8 +3635,8 @@ main(void) { temp++; } } - if ( cmd.any.opcode == ATS && cmd.ats.rsvd == 0 && - cmd.ats.rsvd1 == 0) + if ( cmd.any.opcode == ATS && cmd.ats.rsvd == 0 && + cmd.ats.rsvd1 == 0) cmd.ats.func3 = 0x7; generic_any(cmd); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3713,7 +3713,7 @@ main(void) { cqcsr.raw = read_register(CQCSR_OFFSET, 4); fail_if( ( cqcsr.cmd_ill != 0 ) ); - // idle + // idle process_commands(); END_TEST(); @@ -3726,7 +3726,7 @@ main(void) { g_gxl_writeable = 1; g_reg_file.fctl.gxl = 1; - DC_addr = add_device(0x000000, 1, 0, 0, 0, 0, 0, + DC_addr = add_device(0x000000, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, IOHGATP_Sv32x4, IOSATP_Bare, PD20, MSIPTP_Flat, 1, 0xFFFFFFFFFF, 0x1000000000); @@ -3802,10 +3802,10 @@ main(void) { 1, WRITE, &req, &rsp); fail_if( ( check_rsp_and_faults(&req, &rsp, SUCCESS, 0, 0) < 0 ) ); END_TEST(); - + START_TEST("Misc. Register Access tests"); - - // Write read-only registers + + // Write read-only registers for ( offset = 0; offset < 4096; ) { i = offset; switch (offset) { @@ -3829,7 +3829,7 @@ main(void) { temp = fctl.raw; fail_if( ( fctl.be != 0 ) ); fail_if( ( fctl.wsi != 0 ) ); - // IOMMU is on - this register should not be writeable + // IOMMU is on - this register should not be writeable fctl.be = 1; fctl.wsi = 1; write_register(i, 4, fctl.raw); @@ -3854,13 +3854,13 @@ main(void) { write_register(CQT_OFFSET, 4, 0); write_register(i, 4, fctl.raw); fctl.raw = read_register(i, 4); - fail_if( ( fctl.be != 1 ) ); - fail_if( ( fctl.wsi != 0 ) ); + fail_if( ( fctl.be != 1 ) ); + fail_if( ( fctl.wsi != 0 ) ); g_reg_file.capabilities.igs = IGS_BOTH; fctl.wsi = 1; write_register(i, 4, fctl.raw); fctl.raw = read_register(i, 4); - fail_if( ( fctl.wsi != 1 ) ); + fail_if( ( fctl.wsi != 1 ) ); fctl.be = 0; fctl.wsi = 0; @@ -4006,7 +4006,7 @@ main(void) { } offset += 8; break; - + case TR_REQ_IOVA_OFFSET: case TR_REQ_CTRL_OFFSET: temp = read_register(i, 8); diff --git a/iommu_ref_model/test/test_app.h b/iommu_ref_model/test/test_app.h index 252fbbb5..f08db592 100644 --- a/iommu_ref_model/test/test_app.h +++ b/iommu_ref_model/test/test_app.h @@ -20,16 +20,16 @@ extern void send_translation_request(uint32_t did, uint8_t pid_valid, uint32_t p hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp); extern int8_t check_rsp_and_faults(hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp, status_t status, uint16_t cause, uint64_t exp_iotval2); -extern int8_t check_msg_faults(uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, +extern int8_t check_msg_faults(uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, uint8_t exp_PRIV, uint32_t exp_DID, uint64_t exp_iotval); extern int8_t check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t EXEC, uint16_t reserved0, uint8_t reserved1, uint64_t PAYLOAD); extern uint64_t get_free_gppn(uint64_t num_gppn, iohgatp_t iohgatp); -extern uint64_t add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, uint8_t t2gpa, - uint8_t dtf, uint8_t prpr, +extern uint64_t add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, uint8_t t2gpa, + uint8_t dtf, uint8_t prpr, uint8_t gade, uint8_t sade, uint8_t dpe, uint8_t sbe, uint8_t sxl, uint8_t iohgatp_mode, uint8_t iosatp_mode, uint8_t pdt_mode, - uint8_t msiptp_mode, uint8_t msiptp_pages, uint64_t msi_addr_mask, + uint8_t msiptp_mode, uint8_t msiptp_pages, uint64_t msi_addr_mask, uint64_t msi_addr_pattern); // Global variables diff --git a/iommu_ref_model/test/test_utils.c b/iommu_ref_model/test/test_utils.c index c8c027e2..79f2de98 100644 --- a/iommu_ref_model/test/test_utils.c +++ b/iommu_ref_model/test/test_utils.c @@ -30,9 +30,9 @@ get_free_gppn(uint64_t num_gppn, iohgatp_t iohgatp) { free_gppn = free_gppn & ~(num_gppn -1); } next_free_gpage[iohgatp.GSCID] = free_gppn + num_gppn; - return free_gppn; + return free_gppn; } -int8_t +int8_t enable_cq( uint32_t nppn) { cqb_t cqb; @@ -71,7 +71,7 @@ enable_cq( return 0; } -int8_t +int8_t enable_fq( uint32_t nppn) { fqb_t fqb; @@ -107,7 +107,7 @@ enable_fq( return 0; } -int8_t +int8_t enable_disable_pq( uint32_t nppn, uint8_t enable_disable) { pqb_t pqb; @@ -166,7 +166,7 @@ enable_iommu( ddtp.raw = 0; ddtp.ppn = get_free_ppn(1); // Clear the page - for ( i = 0; i < 512; i++ ) + for ( i = 0; i < 512; i++ ) write_memory((char *)&zero, (ddtp.ppn * PAGESIZE) | (i * 8), 8); ddtp.iommu_mode = iommu_mode; @@ -174,7 +174,7 @@ enable_iommu( do { ddtp.raw = read_register(DDTP_OFFSET, 8); } while ( ddtp.busy == 1 ); - if ( iommu_mode != Off ) { + if ( iommu_mode != Off ) { g_reg_file.ddtp.busy = 1; ddtp.iommu_mode = Off; write_register(DDTP_OFFSET, 8, ddtp.raw); @@ -184,7 +184,7 @@ enable_iommu( } return 0; } -void +void send_translation_request(uint32_t did, uint8_t pid_valid, uint32_t pid, uint8_t no_write, uint8_t exec_req, uint8_t priv_req, uint8_t is_cxl_dev, addr_type_t at, uint64_t iova, uint32_t length, uint8_t read_writeAMO, @@ -205,7 +205,7 @@ send_translation_request(uint32_t did, uint8_t pid_valid, uint32_t pid, uint8_t return; } int8_t -check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t EXEC, +check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t EXEC, uint16_t reserved0, uint8_t reserved1, uint64_t PLOAD) { page_rec_t page_rec; @@ -215,20 +215,20 @@ check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t E pqh.raw = read_register(PQH_OFFSET, 4); pqb.raw = read_register(PQB_OFFSET, 8); read_memory(((pqb.ppn * PAGESIZE) | (pqh.index * 16)), 16, (char *)&page_rec); - if ( page_rec.DID != DID ) return -1; - if ( page_rec.PID != PID ) return -1; - if ( page_rec.PV != PV ) return -1; - if ( page_rec.PRIV != PRIV ) return -1; - if ( page_rec.EXEC != EXEC ) return -1; - if ( page_rec.reserved0 != reserved0 ) return -1; - if ( page_rec.reserved1 != reserved1 ) return -1; - if ( page_rec.PAYLOAD != PLOAD ) return -1; + if ( page_rec.DID != DID ) return -1; + if ( page_rec.PID != PID ) return -1; + if ( page_rec.PV != PV ) return -1; + if ( page_rec.PRIV != PRIV ) return -1; + if ( page_rec.EXEC != EXEC ) return -1; + if ( page_rec.reserved0 != reserved0 ) return -1; + if ( page_rec.reserved1 != reserved1 ) return -1; + if ( page_rec.PAYLOAD != PLOAD ) return -1; write_register(PQH_OFFSET, 4, pqh.raw + 1); return 0; } int8_t check_msg_faults( - uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, uint8_t exp_PRIV, + uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, uint8_t exp_PRIV, uint32_t exp_DID, uint64_t exp_iotval) { fault_rec_t fault_rec; fqb_t fqb; @@ -272,7 +272,7 @@ check_rsp_and_faults( hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp, status_t status, - uint16_t cause, + uint16_t cause, uint64_t exp_iotval2) { fault_rec_t fault_rec; @@ -337,11 +337,11 @@ check_rsp_and_faults( return 0; } uint64_t -add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, uint8_t t2gpa, - uint8_t dtf, uint8_t prpr, +add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, uint8_t t2gpa, + uint8_t dtf, uint8_t prpr, uint8_t gade, uint8_t sade, uint8_t dpe, uint8_t sbe, uint8_t sxl, uint8_t iohgatp_mode, uint8_t iosatp_mode, uint8_t pdt_mode, - uint8_t msiptp_mode, uint8_t msiptp_pages, uint64_t msi_addr_mask, + uint8_t msiptp_mode, uint8_t msiptp_pages, uint64_t msi_addr_mask, uint64_t msi_addr_pattern) { device_context_t DC; char zero[16384]; @@ -422,7 +422,7 @@ add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, u } return add_dev_context(&DC, device_id); } -void +void iotinval( uint8_t f3, uint8_t GV, uint8_t AV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, uint64_t address) { command_t cmd; @@ -452,7 +452,7 @@ iotinval( process_commands(); return; } -void +void ats_command( uint8_t f3, uint8_t DSV, uint8_t PV, uint32_t PID, uint8_t DSEG, uint16_t RID, uint64_t payload) { command_t cmd; @@ -483,7 +483,7 @@ ats_command( process_commands(); return; } -void +void generic_any( command_t cmd) { cqb_t cqb; @@ -501,8 +501,8 @@ generic_any( process_commands(); return; } - -void + +void iodir( uint8_t f3, uint8_t DV, uint32_t DID, uint32_t PID) { command_t cmd; @@ -570,5 +570,5 @@ get_free_ppn( free_ppn = next_free_page; next_free_page += num_ppn; memset(&memory[free_ppn * PAGESIZE], 0, num_ppn * PAGESIZE); - return free_ppn; + return free_ppn; } diff --git a/readme.adoc b/readme.adoc deleted file mode 100644 index 2d62f722..00000000 --- a/readme.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= RISC-V IOMMU specification - -The specification is in Frozen state and pending ratification. - -= License - -This work is licensed under a Creative Commons Attribution 4.0 International License (CC-BY-4.0). -See the link:LICENSE[LICENSE] file for details. - -= Contributors - -Contributors to this specification are contained in the link:contributors.adoc[contributors] file. - -For instructions on how to contribute please see the link:CONTRIBUTING.md[CONTRIBUTING] file. - -= Dependencies - -To build the document, you'll need the following tools installed on your system: - -``` - Make - asciiDoctor-pdf, asciidoctor-bibtex, asciidoctor-diagram and asciidoctor-mathematical - Docker -``` - -= Cloning and Building the Document - -This project uses submodules to include the RISC-V documentation toolchain. - -``` - git clone --recurse-submodule https://github.com/riscv-non-isa/riscv-iommu.git - cd ./riscv-zacas.git - make VERSION=v1.0.0 REVMARK=Draft -``` - -`VERSION`: Represents the version of the specification being built. By default, this is set to 'v0.0.0'. You can change this to a different value, like 'v1.0.0', 'v1.1.0', etc., based on the current version of your specification. - -`REVMARK`: This represents a revision marker for the project. Its default value is 'Draft'. You may want to change this to something like 'Release', 'Stable' or 'Ratified'. \ No newline at end of file diff --git a/bibliography.adoc b/src/bibliography.adoc similarity index 100% rename from bibliography.adoc rename to src/bibliography.adoc diff --git a/contributors.adoc b/src/contributors.adoc similarity index 100% rename from contributors.adoc rename to src/contributors.adoc diff --git a/images/ddt-base.svg b/src/images/ddt-base.svg similarity index 99% rename from images/ddt-base.svg rename to src/images/ddt-base.svg index b975e192..10e632e3 100644 --- a/images/ddt-base.svg +++ b/src/images/ddt-base.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/ddt-ext.svg b/src/images/ddt-ext.svg similarity index 99% rename from images/ddt-ext.svg rename to src/images/ddt-ext.svg index 6d50eae2..671ca012 100644 --- a/images/ddt-ext.svg +++ b/src/images/ddt-ext.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/guest-OS.svg b/src/images/guest-OS.svg similarity index 99% rename from images/guest-OS.svg rename to src/images/guest-OS.svg index 2a07ca82..7dff72de 100644 --- a/images/guest-OS.svg +++ b/src/images/guest-OS.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/hypervisor.svg b/src/images/hypervisor.svg similarity index 99% rename from images/hypervisor.svg rename to src/images/hypervisor.svg index 06228840..eb8a5485 100644 --- a/images/hypervisor.svg +++ b/src/images/hypervisor.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/interfaces.svg b/src/images/interfaces.svg similarity index 99% rename from images/interfaces.svg rename to src/images/interfaces.svg index b9e312a4..2303a02d 100644 --- a/images/interfaces.svg +++ b/src/images/interfaces.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/images/msi-imsic.svg b/src/images/msi-imsic.svg similarity index 99% rename from images/msi-imsic.svg rename to src/images/msi-imsic.svg index b5370366..d48df744 100644 --- a/images/msi-imsic.svg +++ b/src/images/msi-imsic.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/non-virt-OS.svg b/src/images/non-virt-OS.svg similarity index 99% rename from images/non-virt-OS.svg rename to src/images/non-virt-OS.svg index ac2e6dd0..338547a1 100644 --- a/images/non-virt-OS.svg +++ b/src/images/non-virt-OS.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/pdt.svg b/src/images/pdt.svg similarity index 99% rename from images/pdt.svg rename to src/images/pdt.svg index 679a181f..bfeaadb2 100644 --- a/images/pdt.svg +++ b/src/images/pdt.svg @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/images/placement.svg b/src/images/placement.svg similarity index 99% rename from images/placement.svg rename to src/images/placement.svg index 7f638a60..d680907b 100644 --- a/images/placement.svg +++ b/src/images/placement.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/index.adoc b/src/index.adoc similarity index 100% rename from index.adoc rename to src/index.adoc diff --git a/iommu.bib b/src/iommu.bib similarity index 100% rename from iommu.bib rename to src/iommu.bib diff --git a/iommu_data_structures.adoc b/src/iommu_data_structures.adoc similarity index 99% rename from iommu_data_structures.adoc rename to src/iommu_data_structures.adoc index 68d926eb..b54bb8a1 100644 --- a/iommu_data_structures.adoc +++ b/src/iommu_data_structures.adoc @@ -1433,7 +1433,7 @@ group of entries. |First-stage page table (when second-stage is not Bare) |`GSCID`, `PSCID`, and IOVA | <> -|First-stage page table +|First-stage page table (when second-stage is Bare) |`PSCID`, and IOVA | <> |Second-stage page table|`GSCID`, `GPA` | <> diff --git a/iommu_debug.adoc b/src/iommu_debug.adoc similarity index 100% rename from iommu_debug.adoc rename to src/iommu_debug.adoc diff --git a/iommu_hw_guidelines.adoc b/src/iommu_hw_guidelines.adoc similarity index 99% rename from iommu_hw_guidelines.adoc rename to src/iommu_hw_guidelines.adoc index 3d359905..17e2d3c5 100644 --- a/iommu_hw_guidelines.adoc +++ b/src/iommu_hw_guidelines.adoc @@ -93,4 +93,3 @@ If the IO bridge is not capable of signaling such deferred errors uniquely from other errors that prevent the IOMMU from accessing in-memory data structures then the IOMMU may report such errors as access faults instead of using the differentiated data corruption cause codes. - diff --git a/iommu_in_memory_queues.adoc b/src/iommu_in_memory_queues.adoc similarity index 100% rename from iommu_in_memory_queues.adoc rename to src/iommu_in_memory_queues.adoc diff --git a/iommu_intro.adoc b/src/iommu_intro.adoc similarity index 99% rename from iommu_intro.adoc rename to src/iommu_intro.adoc index 3548b61f..f7d341a0 100644 --- a/iommu_intro.adoc +++ b/src/iommu_intro.adoc @@ -352,7 +352,7 @@ performs memory accesses using those addresses, an IOMMU is responsible for translating those guest physical addresses into supervisor physical addresses, referencing address-translation data structures supplied by the hypervisor. -<> illustrates the concept. +<> illustrates the concept. The device D1 is directly assigned to VM-1 and device D2 is directly assigned to VM-2. The VMM configures a second-stage page table to be used for each device and restricts the memory that can be accessed by D1 to VM-1 associated memory @@ -438,7 +438,7 @@ a GPA using the first-stage page tables managed by the guest OS and the GPA translated to a SPA using the second-stage page tables managed by the hypervisor. -<> illustrates the concept. +<> illustrates the concept. The IOMMU is configured to perform address translation using a first-stage and second-stage page table for device D1. The second-stage is typically used by @@ -687,4 +687,3 @@ features: Features supported by the IOMMU may be discovered using the `capabilities` register <>. - diff --git a/iommu_registers.adoc b/src/iommu_registers.adoc similarity index 99% rename from iommu_registers.adoc rename to src/iommu_registers.adoc index a990daf5..56305e16 100644 --- a/iommu_registers.adoc +++ b/src/iommu_registers.adoc @@ -1207,13 +1207,13 @@ There is no associated `iohpmevt0`. |63 |`OF` |RW | Overflow |=== -The `OF` bit is set when the `iohpmcycles` counter overflows, and remains set +The `OF` bit is set when the `iohpmcycles` counter overflows, and remains set until cleared by software. Since `iohpmcycles` value is an unsigned value, overflow is defined as unsigned overflow. Note that there is no loss of information after an overflow since the counter wraps around and keeps counting while the sticky `OF` bit remains set. -If the `iohpmcycles` counter overflows when the `OF` bit is zero, then a HPM +If the `iohpmcycles` counter overflows when the `OF` bit is zero, then a HPM Counter Overflow interrupt is generated by setting `ipsr.pmip` bit to 1. If the `OF` bit is already one, then no interrupt request is generated. Consequently the `OF` bit also functions as a count overflow interrupt disable for the diff --git a/iommu_sw_guidelines.adoc b/src/iommu_sw_guidelines.adoc similarity index 99% rename from iommu_sw_guidelines.adoc rename to src/iommu_sw_guidelines.adoc index 8fe90c49..8585bb1e 100644 --- a/iommu_sw_guidelines.adoc +++ b/src/iommu_sw_guidelines.adoc @@ -418,14 +418,10 @@ To disable ATS and/or PRI: . Disable ATS and/or PRI at the device . Set `EN_ATS` and/or `EN_PRI` to 0 in the device-context. If `EN_ATS` is set to 0 then set `EN_PRI` and `T2GPA` to 0. If `EN_PRI` is set to 0 then set `PRPR` - to 0. + to 0. . Queue commands to the IOMMU to invalidate all cached first/second-stage page table entries, DDT entries, MSI PT entries (if required), and PDT entries (if required). . Queue commands to the IOMMU to invalidate DevATC by generating Invalidation Request messages. . Enable DMA operations in the device. - - - - diff --git a/header.adoc b/src/riscv-iommu.adoc similarity index 66% rename from header.adoc rename to src/riscv-iommu.adoc index 8c735d2c..c0855744 100644 --- a/header.adoc +++ b/src/riscv-iommu.adoc @@ -1,21 +1,20 @@ -[[header]] += RISC-V IOMMU Architecture Specification +include::../docs-resources/global-config.adoc[] +:docgroup: IOMMU Task Group :description: RISC-V IOMMU Architecture Specification -:company: RISC-V.org :revdate: 06/2023 :revnumber: 1.0 :revremark: This document is Ratified. See http://riscv.org/spec-state for details. -:url-riscv: http://riscv.org -:doctype: book :preface-title: Preamble :colophon: :appendix-caption: Appendix -:imagesdir: images -:title-logo-image: image:risc-v_logo.svg[pdfwidth=3.25in,align=center] +:imagesdir: ../docs-resources/images +:title-logo-image: image:risc-v_logo.png["RISC-V International Logo",pdfwidth=3.25in,align=center] // Settings: :experimental: :reproducible: :imagesoutdir: images -:bibtex-file: iommu.bib +:bibtex-file: src/iommu.bib :bibtex-order: appearance :bibtex-style: ieee :icons: font @@ -34,10 +33,19 @@ endif::[] :footnote: :xrefstyle: short -= RISC-V IOMMU Architecture Specification -IOMMU Task Group +// Preamble - Begin +[preface] +== List of figures +list-of::image[hide_empty_section=true, enhanced_rendering=true] + +[preface] +== List of tables +list-of::table[hide_empty_section=true, enhanced_rendering=true] + +[preface] +== List of listings +list-of::listing[hide_empty_section=true, enhanced_rendering=true] -// Preamble [WARNING] .This document is link:http://riscv.org/spec-state[Ratified]. ==== @@ -47,8 +55,8 @@ follow-on new extension. Ratified extensions are never revised. [preface] == Copyright and license information -This specification is licensed under the Creative Commons -Attribution 4.0 International License (CC-BY 4.0). The full +This specification is licensed under the Creative Commons +Attribution 4.0 International License (CC-BY 4.0). The full license text is available at https://creativecommons.org/licenses/by/4.0/. @@ -56,6 +64,9 @@ Copyright 2023 by RISC-V International. [preface] include::contributors.adoc[] +// Preamble - End + +:imagesdir: images include::iommu_intro.adoc[] include::iommu_data_structures.adoc[] include::iommu_in_memory_queues.adoc[] From 2c32f1e3ddc2933a9432fc6b512e56f8bdd701b5 Mon Sep 17 00:00:00 2001 From: Kevin Broch Date: Mon, 3 Jun 2024 13:26:34 -0700 Subject: [PATCH 2/5] Change theme to use same as the ISA manual Signed-off-by: Kevin Broch --- Makefile | 4 +++- docs-resources | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a6188e81..386e6baa 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,8 @@ BUILD_DIR := build DOCS_PDF := $(DOCS:%.adoc=%.pdf) DOCS_HTML := $(DOCS:%.adoc=%.html) +PDF_THEME := docs-resources/themes/riscv-spec.yml + XTRA_ADOC_OPTS := ASCIIDOCTOR_PDF := asciidoctor-pdf ASCIIDOCTOR_HTML := asciidoctor @@ -42,7 +44,7 @@ OPTIONS := --trace \ -a revremark=${REVMARK} \ -a revdate=${DATE} \ -a pdf-fontsdir=docs-resources/fonts \ - -a pdf-theme=docs-resources/themes/riscv-pdf.yml \ + -a pdf-theme=${PDF_THEME} \ $(XTRA_ADOC_OPTS) \ -D build \ --failure-level=ERROR diff --git a/docs-resources b/docs-resources index c0ff7005..48837076 160000 --- a/docs-resources +++ b/docs-resources @@ -1 +1 @@ -Subproject commit c0ff7005346bc05dee68fa20354f454aea193ee2 +Subproject commit 4883707652d3219d7fbd9939bf7458f1587b0c0b From b66d0c16f801e3b31590239542c46e3dc37b3dfc Mon Sep 17 00:00:00 2001 From: Kevin Broch Date: Mon, 3 Jun 2024 15:43:50 -0700 Subject: [PATCH 3/5] update docs-resources to pull in the new table:fontsize: 11.5 Signed-off-by: Kevin Broch --- docs-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-resources b/docs-resources index 48837076..caaa4e66 160000 --- a/docs-resources +++ b/docs-resources @@ -1 +1 @@ -Subproject commit 4883707652d3219d7fbd9939bf7458f1587b0c0b +Subproject commit caaa4e66593331142e397d9dbb91089034830aa2 From d16219667620c82842ad002db142a9c1ebd39e24 Mon Sep 17 00:00:00 2001 From: Kevin Broch Date: Wed, 5 Jun 2024 10:38:02 -0700 Subject: [PATCH 4/5] update doc-resources to latest Signed-off-by: Kevin Broch --- docs-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-resources b/docs-resources index caaa4e66..dab0dd1d 160000 --- a/docs-resources +++ b/docs-resources @@ -1 +1 @@ -Subproject commit caaa4e66593331142e397d9dbb91089034830aa2 +Subproject commit dab0dd1dcf6f30e2ce269e6f62ca66ad68775fd3 From 5d7181e423e102f3ef0009ea85fef6cbf6e8f256 Mon Sep 17 00:00:00 2001 From: Kevin Broch Date: Thu, 6 Jun 2024 16:46:14 -0700 Subject: [PATCH 5/5] update docs-resources to latest to pull in unified pdf theme Signed-off-by: Kevin Broch --- Makefile | 4 +--- docs-resources | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 386e6baa..a6188e81 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,6 @@ BUILD_DIR := build DOCS_PDF := $(DOCS:%.adoc=%.pdf) DOCS_HTML := $(DOCS:%.adoc=%.html) -PDF_THEME := docs-resources/themes/riscv-spec.yml - XTRA_ADOC_OPTS := ASCIIDOCTOR_PDF := asciidoctor-pdf ASCIIDOCTOR_HTML := asciidoctor @@ -44,7 +42,7 @@ OPTIONS := --trace \ -a revremark=${REVMARK} \ -a revdate=${DATE} \ -a pdf-fontsdir=docs-resources/fonts \ - -a pdf-theme=${PDF_THEME} \ + -a pdf-theme=docs-resources/themes/riscv-pdf.yml \ $(XTRA_ADOC_OPTS) \ -D build \ --failure-level=ERROR diff --git a/docs-resources b/docs-resources index dab0dd1d..3dd7194c 160000 --- a/docs-resources +++ b/docs-resources @@ -1 +1 @@ -Subproject commit dab0dd1dcf6f30e2ce269e6f62ca66ad68775fd3 +Subproject commit 3dd7194c6694001d05e5c083ab606932b8eb72a7