diff --git a/.github/workflows/build_test.yaml b/.github/workflows/build_test.yaml new file mode 100644 index 0000000000000..04dae68b12cc8 --- /dev/null +++ b/.github/workflows/build_test.yaml @@ -0,0 +1,198 @@ +--- +#------------------------------------------------------------------------------ +# QEMU OpenTitan CI +# +# Copyright (c) 2023-2025 Rivos, Inc. +# Copyright (c) 2025 lowRISC contributors. +# SPDX-License-Identifier: Apache License 2.0 +#------------------------------------------------------------------------------ + +name: Build & Test QEMU OT +on: + - pull_request + - workflow_dispatch +jobs: + build-clang: + runs-on: ubuntu-24.04 + steps: + - name: Install deps + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | + sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && + sudo add-apt-repository "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" && + sudo apt-get update && + sudo apt-get install -y git make pkg-config clang-21 cmake ninja-build python3 rust-all \ + libpixman-1-dev libglib2.0-dev + - name: Check out QEMU + uses: actions/checkout@v4 + - name: Configure + run: | + rm -rf build-clang + git clean -dffx subprojects + mkdir build-clang + (cd build-clang && + ../configure --cc=clang-21 --disable-werror --disable-install-blobs \ + --target-list=riscv32-softmmu,riscv64-softmmu) + - name: Build + run: | + ninja -C build-clang && + ninja -C build-clang qemu-img && + strip build-clang/qemu-system-riscv32 + - name: Create minimal test binaries + run: | + scripts/opentitan/swexit.py -t ibexdemo -b 0x0 -o build-clang/exit_id.bin + scripts/opentitan/swexit.py -t earlgrey -b 0x80 -o build-clang/exit_eg.bin + scripts/opentitan/swexit.py -t darjeeling -b 0x80 -o build-clang/exit_dj.bin + - name: Upload QEMU binary artifacts + uses: actions/upload-artifact@v4 + with: + name: qemu-bin + path: | + build-clang/qemu-system-riscv32 + build-clang/exit_*.bin + docs/config/opentitan/*.cfg + retention-days: 1 + - name: Pack source artifacts + # GitHub takes ages to retrieve each source file, so pack them + run: | + tar czf qemu-src-artifact.tar.gz \ + subprojects/libtomcrypt/src/headers/*.h \ + build-clang/*.h \ + build-clang/qapi/*.h \ + build-clang/trace/*.h \ + build-clang/config.status \ + build-clang/compile_commands.json + - name: Upload QEMU source artifacts + uses: actions/upload-artifact@v4 + with: + name: qemu-src + path: qemu-src-artifact.tar.gz + retention-days: 1 + + format: + runs-on: ubuntu-24.04 + steps: + - name: Install tools + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | + sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && + sudo add-apt-repository "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" && + sudo apt-get update && + sudo apt-get install -y clang-format-21 + - name: Check out QEMU + uses: actions/checkout@v4 + - name: Check C code format + run: | + scripts/opentitan/ot-format.sh --ci --Werror --dry-run + + lint-python: + runs-on: ubuntu-latest + steps: + - name: Check out QEMU + uses: actions/checkout@v4 + - name: Install tools + run: | + sudo apt-get update && + sudo apt-get install -y python3-pip + # ubuntu "latest" is too old to require --break-system-packages ... + pip3 install -r scripts/opentitan/requirements.txt + - name: Lint Python code + run: | + flake8 --config scripts/opentitan/.flake8 scripts/opentitan/*.py \ + python/qemu/jtagtools python/qemu/ot + pylint --rcfile scripts/opentitan/.pylintrc -d 'duplicate-code' -d 'fixme' \ + scripts/opentitan/*.py python/qemu/jtagtools python/qemu/ot + + lint-clang: + runs-on: ubuntu-24.04 + needs: build-clang + steps: + - name: Install tools + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | + sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && + sudo add-apt-repository "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" && + sudo apt-get update && + sudo apt-get install -y clang-tidy-21 libglib2.0-dev + - name: Check out QEMU + uses: actions/checkout@v4 + - name: Download QEMU source artifacts + uses: actions/download-artifact@v4 + with: + name: qemu-src + - name: Unpack source artifacts + run: | + tar xzf qemu-src-artifact.tar.gz + - name: Clang tidy + # Expect many warnings/errors (accounted but not reported) from included QEMU files + run: | + scripts/opentitan/ot-tidy.py --build-dir build-clang --ci-files -j + + lint-commits: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Don't shallow clone, we need to see all commits. + - name: Lint commits + run: ./scripts/opentitan/lint-commits.sh "origin/${{ github.base_ref }}" + + test-clang: + runs-on: ubuntu-24.04 + needs: build-clang + steps: + - name: Install tools + run: | + sudo apt-get update && + sudo apt-get install -y libpixman-1-0 libglib2.0-dev + - name: Download QEMU binary artifacts + uses: actions/download-artifact@v4 + with: + name: qemu-bin + - name: Check machine availability + run: | + chmod +x build-clang/qemu-system-riscv32 && + build-clang/qemu-system-riscv32 -M help | grep ibexdemo && + build-clang/qemu-system-riscv32 -M help | grep ot-earlgrey && + build-clang/qemu-system-riscv32 -M help | grep ot-darjeeling + - name: Check IbexDemo VM execution + run: | + timeout -s KILL 4 build-clang/qemu-system-riscv32 -M ibexdemo -nographic \ + -device loader,addr=0x100080,file=build-clang/exit_id.bin -d in_asm,int + - name: Check EarlGrey VM execution + run: | + timeout -s KILL 4 build-clang/qemu-system-riscv32 -M ot-earlgrey,no_epmp_cfg=true -nographic \ + -object ot-rom_img,id=rom,file=build-clang/exit_eg.bin -global ot-ibex_wrapper.lc-ignore=on \ + -readconfig docs/config/opentitan/earlgrey.cfg -d in_asm,int \ + -trace ot_ibex_wrapper_exit + - name: Check Darjeeling VM execution + run: | + timeout -s KILL 4 build-clang/qemu-system-riscv32 -M ot-darjeeling,no_epmp_cfg=true -nographic \ + -object ot-rom_img,id=rom0,file=build-clang/exit_dj.bin -global ot-ibex_wrapper.lc-ignore=on \ + -readconfig docs/config/opentitan/darjeeling.cfg -d in_asm,int \ + -trace ot_ibex_wrapper_exit + + build-gcc: + runs-on: ubuntu-24.04 + steps: + - name: Install tools + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | + sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && + sudo add-apt-repository "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" && + sudo apt-get update && + sudo apt-get install -y git make pkg-config gcc cmake ninja-build python3 rust-all \ + libpixman-1-dev libglib2.0-dev + - name: Check out QEMU + uses: actions/checkout@v4 + - name: Configure + run: | + rm -rf build-gcc + git clean -dffx subprojects + mkdir build-gcc + (cd build-gcc && + ../configure --cc=gcc --enable-werror --disable-install-blobs \ + --target-list=riscv32-softmmu,riscv64-softmmu) + - name: Build + run: | + ninja -C build-gcc diff --git a/.github/workflows/ci_regression.yml b/.github/workflows/ci_regression.yml new file mode 100644 index 0000000000000..2a236b8318ddc --- /dev/null +++ b/.github/workflows/ci_regression.yml @@ -0,0 +1,51 @@ +#------------------------------------------------------------------------------ +# OpenTitan CI regression runner +# +# Copyright (c) 2025 lowRISC CIC +# SPDX-License-Identifier: Apache License 2.0 +#------------------------------------------------------------------------------ + +name: OT Tests +on: + pull_request: + workflow_dispatch: + inputs: + opentitan_repo: + description: OpenTitan repository to be checked out + required: true + default: lowRISC/opentitan + type: string + opentitan_ref: + description: Branch, tag, or commit ref from OpenTitan to test + required: true + default: earlgrey_1.0.0 + type: string + +jobs: + earlgrey_rom_with_fake_keys: + name: ROM + uses: ./.github/workflows/eg_regression.yml + secrets: inherit + with: + exec_env: sim_qemu_rom_with_fake_keys + opentitan_repo: ${{ inputs.opentitan_repo || 'lowRISC/opentitan' }} + opentitan_ref: ${{ inputs.opentitan_ref || 'earlgrey_1.0.0' }} + + earlgrey_rom_ext: + name: ROM_EXT + uses: ./.github/workflows/eg_regression.yml + secrets: inherit + with: + exec_env: sim_qemu_rom_ext + test_timeout: 150 + opentitan_repo: ${{ inputs.opentitan_repo || 'lowRISC/opentitan' }} + opentitan_ref: ${{ inputs.opentitan_ref || 'earlgrey_1.0.0' }} + + earlgrey_sival_rom_ext: + name: SiVal ROM_EXT + uses: ./.github/workflows/eg_regression.yml + secrets: inherit + with: + exec_env: sim_qemu_sival_rom_ext + opentitan_repo: ${{ inputs.opentitan_repo || 'lowRISC/opentitan' }} + opentitan_ref: ${{ inputs.opentitan_ref || 'earlgrey_1.0.0' }} diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml new file mode 100644 index 0000000000000..2091ed9319f0d --- /dev/null +++ b/.github/workflows/create_release.yml @@ -0,0 +1,51 @@ +name: Create Release +on: + workflow_dispatch: + inputs: + release_tag: + required: true + type: string + +jobs: + release: + permissions: + # Necessary permissions to create a release. + contents: write + env: + BUILD_DIR: build + BRANCH_NAME: ${{ github.event.repository.default_branch }} + RELEASE_BIN_ARCHIVE: qemu-ot-earlgrey-${{ inputs.release_tag }}-x86_64-unknown-linux-gnu.tar.gz + runs-on: ubuntu-22.04 + timeout-minutes: 10 + steps: + - name: Check out repository + uses: actions/checkout@v3 + # Update the package index, then install all dependencies listed in + # the various apt-requirements.txt files in the project. + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build libpixman-1-dev + - name: Configure + run: | + mkdir "$BUILD_DIR" + cd "$BUILD_DIR" + ../configure --target-list=riscv32-softmmu --without-default-features --enable-tcg \ + --enable-tools --enable-trace-backends=log + - name: Build + run: | + cd "$BUILD_DIR" + ninja + ninja qemu-img + - name: Create binary archive + run: | + ./scripts/opentitan/make_release.sh "$RELEASE_BIN_ARCHIVE" . "$BUILD_DIR" + - name: Create release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create \ + --target "$BRANCH_NAME" \ + ${{ inputs.release_tag }} \ + --generate-notes \ + "$RELEASE_BIN_ARCHIVE#QEMU system emulator" diff --git a/.github/workflows/eg_regression.yml b/.github/workflows/eg_regression.yml new file mode 100644 index 0000000000000..0080870ede90f --- /dev/null +++ b/.github/workflows/eg_regression.yml @@ -0,0 +1,78 @@ +#------------------------------------------------------------------------------ +# OpenTitan regression run definition +# +# Copyright (c) 2025 lowRISC CIC +# SPDX-License-Identifier: Apache License 2.0 +#------------------------------------------------------------------------------ + +name: OpenTitan Regression +on: + workflow_call: + inputs: + exec_env: + description: OpenTitan QEMU execution environment to test + required: true + default: qemu # Default tag, captures all QEMU exec envs in OpenTitan + type: string + test_timeout: + description: The maximum timeout in seconds to use per executed test + required: false + type: string + opentitan_repo: + description: OpenTitan repository to be checked out + required: true + default: lowRISC/opentitan + type: string + opentitan_ref: + description: Branch, tag, or commit ref from OpenTitan to test + required: true + default: earlgrey_1.0.0 + type: string + +jobs: + regression: + name: EG Regression + runs-on: ubuntu-22.04 + steps: + - name: Checkout OpenTitan + uses: actions/checkout@v5 + with: + repository: ${{ inputs.opentitan_repo || 'lowRISC/opentitan' }} + ref: ${{ inputs.opentitan_ref || 'earlgrey_1.0.0' }} + fetch-depth: 0 # fetch all commits to avoid bug with bitstream rule + + - name: Prepare OpenTitan environment + uses: ./.github/actions/prepare-env + + - name: Checkout QEMU + uses: actions/checkout@v5 + with: + path: qemu + + - name: Build QEMU + working-directory: qemu + run: | + ./configure \ + --target-list=riscv32-softmmu \ + --without-default-features \ + --enable-tcg \ + --disable-tools \ + --enable-trace-backends=log + + ninja -C build qemu-system-riscv32 + + - name: Run OpenTitan regressions + shell: bash + run: | + set -o pipefail + ./qemu/scripts/opentitan/run-bazel-tests.sh ./ qemu \ + ${{ inputs.exec_env }} \ + ${{ inputs.test_timeout }} \ + | tee ${{ inputs.exec_env }}_test_results.txt + + - name: Upload Bazel test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.exec_env }}-bazel-test-results + path: ${{ inputs.exec_env }}_test_results.txt diff --git a/.gitignore b/.gitignore index 61fa39967b542..f23f42e170371 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ .sdk .stgit-* .git-submodule-status -.clang-format .gdb_history cscope.* tags @@ -20,3 +19,11 @@ GTAGS *.swp *.patch *.gcov +subprojects/*-*/ +subprojects/libtomcrypt/ +subprojects/packagecache/ +!subprojects/packagefiles/**/*.patch +hw/opentitan/otbn/otbn/Cargo.lock +hw/opentitan/otbn/otbn/target/ +.clangd +.zed diff --git a/.gitlab-ci.d/opentitan/build.yml b/.gitlab-ci.d/opentitan/build.yml new file mode 100644 index 0000000000000..48c69f1f7f6b7 --- /dev/null +++ b/.gitlab-ci.d/opentitan/build.yml @@ -0,0 +1,75 @@ +#------------------------------------------------------------------------------ +# QEMU OpenTitan CI +#------------------------------------------------------------------------------ + +build-clang: + tags: + - qemu_ot + stage: build + # build QEMU for OT platforms, ensure subprojects are cleaned up first + # store generated header files and ninja command file as artifacts, which are + # required to run the clang-tidy stage + # libvhost-user.c generates sign-compare warnings with clang, so disable + # warning-as-error + # the alternative would be to build here with GCC, then rebuild everything + # with clang in clang-tidy stage, as meson generates different, incompatible + # warning list between GCC and clang... + script: + - rm -rf build + - git clean -dffx subprojects + - mkdir build + - cd build + - ../configure --cc=clang-21 --disable-werror $QEMU_BUILD_OPTS + --target-list=riscv32-softmmu,riscv64-softmmu,x86_64-linux-user + - ninja + - ninja qemu-img + - strip qemu-system-riscv32 qemu-img + - QEMU_DIR="$(cd .. && pwd -P)"; cat compile_commands.json | + sed -E 's,'"$QEMU_DIR"',@QEMU_DIR@,g' > compile_commands.json.tpl + - ../scripts/opentitan/swexit.py -t ibexdemo -b 0x0 -o exit_id.bin + - ../scripts/opentitan/swexit.py -t earlgrey -b 0x80 -o exit_eg.bin + - ../scripts/opentitan/swexit.py -t darjeeling -b 0x80 -o exit_dj.bin + artifacts: + public: false + expire_in: 1 hour + name: "qemu-ot" + paths: + - subprojects/libtomcrypt/src/headers/*.h + - build/*.h + - build/qapi/*.h + - build/trace/*.h + - build/config.status + - build/compile_commands.json.tpl + - build/qemu-system-riscv32 + - build/qemu-img + - build/exit_*.bin + +build-gcc: + tags: + - qemu_ot + stage: build + # build QEMU for OT platforms, ensure subprojects are cleaned up first + # build with GCC may need different warnings + script: + - rm -rf build-gcc + - mkdir build-gcc + - cd build-gcc + - ../configure --cc=gcc $QEMU_BUILD_OPTS --target-list=riscv32-softmmu,riscv64-softmmu + - ninja + +format: + tags: + - qemu_ot + stage: build + script: + - scripts/opentitan/ot-format.sh --ci --Werror --dry-run + +tidy: + tags: + - qemu_ot + stage: build + needs: ["build-clang"] + script: + - QEMU_DIR="$(pwd -P)"; cat build/compile_commands.json.tpl | + sed -E 's,@QEMU_DIR@,'"$QEMU_DIR"',g' > build/compile_commands.json + - scripts/opentitan/ot-tidy.py --build-dir build --ci-files -j diff --git a/.gitlab-ci.d/opentitan/ot-bmtests.yml b/.gitlab-ci.d/opentitan/ot-bmtests.yml new file mode 100644 index 0000000000000..9134c53b0925a --- /dev/null +++ b/.gitlab-ci.d/opentitan/ot-bmtests.yml @@ -0,0 +1,63 @@ +# Baremetal Tests for Earlgrey & Darjeeling + +baremetal-eg-tests: + tags: + - qemu_ot + stage: test + needs: + - "build-clang" + - project: rv/sandbox/rot/baremetal_test + job: build-eg + ref: $BAREMETAL_REF + artifacts: true + variables: + BASEDIR: bmtests/eg + CI_EXEC: 1 + DISABLE_FLAKY: 1 + script: + - python3 -m virtualenv .venv + - . .venv/bin/activate + - pip3 install -r scripts/opentitan/requirements.txt + - rm -rf ${BASEDIR} + - mkdir -p ${BASEDIR} + - zstd -d --stdout ot-eg-bmtest.tar.zst | tar xf - -C ${BASEDIR} + - find ${BASEDIR} + - scripts/opentitan/pyot.py -vv -c ${BASEDIR}/data/ot-earlgrey/qemu/pyot.hjson + -w ot-earlgrey.csv -R -T 3 + artifacts: + public: false + expire_in: 1 year + name: "bm-ot-earlgrey" + paths: + - ot-earlgrey.csv + +baremetal-dj-tests: + tags: + - qemu_ot + stage: test + needs: + - "build-clang" + - project: rv/sandbox/rot/baremetal_test + job: build-dj + ref: $BAREMETAL_REF + artifacts: true + variables: + BASEDIR: bmtests/dj + CI_EXEC: 1 + DISABLE_FLAKY: 1 + script: + - python3 -m virtualenv .venv + - . .venv/bin/activate + - pip3 install -r scripts/opentitan/requirements.txt + - rm -rf ${BASEDIR} + - mkdir -p ${BASEDIR} + - zstd -d --stdout ot-dj-bmtest.tar.zst | tar xf - -C ${BASEDIR} + - find ${BASEDIR} + - scripts/opentitan/pyot.py -vv -c ${BASEDIR}/data/ot-darjeeling/qemu/pyot.hjson + -w ot-darjeeling.csv -R -T 3 + artifacts: + public: false + expire_in: 1 year + name: "bm-ot-darjeeling" + paths: + - ot-darjeeling.csv diff --git a/.gitlab-ci.d/opentitan/ot-smoke.yml b/.gitlab-ci.d/opentitan/ot-smoke.yml new file mode 100644 index 0000000000000..ed5a82c9fd409 --- /dev/null +++ b/.gitlab-ci.d/opentitan/ot-smoke.yml @@ -0,0 +1,20 @@ +smoke-tests-ot: + tags: + - qemu_ot + stage: test + needs: ["build-clang"] + script: + - build/qemu-system-riscv32 -M help | grep ibexdemo + - build/qemu-system-riscv32 -M help | grep ot-earlgrey + - timeout -s KILL 4 build/qemu-system-riscv32 -M ibexdemo -nographic + -device loader,addr=0x100080,file=build/exit_id.bin -d in_asm,int + - timeout -s KILL 4 build/qemu-system-riscv32 -M ot-earlgrey,no_epmp_cfg=true + -object ot-rom_img,id=rom,file=build/exit_eg.bin -d in_asm,int + -nographic -global ot-ibex_wrapper.lc-ignore=on + -readconfig docs/config/opentitan/earlgrey.cfg + -trace ot_ibex_wrapper_exit + - timeout -s KILL 4 build/qemu-system-riscv32 -M ot-darjeeling,no_epmp_cfg=true + -object ot-rom_img,id=rom0,file=build/exit_dj.bin -d in_asm,int + -nographic -global ot-ibex_wrapper.lc-ignore=on + -readconfig docs/config/opentitan/darjeeling.cfg + -trace ot_ibex_wrapper_exit diff --git a/.gitlab-ci.d/opentitan/python-ot.yml b/.gitlab-ci.d/opentitan/python-ot.yml new file mode 100644 index 0000000000000..fb0cc173e82c3 --- /dev/null +++ b/.gitlab-ci.d/opentitan/python-ot.yml @@ -0,0 +1,14 @@ +python-ot: + tags: + - qemu_ot + stage: build + script: + # disable duplicate code as all front end are tested at once (false positive) + # disable fixme ("# TODO" comments) + - python3 -m virtualenv .venv + - . .venv/bin/activate + - pip3 install -r scripts/opentitan/requirements.txt + - pylint --rcfile scripts/opentitan/.pylintrc -d 'duplicate-code' -d 'fixme' + scripts/opentitan/*.py python/qemu/jtagtools python/qemu/ot + - flake8 --config scripts/opentitan/.flake8 + scripts/opentitan/*.py python/qemu/jtagtools python/qemu/ot diff --git a/.gitlab-ci.d/opentitan/qemu-ot.yml b/.gitlab-ci.d/opentitan/qemu-ot.yml new file mode 100644 index 0000000000000..7e2886b7ac24c --- /dev/null +++ b/.gitlab-ci.d/opentitan/qemu-ot.yml @@ -0,0 +1,9 @@ +variables: + BAREMETAL_REF: "ot-251125-1" + QEMU_BUILD_OPTS: "--disable-install-blobs" + +include: + - local: '/.gitlab-ci.d/opentitan/build.yml' + - local: '/.gitlab-ci.d/opentitan/python-ot.yml' + - local: '/.gitlab-ci.d/opentitan/ot-smoke.yml' + - local: '/.gitlab-ci.d/opentitan/ot-bmtests.yml' diff --git a/MAINTAINERS b/MAINTAINERS index 63e9ba521bcc5..e714850420e16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1680,14 +1680,41 @@ F: pc-bios/vof* RISC-V Machines --------------- + +EarlGrey and Darjeeling OpenTitan platforms +M: Emmanuel Blot +M: Loïc Lefort +S: Supported +F: hw/opentitan/* +F: include/hw/opentitan/* +F: scripts/opentitan/* +F: hw/riscv/ot_darjeeling.c +F: hw/riscv/ot_earlgrey.c +F: include/hw/riscv/ot_darjeeling.h +F: include/hw/riscv/ot_earlgrey.h + +Ibex platforms and utilities +M: Emmanuel Blot +M: Loïc Lefort +S: Supported +F: hw/riscv/ibex_common.c +F: include/hw/riscv/ibex_common.h +F: include/hw/riscv/ibex_irq.h +F: hw/ibexdemo/* +F: include/hw/ibexdemo/* + OpenTitan M: Alistair Francis L: qemu-riscv@nongnu.org S: Supported F: hw/riscv/opentitan.c -F: hw/*/ibex_*.c +F: hw/ssi/ibex_spi_host.c +F: hw/timer/ibex_timer.c +F: hw/char/ibex_uart.c F: include/hw/riscv/opentitan.h -F: include/hw/*/ibex_*.h +F: include/hw/ssi/ibex_spi_host.h +F: include/hw/timer/ibex_timer.h +F: include/hw/char/ibex_uart.h Microchip PolarFire SoC Icicle Kit L: qemu-riscv@nongnu.org diff --git a/README.md b/README.md new file mode 100644 index 0000000000000..11e299d9ce13a --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# QEMU OpenTitan README + +[![.github/workflows/build_test.yaml](https://github.com/lowRISC/qemu/actions/workflows/build_test.yaml/badge.svg?branch=ot-10.1.0)](https://github.com/lowRISC/qemu/actions/workflows/build_test.yaml) + +QEMU is a generic and open source machine & userspace emulator and virtualizer. + +QEMU is capable of emulating a complete machine in software without any need for hardware +virtualization support. By using dynamic translation, it achieves very good performance. + +This branch contains a fork of QEMU 10.1.0 dedicated to support lowRISC Ibex platforms: + * [OpenTitan](https://opentitan.org) [EarlGrey](docs/opentitan/ot_earlgrey.md), based on + [1.0.0](https://github.com/lowRISC/opentitan/tree/earlgrey_1.0.0). + * [OpenTitan](https://opentitan.org) [Darjeeling](docs/opentitan/ot_darjeeling.md), based on + [development version](https://github.com/lowRISC/opentitan/tree/master). + * [lowRISC](https://github.com/lowRISC/ibex-demo-system) [IbexDemo](docs/opentitan/ibexdemo.md). + +See [installation instructions](docs/opentitan/index.md) + +See also original [QEMU README file](README_QEMU.rst) diff --git a/README.rst b/README_QEMU.rst similarity index 100% rename from README.rst rename to README_QEMU.rst diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 7c20d9db122e5..2db0decc25d61 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -653,6 +653,10 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, static inline bool cpu_handle_halt(CPUState *cpu) { #ifndef CONFIG_USER_ONLY + if (unlikely(cpu->disabled)) { + return true; + } + if (cpu->halted) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; bool leave_halt = tcg_ops->cpu_exec_halt(cpu); @@ -703,6 +707,10 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) *ret = cpu->exception_index; if (*ret == EXCP_DEBUG) { cpu_handle_debug_exception(cpu); + if (cpu->exception_index < 0) { + /* the handler has cleared the exception */ + return false; + } } cpu->exception_index = -1; return true; @@ -998,6 +1006,13 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) tb_add_jump(last_tb, tb_exit, tb); } + if (unlikely((s.cflags != -1) && (s.cflags & CF_SINGLE_STEP))) { + CPUClass *cc = cpu->cc; + if (cc->debug_enable_singlestep) { + cc->debug_enable_singlestep(cpu, s.pc); + } + } + cpu_loop_exec_tb(cpu, tb, s.pc, &last_tb, &tb_exit); /* Try to align the host and virtual clocks diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/riscv32-softmmu/default.mak index c2cd86ce05f02..8122e3247503f 100644 --- a/configs/devices/riscv32-softmmu/default.mak +++ b/configs/devices/riscv32-softmmu/default.mak @@ -10,3 +10,6 @@ # CONFIG_SIFIVE_U=n # CONFIG_RISCV_VIRT=n # CONFIG_OPENTITAN=n +# CONFIG_OT_DARJEELING=n +# CONFIG_OT_EARLGREY=n +# CONFIG_IBEXDEMO=n diff --git a/disas/meson.build b/disas/meson.build index bbfa11978352e..d549b9b072ebf 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -7,7 +7,8 @@ common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c', 'nanomips.c')) common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files( 'riscv.c', 'riscv-xthead.c', - 'riscv-xventana.c' + 'riscv-xventana.c', + 'riscv-zbr.c' )) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) diff --git a/disas/riscv-zbr.c b/disas/riscv-zbr.c new file mode 100644 index 0000000000000..1f03752ec3518 --- /dev/null +++ b/disas/riscv-zbr.c @@ -0,0 +1,78 @@ +/* + * QEMU RISC-V Disassembler for Zbr + * + * Copyright (c) 2023 Rivos Inc + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "disas/riscv.h" +#include "disas/riscv-zbr.h" + +typedef enum { + /* 0 is reserved for rv_op_illegal. */ + rv_op_crc32_b = 1, + rv_op_crc32_h = 2, + rv_op_crc32_w = 3, + rv_op_crc32_d = 4, + rv_op_crc32c_b = 5, + rv_op_crc32c_h = 6, + rv_op_crc32c_w = 7, + rv_op_crc32c_d = 8, +} rv_zbr_op; + +const rv_opcode_data rv_zbr_opcode_data[] = { + { "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, + { "crc32.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32.w", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32c.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32c.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32c.w", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "crc32c.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, +}; + +void decode_zbr(rv_decode *dec, rv_isa isa) +{ + rv_inst inst = dec->inst; + rv_opcode op = rv_op_illegal; + + switch ((inst >> 0) & 0b1111111) { + case 0b0010011: + switch ((inst >> 12) & 0b111) { + case 0b001: + switch ((inst >> 20 & 0b111111111111)) { + case 0b011000010000: + op = rv_op_crc32_b; + break; + case 0b011000010001: + op = rv_op_crc32_h; + break; + case 0b011000010010: + op = rv_op_crc32_w; + break; + case 0b011000010011: + op = rv_op_crc32_d; + break; + case 0b011000011000: + op = rv_op_crc32c_b; + break; + case 0b011000011001: + op = rv_op_crc32c_h; + break; + case 0b011000011010: + op = rv_op_crc32c_w; + break; + case 0b011000011011: + op = rv_op_crc32c_d; + break; + } + break; + } + break; + } + dec->op = op; +} diff --git a/disas/riscv-zbr.h b/disas/riscv-zbr.h new file mode 100644 index 0000000000000..366040ed53c23 --- /dev/null +++ b/disas/riscv-zbr.h @@ -0,0 +1,18 @@ +/* + * QEMU RISC-V Disassembler for Zbr + * + * Copyright (c) 2023 Rivos Inc + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef DISAS_RISCV_ZBR_H +#define DISAS_RISCV_ZBR_H + +#include "disas/riscv.h" + +extern const rv_opcode_data rv_zbr_opcode_data[]; + +void decode_zbr(rv_decode *, rv_isa); + +#endif /* DISAS_RISCV_ZBR_H */ diff --git a/disas/riscv.c b/disas/riscv.c index 85cd2a9c2aefe..a6185a1017a43 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -27,6 +27,9 @@ #include "disas/riscv-xthead.h" #include "disas/riscv-xventana.h" +/* Extensions that are not yet upstream */ +#include "disas/riscv-zbr.h" + typedef enum { /* 0 is reserved for rv_op_illegal. */ rv_op_lui = 1, @@ -5434,6 +5437,9 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, { has_xtheadmempair_p, xthead_opcode_data, decode_xtheadmempair }, { has_xtheadsync_p, xthead_opcode_data, decode_xtheadsync }, { has_XVentanaCondOps_p, ventana_opcode_data, decode_xventanacondops }, + + /* Instructions that are not yet upstream */ + { has_zbr_p, rv_zbr_opcode_data, decode_zbr }, }; for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { @@ -5529,3 +5535,14 @@ int print_insn_riscv128(bfd_vma memaddr, struct disassemble_info *info) { return print_insn_riscv(memaddr, info, rv128); } + +const char *get_riscv_debug_reg_name(int regno) +{ + switch (regno) { + case 0x0000 ... 0x0fff: return csr_name(regno); + case 0x1000 ... 0x101f: return rv_ireg_name_sym[regno-0x1000]; + case 0x1020 ... 0x103f: return rv_freg_name_sym[regno-0x1020]; + /* TODO: need to add vector regs (not part of 0.13.2 debug spec) */ + default: return NULL; + } +} diff --git a/docs/config/opentitan/darjeeling.cfg b/docs/config/opentitan/darjeeling.cfg new file mode 100644 index 0000000000000..e7b9802d8b9e3 --- /dev/null +++ b/docs/config/opentitan/darjeeling.cfg @@ -0,0 +1,69 @@ +# Generated from OpenTitan commit: c5507b4cdc + +[ot_device "ot-rom_ctrl.rom0"] + key = "30ae84156d37cc68063276f9e85faee1" + nonce = "0a553e45bab60fd5" + +[ot_device "ot-rom_ctrl.rom1"] + key = "9649127ec56c7b0e9645bf231b5b37b8" + nonce = "29ae80f5b440dc77" + +[ot_device "ot-otp-dj"] + digest_const = "09c87e42745452d8a010a9f0ef3221d5" + digest_iv = "a0806e02a1fba55b" + inv_default_part_15 = "58b183f3d37975b4a9524de21084a9d64bba835c10b5e29043022273f7afbf68e78e601c1704c34a6dfd043e96e1ef76d15c0798ef406091d605165216fd3f856fb88c3b4fd535bd" + inv_default_part_16 = "00000000696900001f2a6bd606d55f72" + inv_default_part_17 = "1fb5110b0618183cbf722f142ef9facfb5742826d2ce8d8bb874ddd1dbca5322ddf650f1a00008ee0000000000000000" + inv_default_part_18 = "2552a6aa7830346413591b15ed2553188688686a7d26f94a0000000000000000" + inv_default_part_19 = "eff32b59c0a86294d9767fdcb47456994c8fd64171edb20835aef32cf20b0c620e9af6c53593daec8e3caa2e495a897602e2904aa8a7090712cf9a372be9c2b9c1fbff3b68368c5afedcdee44f5d8d84276d9c42b4b5c6539c73a2705a4682baa1885457797963c3980bff063fc8bc645a7f3e2373a78aa20000000000000000" + inv_default_part_20 = "9c47222c695c123916e90f1bdde834c31d3eef689e998822eddeb20732f666faba37deb973d827e00000000000000000" + inv_default_part_21 = "6149b9ff4f5979607aead63a44f896431df745a52c5af5fdf86d2ce9fa1041c43f145a8bf5be7640d7aaf2481067180fd08f694a5f790581d728bd369d03f8087a60a7f8ed956442c9cff0f99e594c7307f376e7b2b2ff8c" + scrmbl_key = "d6780626a12b5904a9b37439f8177d19d04d3fad040ed02909a9ea4b5429b9e6" + secret0_scramble_key = "688a9a20b68e0d35660e593f560f6866" + secret1_scramble_key = "a1ad90a50942397740ab78c5737a2379" + secret2_scramble_key = "c2ede5b25ec5514b680ccaab361c3f85" + secret3_scramble_key = "8e1c5cccc121a2c95d21294d190ab75c" + sram_const = "4dcba329ff2f7d4b8a3acdb325087fab" + sram_iv = "9bd623e40aec9b61" + +[ot_device "ot-lc_ctrl"] + dev = "d2fd2987e3062f6119c7560acbbe9f6f" + invalid = "0d20b07721f7ff507ad2b9fb9cc7ff06" + lc_state_first = "eebd62140286d28089f20c8f78baa23d9210b65583a165a35342d646189f81d751c346984482681b" + lc_state_last = "eebde6d52eb6dbd5b9f79dcf7ebfbe3fb672bff5dfe577afd36efe6f99ffe1ff73e3779ec4fa7a9b" + lc_trscnt_first = "ff595454ab481e0fd02144da44cc929a4149279a202522dcf2352590ec602b24d82b42968a94dec42469cc17190a4e65" + lc_trscnt_last = "ff59557fbb79decfd2b776fb6fcfdf9b51f9affbad277bfcfab7a7b1ef70ebafdcebd6bebadeffc7a66fff17993a7e75" + ownership_first = "ea846e2884d9198c4a42348a61406249" + ownership_last = "fecc6faaeef93dcccefef68f696f6adf" + production = "ffc2171a49199bb53d8e0daa8f0578db" + raw_unlock_token = "e4225dc332ea1fda63b4c524556ed4d4" + rma = "aa5f022791480b4e709e0f80976e0966" + soc_dbg_first = "6b36fc2c" + soc_dbg_last = "ebf6fc7f" + test_unlocked = "e4c72c47d9e15fa8ff9f82833e32c151" + +[ot_device "ot-keymgr_dpe"] + aes_seed = "9a885419a9d57e36519fa42d20efa348cb77f5089a8381b62d9717b3647e5ce0" + hard_output_seed = "4d57ac27843ea2a0163efeda5b24d93f97d62d99c960542f4a1f2595192e9a96" + kmac_seed = "796ca68aa29523d3f94f27c74acae76b3e145326741f804e3c3a3451469c6118" + lfsr_seed = "488f3ffa7700ec4c" + none_seed = "49fcb59874cddc9cbc645d9e02a96b9980911844d3c74de85e05164b829d484b" + otbn_seed = "fa23bc32e428ad2be2584fe8d5491fa8e7f19aaa4133ad0d2704702ae2ff9d98" + revision_seed = "7b416b49b114f994a969864a57c3482ab3bdcbd9fe825728f7ba40a22c9719c5" + soft_output_seed = "d7c160f492d0e8757631ebf752a1e5604e2d6171f5dba9ec4249052dcc7a4d58" + +[ot_device "ot-ast-dj"] + topclocks = "main:1000000000,io:1000000000,aon:62500000" + aonclocks = "aon" + +[ot_device "ot-clkmgr"] + topclocks = "main:16,io:16,aon:1" + refclock = "aon" + subclocks = "io_div2:io:2,io_div4:io:4,aes:main:1,hmac:main:1,kmac:main:1,otbn:main:1" + groups = "powerup:aon+io+io_div2+io_div4+main,trans:aes+hmac+kmac+otbn,infra:aon+io_div4+main,secure:io_div4+main,peri:aon+io_div2+io_div4,timers:aon+io_div4" + swcg = "peri" + hint = "trans" + +[ot_device "ot-pwrmgr"] + clocks = "main,io" + diff --git a/docs/config/opentitan/earlgrey.cfg b/docs/config/opentitan/earlgrey.cfg new file mode 100644 index 0000000000000..0836d865872be --- /dev/null +++ b/docs/config/opentitan/earlgrey.cfg @@ -0,0 +1,71 @@ +# Generated from OpenTitan commit: 011b6ea1fe + +[ot_device "ot-rom_ctrl"] + key = "663c291739ff0e7d644758fee1c58564" + nonce = "fee457dee82b6e06" + +[ot_device "ot-otp-eg"] + digest_const = "0e95f517cb98955b4d5a89aa9109294a" + digest_iv = "bead91d5fa4e0915" + flash_addr_const = "d60822e1faec5c7290c7f21f6224f027" + flash_addr_iv = "0b7474d640f8a7f5" + flash_data_const = "277195fc471e4b26b6641214b61d1b43" + flash_data_iv = "e048b657396b4b83" + inv_default_part_5 = "7edc64361898f6ff7023461f42b4a5b3f7f71ea9a9507acf17c456385a48b963a629408e450e8458f3cd636e3c9a1140ae2905da9b31bb7ac60dd16b888838df2737bacf95ed7bf8" + inv_default_part_6 = "6969690000000000f254e78568a7f4bb" + inv_default_part_7 = "024c5fee0f5c8bb2c3080ad0531facb5370ad4f5b61d71b62203a5595f131d71a060cae9543819be" + inv_default_part_8 = "31dc5b08ced196d3b50ff2274384b9dbdd0d4e5d6bd0177ec2dce29f8327c8dbca99e674d3996d4260d2a0790332d0552ab6973f142947235a0c88a3ea33571096c8ddc72428751c29709bbd80960ee0a80ddce593c569c4" + inv_default_part_9 = "8a1cd4f5518b4d2a1978b594ed3dcd94671685f41086d5d3f6f8a097aad0585e4d857adfdebd0d2c0ece8ed011c5bad01988d871b8d25f316e627ccc51fc79029f45333ca4988068edfed1b3f0968cd628a94cbb02adbb8c" + inv_default_part_10 = "be6f2b4a67801b852a4529345af1cdbf37e97ab260e717e8e3c3363a666c130154d936fd1163e401fadd9f8c0ee9d1a056a2719fc2c345a4873c594f465e723e64ba4e17c79665cccb7943e751f0059633fbb917e41db693" + scrmbl_key = "55d70063277642b5309a163990b966cd494444c3bcdf8087b7facd65e9654cd8" + secret0_scramble_key = "3ba121c5e097ddeb7768b4c666e9c3da" + secret1_scramble_key = "effa6d736c5eff49ae7b70f9c46e5a62" + secret2_scramble_key = "85a9e830bc059ba9286d6e2856a05cc3" + sram_const = "4a22d4b78fe0266fbee3958332f2939b" + sram_iv = "f98c48b1f9377284" + +[ot_device "ot-lc_ctrl"] + dev = "90f9c5c06f733dc911a321dd4c0ac240" + invalid = "5bc66d10208c4fb51b97bbf4d12c378c" + lc_state_first = "ee75b407d2314d2ef84185ac8c990f536071632c086d4c924070be92d2948d6228b2711e9b2d8c4d" + lc_state_last = "ee75fe0ffe7b6f3ffc5f9ffd9ff96fdb7f736f6c9e6fdcd35277fef2d3bdcd6ffbb2f59fdf3fbedd" + lc_trscnt_first = "dfb6c45a241f85ce9f42229e8627462fdb02c6701242f14b41891180045c09c26c52744267c04aa055921b9461bb07da" + lc_trscnt_last = "dfb6f4fabf1fefcebf5ba2ffc677c6afdbabcefeb672f36b4fbdb3988dfe1be67e7e77ca77c76af7ddde3b9e7fbfe7de" + ownership_first = "3c61398d626885931da660ed2ab18a0f" + ownership_last = "bc757dbdeaf9b7d35de7e9efabfbbecf" + production = "6d467215dab3f2b54a52e6728678af07" + raw_unlock_token = "ea2b3f32cbe77554e43c8ea7ebf197c2" + rma = "18068e344d2eae4d73c8fa54de8aa4a4" + soc_dbg_first = "440af80d" + soc_dbg_last = "6c9ef9cf" + test_unlocked = "cfd6a5a5bf3032db51fa1eb92f6ce10e" + +[ot_device "ot-keymgr"] + aes_seed = "c9e662e1e1b4982b3e8eff63890dbeae926fd468a77efde3de5b4caf4776a247" + cdi_seed = "516c144b34c96dfabb6f6e79208a74f35c79f397c4e4c7e22b7581848a90a125" + creator_identity_seed = "70251696fbb4ba169a6cd82fad46a0a5c04009bb934c7ef7b83b6e40610b4309" + hard_output_seed = "baf4410f06dcc036fcd16fcde97d171891105dd895e3a1d0a19a16d6dbd8b20f" + kmac_seed = "baba4c9908ed16bc5415ec16d28c53551312fcedcf2832a66ceacf8ed4d5b616" + lfsr_seed = "6ca8a8225c8e1705" + none_seed = "4b2276bec9fc1a7a5722a9aaca4db84a32e5c6985a1a6435118b5f5f3fd3b931" + otbn_seed = "177dd43b56fa754e1f53ad658193b563d9bdc6d2aee84852f0cc7371ed3a6faa" + owner_identity_seed = "a4a7bdb05fe921615bf2ff984540f7d43ece76b4eb13363774ed2ed45545e927" + owner_int_identity_seed = "fcb9dc54d4276137f9901d09a76aeaa19de5c579fd38bdf38f0c21d6a52226b6" + revision_seed = "20bdaf59fe2ae209b8325d2c8c35fc960679b106a87e59e6aeb1b5302d334010" + soft_output_seed = "f6d9e4abac398d42c745eef646c1464dca86dafd7c7c71e6058ddfd871c51cac" + +[ot_device "ot-ast-eg"] + topclocks = "main:100000000,io:96000000,usb:48000000,aon:200000" + aonclocks = "aon" + +[ot_device "ot-clkmgr"] + topclocks = "main:500,io:480,usb:240,aon:1" + refclock = "aon" + subclocks = "io_div2:io:2,io_div4:io:4,aes:main:1,hmac:main:1,kmac:main:1,otbn:main:1" + groups = "powerup:aon+io+io_div2+io_div4+main+usb,trans:aes+hmac+kmac+otbn,infra:io+io_div2+io_div4+main+usb,secure:aon+io_div4+main,peri:aon+io+io_div2+io_div4+usb,timers:aon+io_div4" + swcg = "peri" + hint = "trans" + +[ot_device "ot-pwrmgr"] + clocks = "main,io,usb" + diff --git a/docs/opentitan/cfggen.md b/docs/opentitan/cfggen.md new file mode 100644 index 0000000000000..60fb06e867135 --- /dev/null +++ b/docs/opentitan/cfggen.md @@ -0,0 +1,96 @@ +# `cfggen.py` + +`cfggen.py` is a helper tool that can generate a QEMU OT configuration file, +for use with QEMU's `-readconfig` option, populated with sensitive data for +the ROM controller(s), the OTP controller, the Life Cycle controller, etc. + +It heurastically parses configuration and generated RTL files to extract from +them the required keys, seeds, nonces and other tokens that are not stored in +the QEMU binary. + +## Usage + +````text +usage: cfggen.py [-h] [-T {darjeeling,earlgrey}] [-o CFG] [-c SV] [-l SV] + [-S HJSON] [-t HJSON] [-s SOCID] [-C COUNT] + [-a {config,clock}] [-x DEVICE.NAME] [-v] [-d] + [OTDIR] + +OpenTitan QEMU configuration file generator. + +options: + -h, --help show this help message and exit + +Files: + OTDIR OpenTitan root directory + -T, --top {darjeeling,earlgrey} + OpenTitan top name + -o, --out CFG Filename of the config file to generate + -c, --otpconst SV OTP Constant SV file (default: auto) + -l, --lifecycle SV LifeCycle SV file (default: auto) + -S, --secrets HJSON Secret HJSON file (default: auto) + -t, --topcfg HJSON OpenTitan top HJSON config file (default: auto) + +Modifiers: + -s, --socid SOCID SoC identifier, if any + -C, --count COUNT SoC count (default: 1) + +Actions: + -a, --action {config,clock} + Action(s) to perform, default: config + -x, --exclude DEVICE.NAME + Discard any property from DEVICE that starts with NAME + (may be repeated) + +Extras: + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +`OTDIR` is a required positional argument which should point to the root directory of the OpenTitan +repository to analyze. It is used to generate the path towards the required files to parse, each of +which can be overridden with options `-c`, `-l` and `-t`. + +* `-a` specify one or more actions to execute. Default is to generate a configuration file. It is + also possible to emit the list of module input clocks in a plain text format. + +* `-C` specify how many SoCs are used on the platform + +* `-c` alternative path to the `otp_ctrl_part_pkg.sv` file + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-l` alternative path to the `lc_ctrl_state_pkg.sv.sv` file + +* `-o` the filename of the configuration file to generate. It not specified, the generated content + is printed out to the standard output. + +* `-S` path to the generated file that contains all the "secret" constants of the _top_. + +* `-s` specify a SoC identifier for OT platforms with multiple SoCs + +* `-T` specify the OpenTitan _top_ name, such as `darjeeling`, `earlgrey`, ... This option is + mandatory if `-t` is not specified. An OTDIR root directory should be specified with this option. + +* `-t` path to the `top_.gen.hjson` file. This option is mandatory is `-T` is not specified. + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +* `-x` can be used to prevent some device properties from being emitted in the output stream. This + can be useful while implementing a device, whose emulation does not support the comprehensive + feature set of its HW counterpart. + +### Examples + +````sh +./scripts/opentitan/cfggen.py ../opentitan -T earlgrey -o opentitan.cfg +```` + +````sh +# do not emit any 'flash*' properties for the EarlGrey OTP controller +./scripts/opentitan/cfggen.py -o opentitan.cfg \ + -t ../opentitan/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson + -x ot-otp-eg.flash +```` diff --git a/docs/opentitan/checkregs.md b/docs/opentitan/checkregs.md new file mode 100644 index 0000000000000..d16fcf5a86ab6 --- /dev/null +++ b/docs/opentitan/checkregs.md @@ -0,0 +1,72 @@ +# `checkregs.py` + +`checkregs.py` checks whether QEMU register definitions for OpenTitan match the generated OpenTitan +`*_regs.h` files. This enables to spot major differences whenever OpenTitan definitions are updated. + +Note that only register addresses are checked for now, the bit assignment in each register is not +validated. + +## Usage + +````text +usage: checkregs.py [-h] [-q dir] [-a] [-k] [-M] [-v] [-d] file [file ...] + +Verify register definitions. + +positional arguments: + file register header file + +options: + -h, --help show this help message and exit + -q dir, --qemu dir QEMU directory to seek + -a, --all list all discrepancies + -k, --keep keep verifying if QEMU impl. is not found + -M, --no-map do not convert regs into QEMU impl. path + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-a` list all discrepancies rather than only reporting their count. + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-k` keep searching for discrepancies if some error is detected. + +* `-M` do not try to map radix of input register files into their QEMU counter part + +* `-q dir` the directory to look for OpenTitan devices to check. + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +### Examples + +* All EarlGrey register files have been copied into `opentitan/regs-251rc1` + + ````sh + scripts/opentitan/checkregs.py -k -q hw/opentitan ~/opentitan/regs-251rc1/*.h + ```` + reports + ```` + ERROR ot.regs ot_hmac.c: 1 discrepancies + ERROR ot.regs ot_otbn.c: 2 discrepancies + ERROR ot.regs ot_otp.c: 69 discrepancies + ERROR ot.regs ot_pinmux.c: 585 discrepancies + ERROR ot.regs ot_ibex_wrapper.c: 1 discrepancies + 658 differences + ```` + `pinmux` and `otp` registers in QEMU OT are not implemented as a flat list of registers, which + explain the large amount of discrepancies. + + ````sh + scripts/opentitan/checkregs.py -a -k -q hw/opentitan ~/opentitan/regs-251rc1/rv_core_ibex_regs.h -v + ```` + reports + ```` + WARNING ot.regs QEMU ot_ibex_wrapper.c is missing 1 defs + WARNING ot.regs .. DV_SIM_WINDOW (0x80) + ERROR ot.regs ot_ibex_wrapper.c: 1 discrepancies + 1 differences + ```` + which is Ok as DV_SIM_WINDOW is not supported on QEMU. diff --git a/docs/opentitan/debug.md b/docs/opentitan/debug.md new file mode 100644 index 0000000000000..b378dfc60c887 --- /dev/null +++ b/docs/opentitan/debug.md @@ -0,0 +1,51 @@ +## Useful debugging options + +### Device log traces + +Most OpenTitan virtual devices can emit log traces. To select which traces should be logged, a plain +text file can be used along with QEMU `-trace` option. + +To populate this file, the easiest way is to dump all available traces and filter them with a +pattern, for example to get all OpenTitan trace messages: + +````sh +qemu-system-riscv32 -trace help | grep -E '^ot_' > ot_trace.log +qemu-system-riscv32 -trace events=ot_trace.log -D qemu.log ... +```` + +* It is *highly* recommended to use the `-D` option switch when any `-trace` or `-d` (see below) is +selected, to avoid saturating the standard output stream with traces and redirect them into the +specified log file. + +### QEMU log traces + +QEMU provides another way of logging execution of the virtual machine using the `-d` option. Those +log messages are not tied to a specific device but rather to QEMU features. `-d help` can be used +to enumerate these log features, however the most useful ones are enumerated here: + + * `unimp` reports log messages for unimplemented features, _e.g._ when the vCPU attempts to + read from or write into a memory mapped device that has not been implemented. + * `guest_errors` reports log messages of invalid guest software requests, _e.g._ attempts to + perform an invalid configuration. + * `int` reports all interruptions *and* exceptions handled by the vCPU. It may be quite verbose + but also very useful to track down an invalid memory or I/O access for example. This is the + first option to use if the virtual machine seems to stall on start up. + * `in_asm` reports the decoded vCPU instructions that are translated by the QEMU TCG, _i.e._ here + the RISC-V instructions. Note that transcoded instructions are cached and handled by blocks, + so the flow of transcoded instruction do not exactly reflect the stream of the executed guest + instruction, e.g. may only appear once in a loop. Use the next log option, `exec`, to get + more detailed but also much more verbose log traces. + * `exec` reports the vCPU execution stream. + +Those options should be combined with a comma separator, _e.g._ `-d unimp,guest_errors,int` + +`in_asm` option may be able to report the name of the guest executed function, as long as the guest +application symbols have been loaded. This is the case when the `-kernel` option is used to load +an ELF non-stripped file. Unfortunately, this feature is not available for guest applications that +are loaded from a raw binary file (`.bin`, `.signed.bin`, ...). However the +[`flashgen.py`](flashgen.md) script implements a workaround for this feature, please refer to this +script for more details. + +Finally, a Rust demangler has been added to QEMU, which enables the QEMU integrated disassembler to +emit the demangled names of the Rust symbols for Rust-written guest applications rather than their +mangled versions as stored in the ELF file. diff --git a/docs/opentitan/devproxy.md b/docs/opentitan/devproxy.md new file mode 100644 index 0000000000000..82b72c1f4e6c0 --- /dev/null +++ b/docs/opentitan/devproxy.md @@ -0,0 +1,1181 @@ +## DevProxy Protocol + +### Header + +#### DevProxy header + +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| COMMAND | LENGTH | ++---------------+---------------+---------------+---------------+ +| UID |I| ++---------------+---------------+---------------+---------------+ +``` + +#### DOE PCIe header [doe-pcie-header] + +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| VendorID |ObjectDataType | - | ++---------------+---------------+---------------+---------------+ +| Length | - | ++---------------+---------------+---------------+---------------+ +``` + +#### Length fields + +##### Notes + * Values are encoded using the LE (litle endian) format + * `LENGTH` is the length in bytes excluding the first 8 bytes of the MBXPROXY protocol header, + coded on 16 bits. Payload is therefore < 64KB. + * This field is different from the `Length` is the length in 32-bit words (DW per Intel + terminology) of the Data Object itself, including the 2 first 32-bit words of the DOE header, + coded on 18 bits. Theoritical DOE payload is therefore ~1MB, which is capped by the MBX protocol. + It is not expected to have DOE packets larger than 4KB anyway. + +#### UID and Initiator fields + +DevProxy header is not related whatsoever to the content of the DOE packet, it is a simplistic TLV +protocol, extended with a 31+1 bit UID. This UID is not accounted for in the `LENGTH` field, and is +always present. The UID is a monotonic increasing integer. The initiator of a request should +increment the UID for each request. The receiver should reply once with the same UID. The receiver +should always acknowledge a request, whether it is successfully handled or not, in which case it +should reply with a error code, using the UID of the failed command. The MSB of the 32-bit field +that contains the UID is used to distinguish the peer. The QEMU peer is using `1`, the remote peer +should use `0`. There are therefore two independent UID sequences: each UID is managed and +incremented by the initiator, the receiver never modifies the UID. UIDs are used as sanity check to +ensure sync is not lost between requests and responses. It is a fatal error to miss one UID or to +reuse one. Roll over cases are not managed (2G requests). DevProxy protocol can be used with any +kind of payload, i.e. not DOE payloads. This is the case for the first requests performed on the +communication link for example (see below). + +#### Command fields + +Commands are coded with a 16-bit field. It is expected to only use ASCII bytes for commands, i.e. +two characters that should be enough to encode many commands. Moreover, the initiator of a request +should use UPPERCASE command, and the receiver should reply with the same command using only +lowercased character. This allows to disambiguate initiators from responders, and use of ASCII +character helps tracking and debugging packets. If a command cannot be executed on the receiver +side, the receiver should reply with a `xx` response command (lowercased). The UID enables to track +which command has failed. There is no other cases where the initiator command and the response +command differ (case-insensitive). `XX` is therefore a reserved command. + +#### Role fields + +`Role` field encode an access control list role to use to access a register or a memory location. +Valid values depends on the remote proxy, however the highest (role = 0xF) is reserved to specify +that role field should be ignored, and role-less accessor should be used by the remote proxy. + +### Request/Response packets + +#### Error + +##### Request + +Not applicable + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'xx' | 4..4+N | ++---------------+---------------+---------------+---------------+ +| UID |S| ++---------------+---------------+---------------+---------------+ +| Address | Device | - | ++---------------+---------------+---------------+---------------+ +| Error Code | ++---------------+---------------+---------------+---------------+ +| | +| | +| (Error Message) | +| | +| | ++---------------+---------------+---------------+---------------+ +``` +* `Error Code` is a 32-bit error code that is always present + +``` ++------------+---------------+----------------------------------+ +| Error Code | Error Type | Error Description | ++------------+---------------+----------------------------------+ +| 0x0 | | No error | ++------------+---------------+----------------------------------+ +| 0x1 | Undefined | Unknown | ++------------+---------------+----------------------------------+ +| 0x101 | Request | Invalid command length | ++------------+---------------+----------------------------------+ +| 0x102 | Request | Invalid command code | ++------------+---------------+----------------------------------+ +| 0x103 | Request | Invalid request identifier | ++------------+---------------+----------------------------------+ +| 0x104 | Request | Invalid specifier identifier | ++------------+---------------+----------------------------------+ +| 0x105 | Request | Invalid device identifier | ++------------+---------------+----------------------------------+ +| 0x106 | Request | Invalid request | ++------------+---------------+----------------------------------+ +| 0x107 | Request | Invalid address/register address | ++------------+---------------+----------------------------------+ +| 0x201 | State | Device in error | ++------------+---------------+----------------------------------+ +| 0x401 | Local | Cannot read device | ++------------+---------------+----------------------------------+ +| 0x402 | Local | Cannot write device | ++------------+---------------+----------------------------------+ +| 0x403 | Local | Truncated response | ++------------+---------------+----------------------------------+ +| 0x404 | Local | Incomplete write | ++------------+---------------+----------------------------------+ +| 0x405 | Local | Out of resources | ++------------+---------------+----------------------------------+ +| 0x801 | Internal | Unsupported device | ++------------+---------------+----------------------------------+ +| 0x802 | Internal | Duplicated unique identifier | ++------------+---------------+----------------------------------+ +``` + +* `Error Message` is an optional error message to help diagnose the actual error. The length of the + error message string can be retrieved from the `LENGTH` field. + +Any request may be responded with an error packet. + +#### Handshake + +Handshake is the first command exchanged over the communication link. It enables sanity check of the +link, and to retrieve the version of the protocol the QEMU peer implement. It is the application +responsability to ensure it can successfully communicate with the QEMU proxy. + +Only initiated by the application. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'HS' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'hs' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Version Min | Version Maj | | ++---------------+---------------+---------------+---------------+ +``` + +The current version for this documentation is v0.15. + +Note that semantic versionning does not apply for v0 series. + +#### Logmask + +Logmask can be used to change the qemu_log_mask bitmap at runtime, so log +settings can be altered for specific runtime ranges, for a specific test for +example + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'HL' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---+-----------+---------------+---------------+---------------+ +| Op| Log mask | ++---+-----------+---------------+---------------+---------------+ +``` + +* `Op`: Log operation, among: + * `0`: change nothing, only read back the current log levels + * `1`: add new log channels from the log mask + * `2`: clear log channels from the log mask + * `3`: apply the log mask as is, overridding previous log channel settings + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'hl' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---+-----------+---------------+---------------+---------------+ +| 0 | Previous log mask | ++---+-----------+---------------+---------------+---------------+ +``` + +#### Enumerate Devices [enumerate-devices] + +Enumerate should be called by the Application to retrieve the list of remote devices that can be +driven from the Application over the communication link. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ED' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ed' | 0..4*7N | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Offset | Device | - | ++---------------+---------------+---------------+---------------+ +| Base Address | ++---------------+---------------+---------------+---------------+ +| Word Count | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| Offset | Device | - | ++---------------+---------------+---------------+---------------+ +| Base Address | ++---------------+---------------+---------------+---------------+ +| Word Count | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Offset | Device | - | ++---------------+---------------+---------------+---------------+ +| Base Address | ++---------------+---------------+---------------+---------------+ +| Word Count | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +``` +Reponse contains 0 up to N devices, each device is described with a 28-byte entry, where: + +* `Device` is a unique device identifier that should be used to select the device for all further + requests to the device. +* `Offset` is the relative base address of the first register than can be accessed on the device, + expressed in 32-bit word count +* `RegCount` is the count of 32-bit registers that can be accessed, starting from the base address, + only if b0 is zero. +* `WordCount` is the count of 32-bit slots for a memory-type device +* `Base Address` is the base address of the device in the address space as seen from the local CPU. +* `Identifier` is an arbitrary 16-character string that describes the device. + +The count of device entries can be retrieved from the `LENGTH` field. + +#### Enumerate Memory Spaces [enumerate-mr-spaces] + +Enumerate should be called by the Application to retrieve the list of remote memory spaces that can +be used from the Application over the communication link. + +Each memory space is a top-level memory region, _i.e._ a root memory region. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ES' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'es' | 0..11*4N | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| - | MSpc | ++---------------+---------------+---------------+---------------+ +| Start Address | ++---------------+---------------+---------------+---------------+ +| Size | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| - | MSpc | ++---------------+---------------+---------------+---------------+ +| Start Address | ++---------------+---------------+---------------+---------------+ +| Size | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| - | MSpc | ++---------------+---------------+---------------+---------------+ +| Start Address | ++---------------+---------------+---------------+---------------+ +| Size | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +``` +Reponse contains 0 up to N devices, each device is described with a 44-byte entry, where: + +* `MSpc` is a unique address space identifier than can be used as a selector in other proxy + commands. +* `Start Address` is the lowest valid address in the address space. +* `Size` is the size (in bytes) of the address space +* `Identifier` is an arbitrary 32-character string that describes the memory space. + +The count of address spaces can be retrieved from the `LENGTH` field. + +#### Register Read + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'RW' | 8 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +``` + +Read the content of a 32-bit word register, where + +* `Address` is the register index, i.e. the relative address in bytes / 4. +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'rw' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Value | ++---------------+---------------+---------------+---------------+ +``` + +#### Register Write + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'WW' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +| Value | ++---------------+---------------+---------------+---------------+ +| Mask | ++---------------+---------------+---------------+---------------+ +``` + +Write the content of a 32-bit word register, where + +* `Address` is the register index, i.e. the relative address in bytes / 4. +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Value` is the (optionally masked) 32-bit value to write +* `Mask` is the mask of bits to be written. Masked bits (0) are left unmodified, unmasked bits (1) + are replaced with the bits from the value field. The remote device use read-modify-write sequence + if the destination device does not support atomic set. + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ww' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +#### Read Buffer + +Read the content of several subsequence 32-bit registers, where + +* `Address` is the index of the first register, i.e. the relative address in bytes / 4. The address + is automatically incremented by the receiver side to read each register +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Count` is the number of the register to read. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'RS' | 8 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'rs' | 4..4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #N-1 | ++---------------+---------------+---------------+---------------+ +``` + +#### Write Buffer + +Write the content of several subsequence 32-bit registers, where + +* `Address` is the index of the first register, i.e. the relative address in bytes / 4. The address + is automatically incremented by the receiver side to write each register +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Value` are the values to write in each register. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'WS' | 4 + 4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #N-1 | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ws' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +#### Read Mailbox + +Read the content of a DOE mailbox, where + +* `Address` is the index of the mailbox register, i.e. the relative address in bytes / 4. +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Count` is the number of the 32-bit words to read out of the mailbox + +The content of the mailbox is read till either `Count` 32-bit words are read _or_ the Data Object +has been fully read. Each read word is automatically flagged as read in the remote mailbox (see DOE +protocol for detail). + +It is the responsability of the Application to ensure that the remote mailbox is ready to be read +before initiating this command. If an error occurs during the read out of the mailbox, an error +response should be returned. It is not an error to read less words than requests, _i.e._ it is safe +to specify a high count of words to read - as long as the response may fit into a DevProxy packet. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'RX' | 8 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'rx' | 4..4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #Count-1 | ++---------------+---------------+---------------+---------------+ +``` + +#### Write Mailbox + +Write a message into the DOE mailbox, where + +* `Address` is the index of the mailbox register, i.e. the relative address in bytes / 4. +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Value` are the values to write to the mailbox + +It is the responsability of the Application to ensure that the remote mailbox is reday to be written +before initiating this command. If an error occurs during the write to the mailbox, an error +response should be returned. + +The responder side automatically triggers the GO bit once all values have been written to the +destination mailbox (if no error occurs). + +The Application is in charge of formatting the payload to ensure that it contains a valid DOE object +(including formatting the header, see [DOE PCIe header](#doe-pcie-header)) + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'WX' | 4 + 4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Address | Device | Role | ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #N-1 | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'wx' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +#### Read Memory + +Read the content of a memory device, where + +* `Address` is the address in bytes of the first 32-bit word +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate](#enumerate-devices)) +* `Count` is the number of 32-bit word to be read. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'RM' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| - | Device | Role | ++---------------+---------------+---------------+---------------+ +| Address | ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'rm' | 4..4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #N-1 | ++---------------+---------------+---------------+---------------+ +``` + +#### Write Memory + +Write a buffer to a memory device + +* `Address` is the address in bytes of the first 32-bit word to be written +* `Role` is the initiator role to use to access the device +* `Device` is the device to access (see [Enumerate Devices](#enumerate-devices)) +* `Value` are the values to write in memory word. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'WM' | 8 + 4*Count | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| - | Device | Role | ++---------------+---------------+---------------+---------------+ +| Address | ++---------------+---------------+---------------+---------------+ +| Value #0 | ++---------------+---------------+---------------+---------------+ +| Value #1 | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| Value #N-1 | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'wm' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Count | ++---------------+---------------+---------------+---------------+ +``` + +#### Resume VM execution + +Resume execution if the VM is currently stopped. + +When VM is started in stod mode `-S`, proxy can be used to configure the VM before kicking off the +vCPUs. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'CX' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'cx' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +#### Quit + +Stop QEMU emulation and return an error code to the caller. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'QT' | 8 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Error code | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'qt' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +This is the last command, as QEMU should exit upon receiving this request. + +#### Enumerate Device Interrupt [enumerate-irq] + +Enumerate can be called by the Application to retrieve the list of interrupt groups of a supported +device. The group in the response can be further used with the [Signal Interrupt API](#signal-interrupt), +[Intercept Interrupts](#intercept-interrupt) and [Release Interrupts](#release-interrupt). + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'IE' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| - | Device | - | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | ++---------------+---------------+---------------+---------------+ +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ie' | 0..36N | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| IRQ count | Group |O| - | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| IRQ count | Group |O| - | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +| .... | ++---------------+---------------+---------------+---------------+ +| IRQ count | Group |O| - | ++---------------+---------------+---------------+---------------+ +| | +| | +| Identifier | +| | +| | ++---------------+---------------+---------------+---------------+ +``` +Reponse contains 0 up to N interrupt groups, each group is described with a 36-byte entry, where: + +* `IRQ count` is the count of the input interrupts for this group, +* `O` is set if IRQ in this group are output interrupts or or not set if they are input interrupts, +* `Group` is the interrupt group identifier identifier. +* `Identifier` defines the interrupt group name + +The count of address spaces can be retrieved from the `LENGTH` field. + +#### Intercept Interrupts [intercept-interrupt] + +Route one or more device output interrupts to the proxy (vs. the internal PLIC) + +* `Device` is the device to access (see [Enumerate Device](#enumerate-devices)) +* `Group` is the IRQ group in the device (see [Enumerate Interrupt](#enumerate-irq)) +* `Interrupt mask` define which interrupts should be released (1 bit per interrupt). The count of + 32-bit interrupt mask word can be retrieved from the header length. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'II' | 8.. | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Group | - | Device | - | ++---------------+---------------+---------------+---------------+ +| | +| Interrupt mask | +| | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ii' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +#### Release Interrupts [release-interrupt] + +Revert any previous interception, reconnecting selected IRQ to their original +destination device. + +* `Device` is the device to access (see [Enumerate Device](#enumerate-devices)) +* `Group` is the IRQ group in the device (see [Enumerate Interrupt](#enumerate-irq)) +* `Interrupt mask` define which interrupts should be released (1 bit per interrupt). The count of + 32-bit interrupt mask word can be retrieved from the header length. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'IR' | 8.. | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Group | - | Device | - | ++---------------+---------------+---------------+---------------+ +| | +| Interrupt mask | +| | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'ir' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +#### Signal Interrupt [signal-interrupt] + +Set or Reset an input interrupt line. + +* `Device` is the device to access (see [Enumerate Device](#enumerate-devices)), +* `Group` the identifier of the IRQ group (see [Enumerate Interrupt](#enumerate-irq)), +* `Interrupt line` the index of the interrupt line to signal within the group. The interrupt line + should range between 0 and the input IRQ count for this group, +* `Level` the new interrupt line level. Usually `1` to assert/set (1) or `0` to deassert/release, + even if any 32-bit value is accepted. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'IS' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| Group | Device | - | ++---------------+---------------+---------------+---------------+ +| Interrupt line | - | ++---------------+---------------+---------------+---------------+ +| Level | ++---------------+---------------+---------------+---------------+ +``` + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'is' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +#### Intercept arbitrary MMIO region [intercept-region] + +It is possible to get intercept access to a memory region. Any intercepted region cannot +be any longer accessed by the remote vCPU. + +Use with care, as it may generate a very high traffic on the communication link. Width of +intercepted location should be kept small. + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'MI' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +|R|W| Priority | - | Stop | - | MSpc | ++---------------+---------------+---------------+---------------+ +| Address | ++---------------+---------------+---------------+---------------+ +| Size | ++---------------+---------------+---------------+---------------+ +``` + +* `R` whether to notify on read access +* `W` whether to notify on write access +* `Priority` is the priority order (increasing order). 0 is reserved. If not sure, use 1. +* `Stop` auto-stop count. If non-zero, only the specified count of notifications are reported, + after which the MMIO location intercepter is automatically discarded. +* `MSpc` is the memory space of the region to select (see [Enumerate Memory Spaces](#enumerate-mr-spaces)) +* `Address` is the byte address of the first byte to intercept in the selected memory space +* `Size` is the width in bytes of the region to intercept + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'mi' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| 0 | Region | - | ++---------------+---------------+---------------+---------------+ +``` + +* `Region` is the new intercepter number that describes the intercepting region + +#### Release intercepted MMIO locations + +##### Request +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'MR' | 4 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +| - | Region | - | ++---------------+---------------+---------------+---------------+ +``` + +* `Region` is the number of the intercepter to release + +##### Response +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| 'mr' | 0 | ++---------------+---------------+---------------+---------------+ +| UID |0| ++---------------+---------------+---------------+---------------+ +``` + +* `Device` is the new device number that describes the intercepting region + +### Interrupt signalling + +Interrupt signalling are messages that never expect a response and that may be sent/received at any +time. Each receiver should be prepared to handle many interrupt messages without any prior +request/command. + +An [intercept interrupt](#intercept-interrupt) command should have been first used to select which +interrupt(s) to receive. + +#### "Wired" Interrupt +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| '^W' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |1| ++---------------+---------------+---------------+---------------+ +| - | Device | - | ++---------------+---------------+---------------+---------------+ +| Channel | Group |O| - | ++---------------+---------------+---------------+---------------+ +| Value | ++---------------+---------------+---------------+---------------+ +``` + +* `Device` that triggered the interrupt +* `Group` which interrupt group has been triggered +* `Channel` which interrupt channel for the group has been triggered +* `Value` the new interrupt value. For binary IRQs, `1` when IRQ is raised, `0` when it is lowered. + +#### MSI Interrupt + +To be defined. + +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| '^M' | 8 | ++---------------+---------------+---------------+---------------+ +| UID |1| ++---------------+---------------+---------------+---------------+ +| - | Device | Role | ++---------------+---------------+---------------+---------------+ +| Value | ++---------------+---------------+---------------+---------------+ +``` + +#### Region Access + +See [Intercept arbitrary MMIO region](#intercept-region) to register a watcher + +``` ++---------------+---------------+---------------+---------------+ +| 0 | 1 | 2 | 3 | +|0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| ++---------------+---------------+---------------+---------------+ +| '^R' | 12 | ++---------------+---------------+---------------+---------------+ +| UID |1| ++---------------+---------------+---------------+---------------+ +|R|W| | Width | - | Region | Role | ++---------------+---------------+---------------+---------------+ +| Address | ++---------------+---------------+---------------+---------------+ +| Value | ++---------------+---------------+---------------+---------------+ +``` + +* `Region` the region watcher identifier, as returned in the interception registration response +* `R` read access +* `W` write access +* `Width` the width in byte of the MMIO access (1/2/4) +* `Address` the absolute address of the MMIO access +* `Value` the value if memory location was written, 0 otherwise diff --git a/docs/opentitan/dtm.md b/docs/opentitan/dtm.md new file mode 100644 index 0000000000000..706dc8d117d04 --- /dev/null +++ b/docs/opentitan/dtm.md @@ -0,0 +1,170 @@ +# `dtm.py` + +`dtm.py` checks that the JTAG/DTM/DM stack is up and running and demonstrates how to use the Debug +Module to access the Ibex core. + +## Usage + +````text +usage: dtm.py [-h] [-S SOCKET] [-t] [-w DELAY] [-l IR_LENGTH] + [--idcode IDCODE] [--dtmcs DTMCS] [--dmi DMI] [-b BASE] [-I] + [-c CSR] [-C CSR_CHECK] [-x] [-X] [-a ADDRESS] [-m {read,write}] + [-s SIZE] [-f FILE] [-D DATA] [-e ELF] [-F] [-v] [-d] + +Debug Transport Module tiny demo + +options: + -h, --help show this help message and exit + +Virtual machine: + -S, --socket SOCKET connection (default tcp:localhost:3335) + -t, --terminate terminate QEMU when done + -w, --idle DELAY stay idle before interacting with DTM + +DMI: + -l, --ir-length IR_LENGTH + bit length of the IR register (default: 5) + --idcode IDCODE define the ID code (default: 1) + --dtmcs DTMCS define an alternative DTMCS register (default: 0x10) + --dmi DMI define an alternative DMI register (default: 0x11) + -b, --base BASE define DMI base address (default: 0x0) + +Info: + -I, --info report JTAG ID code and DTM configuration + -c, --csr CSR read CSR value from hart + -C, --csr-check CSR_CHECK + check CSR value matches + +Actions: + -x, --execute update the PC from a loaded ELF file + -X, --no-exec does not resume hart execution + +Memory: + -a, --address ADDRESS + address of the first byte to access + -m, --mem {read,write} + access memory using System Bus + -s, --size SIZE size in bytes of memory to access + -f, --file FILE file to read/write data for memory access + -D, --data DATA data to write using memory access + -e, --elf ELF load ELF file into memory + -F, --fast-mode do not check system bus status while transferring + +Extras: + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-a` specify the memory address where data is loaded or stored. Useful with the `--mem` option. + See also the `--size` option. Note that only 32-bit aligned addresses are supported for now. + +* `-b` specify the DMI base address for the RISC-V Debug Module + +* `-C` compare a CSR value to the specified value. Requires option `--csr`. + +* `-c` read and report a CSR from the Ibex core. + +* `-D` data to write, useful with `--mem` option in write mode. Mutually exclusive with `--file`. + Data may be specified as an decimal or hexadecimal integer, limited to 32-bit integers. It is also + possible to use `:` followed with a string of hexadecimal nibbles (without 0x prefix). + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-e` specify an ELF32 application file to upload into memory. See also the `--exec` option. + +* `-F` assume System Bus can cope with received data pace. This feature increases transfer data + rate by bypassing SB status check. However it may cause the transfer to fail in case System Bus + becomes busy while data are transferred. + +* `-f` specify the file to read from or write to when option `--mem` is used. Mutually exclusive + with option `--data`. + +* `-I` report the JTAG ID code and the DTM configuration. + +* `-l` specify the length of the TAP instruction register length. + +* `-m ` specify a memory operation to perform. See also `--address`, `--size` and + `--file` options. With `read` operation, if no `--file` is specified, the content of the selected + memory segment is dumped to stdout, with a similar format as the output of `hexdump -C`. If a file + is supplied, the content of the segment is written as binary data into this file. With `write` + operation, `--file` argument is mandatory. The content of the binary file is copied into the + memory, starting at the `--address`. See also the `--elf` option for uploading applications. + +* `-S` specify the socket info to connect to the remote device. + * for QEMU VM JTAG server, TCP and Unix sockets are supported, _i.e._ `tcp:host:port` or + `unix:path/to/socket`. + * For TCP, this should follow the setting of the + `-chardev socket,id=taprbb,host=,port=,...` option for invoking QEMU. + * for Unix sockets, host/port are replaced with the unix socket path specified instead: + `-chardev socket,id=taprbb,path=`. + * for FTDI *232H USB-JTAG interfaces, PyFtdi v0.59+ Python module should be installed, and + pyftdi URL should be used to specify the FTDI device: _e.g._ `ftdi://ftdi:2232/1` + +* `-s` specify the number of bytes to read from or write to memory. Useful with the `--mem` option. + See also the `--address` option. This option may be omitted for the `write` memory operation, in + which case the size of the specified file is used. Note that only sizes multiple of 4 bytes are + supported for now. + +* `-t` send QEMU a request for termination when this script exits. + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +* `-w` pause execution on start up before communication with the remote DTM. This enables QEMU VM + to initialize and boot the guest SW before attempting a communication. It can be repeated once, + the second value being used to delay the termination of the VM when the `-t` option is used. + +* `-X` do not attempt to resume normal execution of the hart once DTM operation have been completed. + This can be useful for example when the QEMU VM is started with `-S` and no application code has + been loaded in memory: once the DTM operations are completed, the default behavior is to resume + the hart execution, would start execution code from the current PC and cause an immediate + exception. The `-x` option can nevertheless be executed, as it is the last action that the script + performs. + +* `-x` execute the loaded ELF application from its entry point. Requires the `--elf` option. + Application is executed even with `-X` defined. + +* `--idcode` specify an alternate IDCODE value + +* `--dmi` specify an alternate address for the DMI register + +* `--dtmcs` specify an alternate address for the DTMCS register + +### Examples + +Running QEMU VM with the `-chardev socket,id=taprbb,host=localhost,port=3335,server=on,wait=off` +option: + +* Retrieve JTAG/DTM/DM information and `mtvec` CSR value + ````sh + ./scripts/opentitan/dtm.py -I -c mtvec + ```` + +* Check that the MISA CSR matches the expected Ibex core value: + ````sh + ./scripts/opentitan/dtm.py -c misa -C 0x401411ad + ```` + +* Load (fast mode) and execute an application + ````sh + ./scripts/opentitan/dtm.py -e .../helloworld -x -F + ```` + +* Dump a memory segment to stdout + ````sh + ./scripts/opentitan/dtm.py -m read -a 0x1000_0080 -s 0x100 + ```` + +* Upload a file into memory and leave the Ibex core halted + ````sh + ./scripts/opentitan/dtm.py -m write -a 0x1000_0000 -f file.dat -X + + ```` + +* Write a 32-bit integer into memory + ````sh + ./scripts/opentitan/dtm.py -m write -a 0x1000_0000 -D 0x1234abcd + # or + ./scripts/opentitan/dtm.py -m write -a 0x1000_0000 -D :1234abcd + ```` diff --git a/docs/opentitan/flashgen.md b/docs/opentitan/flashgen.md new file mode 100644 index 0000000000000..a58b762fdb554 --- /dev/null +++ b/docs/opentitan/flashgen.md @@ -0,0 +1,108 @@ +# `flashgen.py` + +`flashgen.py` populates a QEMU RAW image file which can be loaded by the OpenTitan integrated +flash controller virtual device. + +## Usage + +````text +usage: flashgen.py [-h] [-D] [-a {0,1}] [-s OFFSET] [-x file] [-X elf] + [-b file] [-B elf] [-t OTDESC] [-T] [-U] [-A] [-v] [-d] + flash + +Create/update an OpenTitan backend flash file. + +options: + -h, --help show this help message and exit + +Image: + flash virtual flash file + -D, --discard Discard any previous flash file content + -a, --bank {0,1} flash bank for data (default: 0) + -s, --offset OFFSET offset of the BL0 file (default: 0x10000) + +Files: + -x, --exec file rom extension or application + -X, --exec-elf elf ELF file for rom extension or application, for symbol + tracking (default: auto) + -b, --boot file bootloader 0 file + -B, --boot-elf elf ELF file for bootloader, for symbol tracking (default: + auto) + -t, --otdesc OTDESC OpenTitan style file descriptor, may be repeated + -T, --ignore-time Discard time checking on ELF files + -U, --unsafe-elf Discard sanity checking on ELF files + -A, --accept-invalid Blindly accept invalid input files + +Extra: + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +The (signed) binary files contain no symbols, which can make low-level debugging in QEMU difficult +when using the `-d in_asm` and/or `-d exec` option switches. + +If an ELF file with the same radix as a binary file is located in the directory of the binary +file, or its location is specified in the command line, the path to the ELF file is encoded +into the flash image within a dedicated debug section. + +The OT flash controller emulation, when the stored ELF file exists, attempts to load the symbols +from this ELF file into QEMU disassembler. This enables the QEMU disassembler - used with the +`in_asm`/`exec` QEMU options - to output the name of each executed function as an addition to the +guest PC value. + +It is therefore recommended to ensure the ELF files are located in the same directory as their +matching signed binary files to help with debugging. + +### Arguments + +* `-A` accept any kind of input files, discarding all sanity checks. This option should only be used + to check the behavior of the VM and guest code when invalid files are stored in the embedded flash + device. + +* `-a bank` specify the data partition to store the binary file into, mutually exclusive with `-t`. + +* `-B elf` specify an alternative path to the BL0 ELF file. If not specified, the ELF path file is + reconstructed from the specified binary file (from the same directory). The ELF file is only used + as a hint for QEMU loader. Requires option `-b`, mutually exclusive with `-t`. + +* `-b file` specify the BL0 (signed) binary file to store in the data partition of the flash + image file. The Boot Loader 0 binary file is stored in the data partition at the offset + specified with the -s option, mutually exclusive with `-t`. + +* `-D` discard any flash content that may exist in the QEMU RAW image file. + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-s offset` the offset of the BootLoader image file in the data partition. Note that this offset + may also be hardcoded in the ROM_EXT application. Changing the default offset may cause the + ROM_EXT to fail to load the BL0 application. + +* `-t binfile@address` specify a binary file to store into the data partition of the flash. + This is a compatibility option introduced to support the original `opentitantool image assemble` + syntax. The provided address should be specified in hexadecimal format. Currently, it is not + possible to specify a matching ELF file as the flash debug trailer format is hardcoded to only + support ROM EXT and bootloader binaries in both banks, and does not support arbitrary ELFs. + This option may be repeated to specify multiple files such as the ROM EXT and a bootloader for + example. This option is mutually exclusive with `-b`, `-B`, `-x`, `-X` and `-a`. + +* `-X elf` specify an alternative path to the ROM_EXT ELF file. If not specified, the ELF path file + is reconstructed from the specified binary file (from the same directory). The ELF file is only + used as a hint for QEMU loader. Requires option `-x`, mutually exclusive with `-t`. + +* `-x file` specify the ROM_EXT (signed) binary file or the application to store into the data + partition of the flash image file. Alternatively this file can be any (signed) binary file such as + an OpenTitan test application. Note that if a BL0 binary file is used, the ROM_EXT/test binary + file should be smaller than the selected offset for the bootloader location, mutually exclusive + with `-t`. + +* `-T` tell the script to ignore any time discrepancy between a binary and an ELF file. A binary + file being generated from an ELF file, the former is not expected to be older than the latter. + +* `-U` tell the script to ignore any discrepancies found between a binary file and an ELF file. If + the path to an ELF file is stored in the flash image file, the ELF content is validated against + the binary file. Its code position and size, overall size and entry point should be coherent. + This option implies `-T` option, _i.e._ also discards time comparison between BIN and ELF files. + Note that contents of both files are not compared, as the binary file may be amended after the ELF + file creation. + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. diff --git a/docs/opentitan/gdbreplay.md b/docs/opentitan/gdbreplay.md new file mode 100644 index 0000000000000..71af7867bb1d1 --- /dev/null +++ b/docs/opentitan/gdbreplay.md @@ -0,0 +1,87 @@ +# `gdbreplay.py` + +`gdbreplay.py` uses QEMU log files containing `exec` messages to help a GDB client to replay +execution of a guest application. + +It parses QEMU log files, and creates a GDB server serving GDB remote requests. GDB client can +add breakpoints and follow executed instructions by the guest, stepping or running till a +breakpoint is encountered. It is possible to run execution backward. + +Supported GDB commands: + + * step/step instruction + * reverse step/step instruction + * continue + * hardware breakpoint + * memory dump (code only), requires to provide the application(s) with the help of ELF or binary + files + +QEMU traces do not contain register values so it is not possible to observe any register content or +data. + +## Usage + +````text +usage: gdbreplay.py [-h] [-t LOG] [-e ELF] [-a ADDRESS] [-b BIN] [-g GDB] [-v] [-d] + +QEMU GDB replay. + +options: + -h, --help show this help message and exit + -t LOG, --trace LOG QEMU execution trace log + -e ELF, --elf ELF ELF application + -a ADDRESS, --address ADDRESS + Address to load each specified binary + -b BIN, --bin BIN Binary application + -g GDB, --gdb GDB GDB server (default to localhost:3333) + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-a` specify an address where to load the matching RAW binary application, see `-b` option for + details. May be repeated. + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-b` specify a RAW binary application. May be repeated. For each `-b` argument, there should be + a matching `-a` argument. + +* `-e` specify a ELF application to load. May be repeated. + +* `-g` specify an alternative interface/port to listen for GDB client + +* `-t` specify the QEMU log to parse for `exec`ution traces (see `-d exec` QEMU option) + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +### Examples + +* From one terminal, starts the GDB replay tool + ````sh + # Load two ELFs here, one for the ROM, one for the application to debug + ./scripts/opentitan/gdbreplay.py -vv -t qemu.log \ + -e test_rom_fpga_cw310.elf -e csrng_kat_test_prog_fpga_cw310.elf + ```` + +* From another terminal, starts a regular GDB client + ````sh + riscv64-unknown-elf-gdb + ```` + then + ```` + # Load the ELF file on GDB side so that it knows the symbols + file csrng_kat_test_prog_fpga_cw310.elf + # Connect to gdbreplay + target remote :3333 + # Add a HW breakpoint to the entry function of the test + hb test_main + # Execute till breakpoint + c + ... + # Move execution back to the `test_main` caller + rsi + # Move execution point to the very first instruction + rc + ```` diff --git a/docs/opentitan/gpiodev.md b/docs/opentitan/gpiodev.md new file mode 100644 index 0000000000000..0c160d5245f15 --- /dev/null +++ b/docs/opentitan/gpiodev.md @@ -0,0 +1,78 @@ +# `gpiodev.py` + +`gpiodev.py` acts as a GPIO CharDev backend to record and verify GPIO updates. + +It can be used to run regression tests and verify that the guest emits a predefined sequence of +GPIO updates. + +## Usage + +````text +usage: gpiodev.py [-h] [-p PORT] [-c CHECK] [-r RECORD] [-e END] [-q] [-s] [-t] [-v] [-d] + +GPIO device tiny simulator. + +options: + -h, --help show this help message and exit + -p PORT, --port PORT remote host TCP port (defaults to 8007) + -c CHECK, --check CHECK + input file to check command sequence + -r RECORD, --record RECORD + output file to record command sequence + -e END, --end END emit the specified value to trigger remote exit on last received command + -q, --quit-on-error exit on first error + -s, --single run once: terminate once first remote disconnects + -t, --log-time emit time in log messages + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-p` specify an alternative TCP port to listen for incoming QEMU CharDev socket requests + +* `-c` specify a pre-recorded GPIO backend text file - which only contains ASCII characters and + compare that incoming GPIO requests against the recorded data + +* `-r` specify a file to record incoming GPIO requests + +* `-e` emit a pre-defined GPIO input command - sent to the QEMU GPIO CharDev backend - that may be + recognized by the QEMU guest code as a special marker to end a test sequence. Requires the _check_ + option for detecting the last expected GPIO request. + +* `-q` close the QEMU socket connection on first error or mismatched GPIO request when used with + the _check_ option. + +* `-s` quite the script on the first QEMU socket disconnection. Default is to listen for a new QEMU + CharDev socket connection, restarting from a fresh state. + +* `-t` add time to log messages + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +### Exit Status + +This script returns 0 if no error has been detected, or 1 if an error has been detected or the +GPIO command stream has not been validated against the check file if any. + +### Examples + +With the following examples: + +`-chardev socket,id=gpio,host=localhost,port=8007 -global ot-gpio-$OTMACHINE.chardev=gpio` has been +added to the QEMU command line to connect the GPIO backend to the incoming socket opened from the +script. See the [GPIO documentation](ot_gpio.md) for details and the role of the `OTMACHINE` +environment variable. + +* Record a GPIO request sequence + ````sh + ./scripts/opentitan/gpiodev.py -vv -r gpio.txt -s + ```` + +* Check a GPIO request sequence against a previously record one, then triggers a VM guest app + triggered termination by setting GPIO 31 to a high level. + ````sh + ./scripts/opentitan/gpiodev.py -vv -c gpio.txt -s -e 0x8000_0000 + ```` diff --git a/docs/opentitan/i2c_host_proxy.md b/docs/opentitan/i2c_host_proxy.md new file mode 100644 index 0000000000000..8d100e33d400b --- /dev/null +++ b/docs/opentitan/i2c_host_proxy.md @@ -0,0 +1,52 @@ +# OpenTitan I2C Host Proxy + +The `ot-i2c-host-proxy` device provides a way to execute I2C transactions with QEMU I2C bus devices +through an externally driven `chardev` interface. + +The device can perform read or write transactions with bus devices and is intended to be used to +drive the Opentitan I2C device Target mode, though it can be used to interact with other devices on +the QEMU I2C buses. + +## Configuration + +A chardev and proxy device can be created in QEMU with the following arguments: + +`-chardev pty,i2cN -device ot-i2c-host-proxy,bus=,chardev=i2cN` + +Where `bus` is any of the system's I2C buses. On Earl Grey for example, these are `ot-i2c0`, +`ot-i2c1`, and `ot-i2c2`. + +## Protocol + +The protocol over the chardev mirrors the I2C specification closely. + +Before each transaction, the protocol version must be sent. This is sent as an `i` byte (for I2C), +followed by the version number byte (currently 1). The device will respond with an ACK byte +(see below) if the version matches the implementation, and a NACK byte otherwise. + +A start and repeated start condition is signalled with an `S` byte, followed by a byte containing +the 7-bit target address of the transaction and the read/write bit as the least significant bit +(0 indicates a write transfer, 1 indicates a read transfer). + +On a repeated start condition, the I2C target address of the first transfer will be used, and the +provided address is ignored (transfer direction can be changed). This is a limitation of QEMU. + +When a read transfer is active, a `R` byte can be sent to read a byte of data from the target I2C +device. + +When a write transfer is active, a `W` byte, followed by a data byte, can be sent to write that +byte to the target I2C device. + +A stop condition to end the transaction is signalled with a `P` byte. + +Following a start/repeated start condition and the address byte, as well as after every byte +written during a write transfer, an ACK is signalled with a `.` byte, and a NACK is signalled with +a `!` byte. If the start of a transfer is NACKed, the transaction should be terminated with a stop +condition. + +On a parser error, a `x` byte will be returned, and the parser will not accept any more command +bytes until reset. + +The implementation will throttle processing of written bytes to allow control to return to the +vCPU, so that OT I2C may process the current transaction and prepare response bytes for upcoming +reads. diff --git a/docs/opentitan/ibex_hart.md b/docs/opentitan/ibex_hart.md new file mode 100644 index 0000000000000..ec5101166cbff --- /dev/null +++ b/docs/opentitan/ibex_hart.md @@ -0,0 +1,30 @@ +# IBEX Hart + +## Supported features + +* `RV32I` v2.1 Base Integer Instruction Set with `B` (`Zba`, `Zbb`, `Zbc` and `Zbs`) `C`, `M` + extensions +* `Zicsr` and `Zifencei` extensions +* `Smepmp` extension (ePMP) +* `Zbr` v0.93 unratified ISA extension (crc32 instructions) + +## Unsupported features + +* Extensions not defined in RISC-V standard and/or not ratified are not supported (except `Zbr`) + * `Zbe`, `Zbf`, `Zbp` and `Zbt` +* Ibex NMI +* custom CSRs: `cpuctrlsts`, `secureseed` +* `mret` extension (double fault management) + +## Useful options + +* `-icount 6` reduces the execution speed of the vCPU (Ibex core) to 1GHz >> 6, _i.e._ ~15MHz, + which should roughly match the expected speed of the Ibex core running on the CW310 FPGA, which + is set to 10 MHz. This option is very useful/mandatory to run many OpenTitan tests that rely on + time or CPU cycle to validate features. Using `-icount` option slows down execution speed though, + so it is not recommended to use it when the main goal is to develop SW to run on the virtual + machine. An alternative is to use `-icount shift=auto`, which offers fastest emulation execution, + while preserving an accurate ratio between the vCPU clock and the virtual devices. + +* `-cpu lowrisc-ibex,x-zbr=false` can be used to force disable the Zbr experimental-and-deprecated + RISC-V bitmap extension for CRC32 extension. diff --git a/docs/opentitan/ibexdemo.md b/docs/opentitan/ibexdemo.md new file mode 100644 index 0000000000000..68911ef8d1fac --- /dev/null +++ b/docs/opentitan/ibexdemo.md @@ -0,0 +1,22 @@ +# IbexDemo on Arty A7 + +Ibex Demo is a very lightweight platform that demonstrate the Ibex core features. + +* Hello Word application +````sh +qemu-system-riscv32 -M ibexdemo -nographic -kernel .../hello_world/demo +```` + +* Mandelbrot demo +````sh +qemu-system-riscv32 -M ibexdemo -display -kernel .../demo/lcd_st7735/lcd_st7735 +```` + +## Useful execution options + +#### vCPU + +* `-icount N` reduces the execution speed of the vCPU (Ibex core) to 1GHz >> N + +* `-cpu lowrisc-ibex,x-zbr=true` can be used to force enable (IbexDemo platform) the Zbr + experimental-and-deprecated RISC-V bitmap extension for CRC32 extension. diff --git a/docs/opentitan/index.md b/docs/opentitan/index.md new file mode 100644 index 0000000000000..3da481270c7c4 --- /dev/null +++ b/docs/opentitan/index.md @@ -0,0 +1,41 @@ +# Ibex SoC emulation + +## Requirements + +1. A native toolchain for C and Rust +2. Ninja build tool + +Note: never tested on Windows hosts. + +## Building + +````sh +mkdir build +cd build +../configure --target-list=riscv32-softmmu --without-default-features --enable-tcg \ + --enable-tools --enable-trace-backends=log \ + [--enable-gtk --enable-pixman | --enable-cocoa] +ninja +ninja qemu-img +```` + +* `--enable-gtk --enable-pixman` and `--enable-cocoa` are only useful when using a graphical + display, such as the IbexDemo platform. It is mosly useless with the OpenTitan platform. + + * `--enable-gtk --enable-pixman` should be used on Linux hosts + * `--enable-cocoa` should be used on macOS hosts + +* `--extra-cflags=-Wno-deprecated-declarations` and + `--extra-ldflags=-Wl,-no_warn_duplicate_libraries` may be required to build on recent releases of + macOS (QEMU issues which are not related to the OpenTitan port) + +### Useful build options + + * `--enable-debug` + * `--enable-sanitizers` + +## Supported platforms + + * [IbexDemo](ibexdemo.md) built for Digilent Arty7 board + * [Darjeeling](ot_darjeeling.md) build for CW310 "Bergen" board + * [EarlGrey](ot_earlgrey.md) build for CW310 "Bergen" board diff --git a/docs/opentitan/jtag-dm.md b/docs/opentitan/jtag-dm.md new file mode 100644 index 0000000000000..a5636edc296b0 --- /dev/null +++ b/docs/opentitan/jtag-dm.md @@ -0,0 +1,157 @@ +# JTAG and RISC-V Debug Module support for OpenTitan + +RISC-V Debug Module is implemented as an alternative to the default QEMU GDB server. + +It can be used when low-level features are required, such as prototyping JTAG manufacturing and +provisioning software development, or emulating JTAG Debug Authentication. + +This initial implementation of the RISC-V Debug Module and Pulp DM supports the following features: + +- Ibex core debugging (RV32 only); not tested with multiple harts +- system bus memory access: read and write guest memory +- guest code debugging +- single stepping +- HW breakpoints +- HW watchpoints + +## Communicating with RISC-V DM through a JTAG connection + +In QEMU machines for OpenTitan, any Debug Module can register on the Debug Transport Module, which +dispatches requests to Debug Module depending on the received DMI address. + +See also [JTAG mailbox](jtagmbx.md) and [Life Controller](lc_ctrl_dmi.md) for other Debug Modules. + +``` ++--------------------------+ +| Host (OpenOCD or Python) | ++--------------------------+ + | + | TCP connection ("bitbang mode") + | ++-----|-----------------------------------------------------------------------------------+ +| | QEMU | +| v +---------+ | +| +-------------+ +-----+ +-----------+ | PULP-DM | +------+ | +| | JTAG server |---->| DTM |---->| RISC-V DM |<---->+ ------- +<=======>| Hart | | +| +-------------+ +-----+ +-----------+ | ROM/RAM | || +------+ | +| || +---------+ || | +| || || +--------------+ | +| ================================>| I/O, RAM, ...| | +| +--------------+ | ++-----------------------------------------------------------------------------------------+ +``` + +### Remote bitbang protocol + +The JTAG server supports the Remote Bitbang Protocol which is compatible with other tools such as +Spike and [OpenOCD](https://github.com/riscv/riscv-openocd). + +QEMU should be started with an option such as: +`-chardev socket,id=taprbb,host=localhost,port=3335,server=on,wait=off` so that the JTAG server is +instantiated and listens for incoming connection on TCP port 3335. + +#### Remote termination feature + +The remote Remote Bitbang Protocol supports a "_quit_" feature which enables the remote client to +trigger the end of execution of the QEMU VM. This feature can be useful to run automated tests for +example. + +It is nevertheless possible to disable this feature and ignore the remote exit request so that +multiple JTAG sessions can be run without terminating the QEMU VM. + +To disable this feature, use the `quit` option: `-global tap-ctrl-rbb,quit=off`. + +#### Implementation + +* JTAG server is implemented with `jtag/jtag_bitbang.c` +* DTM is implemented with `hw/riscv/dtm.c` +* RISC-V DM is implemented with `hw/riscv/dm.c` +* Pulp-DM is implemented with `hw/misc/pulp_rv_dm.c` + +See also other supported DM modules on OpenTitan: + +* [JTAG mailbox DMI](jtagmbx.md) +* [LifeCycle DMI](lc_ctrl_dmi.md) + +## Communicating with JTAG server using OpenOCD + +OpenOCD running on a host can connect to the embedded JTAG server, using a configuration script such +as + +```tcl +adapter driver remote_bitbang +remote_bitbang host localhost +remote_bitbang port 3335 + +transport select jtag + +set _CHIPNAME riscv +# part 1, ver 0, lowRISC; actual TAP id depends on the QEMU machine +set _CPUTAPID 0x00011cdf + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +# Hart debug base also depends on the QEMU machine +set DM_BASE 0x00 + +target create $_CHIPNAME riscv -chain-position $_TARGETNAME rtos hwthread -dbgbase $DM_BASE +``` + +## Connecting GDB to OpenOCD + +In another terminal, `riscv{32,64}-unknown-elf-gdb` can be used to connect to OpenOCD: + +``` +# 64-bit version support 32-bit targets +riscv64-unknown-elf-gdb +``` + +A basic `$HOME/.gdbinit` as the following should connect GDB to the running OpenOCD instance: +``` +target remote :3333 +``` + +## Communicating with JTAG server using Python + +`scripts/opentitan/ot` directory contains Python modules that provide several APIs to test the +JTAG/DTM/DM stack. + +A demo application is available from [`scripts/opentitan/dtm.py`](dtm.md) that can report basic +information about this stack and demonstrate how to use the Debug Module to access the Ibex core. + +The [`scripts/opentitan/otpdm.py`](otpdm.md) also use the same stack to access the cells of the OTP +controller. + +### Troubleshooting [#troubleshooting] + +A common issue with initial JTAG configuration is to use the wrong Instruction Register length. +The IR length depends on the actual implementation of the TAP controller and therefore may be +different across HW implementations, here across OpenTitan instantiations. + +Unfortunately, there is no reliable way to automatically detect the IR length, this needs to be +a setting that should be provided to the JTAG tool. Scripts in `scripts/opentitan` use the `-l` / +`--ir-length` option to specify the IR length. The default value may be obtained with the `-h` +option, which is IR length = 5 bits for default EarlGrey and Darjeeling machines. + +Whenever the wrong IR length is specified, or the default IR length is used with a HW/VM machine +that uses a non-default length, the first instruction that is stored in the TAP instruction register +is misinterpreted, which may cause different errors with the same root cause: a wrong IR length +setting. + +It is recommended to query the DMI address bits with for example [`scripts/opentitan/dtm.py`](dtm.md) +which is a basic command that needs a valid IR length setting to complete. Use `dtm.py -I` to query +some low-level information from the remote peer. + +It should report something like: +```` +IDCODE: 0x11cdf +DTM: v0.13, 12 bits +```` + +* If the DTM bit count is stuck to 0, the IR length is likely wrong, +* If an error message such as `Invalid reported address bits` is returned, the IR length is likely + wrong. + +Another common issue is to use a machine with multiple Debug Modules but fail to specify its base +address. The default DMI base address is always `0x0`. Use `-b` / `--base` option to select the +proper Debug Module base address. diff --git a/docs/opentitan/jtagmbx.md b/docs/opentitan/jtagmbx.md new file mode 100644 index 0000000000000..7501140834f87 --- /dev/null +++ b/docs/opentitan/jtagmbx.md @@ -0,0 +1,244 @@ +# Darjeeling JTAG Mailbox + +The JTAG mailbox host side (responder) is connected to the private OT address space, while the +system side (requester) is connected to a Debug Tile Link bus. + +## Communicating with the JTAG Mailbox through a JTAG connection + +In QEMU, a bridge between the Debug Transport Module (DTM) and the JTAG Mailbox is implemented +as Debug Module bridge. + +``` ++----------------+ +| Host (OpenOCD) | ++----------------+ + | + | TCP connection ("bitbang mode") + | ++-----|-----------------------------------------------------------------------------------+ +| v | +| +-------------+ +-----+ +----------+ +---------+ +------+ | +| | JTAG server |---->| DTM |---->| ot_dm_tl |====D====|S> MBX > 2) + +# See ot.mailbox.sysmbox.SysMbox for mailbox communication API +```` + +## Communicating with JTAG server using OpenOCD + +It is possible from OpenOCD running a host to connect to the embedded JTAG server using the +`remote_bitbang` protocol, using a configuration script such as + +```tcl +adapter driver remote_bitbang +remote_bitbang host localhost +remote_bitbang port 3335 + +transport select jtag + +set _CHIPNAME riscv +# part 1, ver 0, lowRISC; actual TAP id depends on the QEMU machine +set _CPUTAPID 0x00011cdf + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +# Hart debug base also depends on the QEMU machine +set DM_BASE 0x00 + +target create $_CHIPNAME riscv -chain-position $_TARGETNAME rtos hwthread -dbgbase $DM_BASE +``` + +From here, it is possible reach the JTAG dmi through the DMI device: + +```tcl +# Mailbox system register addresses +set MBX_SYS_BASE 0x200 + +set SYS_INTR_MSG_ADDR $($MBX_SYS_BASE + 0x0) +set SYS_INTR_MSG_DATA $($MBX_SYS_BASE + 0x1) +set SYS_CONTROL $($MBX_SYS_BASE + 0x2) +set SYS_STATUS $($MBX_SYS_BASE + 0x3) +set SYS_WRITE_DATA $($MBX_SYS_BASE + 0x4) +set SYS_READ_DATA $($MBX_SYS_BASE + 0x5) + +# Mailbox system register bits +set SYS_CONTROL_ABORT 0x1 +set SYS_CONTROL_SYS_INT_EN 0x2 +set SYS_CONTROL_GO 0x80000000 + +set SYS_STATUS_BUSY 0x1 +set SYS_STATUS_INT 0x2 +set SYS_STATUS_ERROR 0x4 +set SYS_STATUS_READY 0x80000000 + +# read the STATUS register +dmi_read $SYS_STATUS + +# write the GO bit of the control register +dmi_write $SYS_CONTROL $SYS_CONTROL_GO +``` + +Unfortunalely the current version of OpenOCD (v0.12+) does not support a JTAG-DMI communication if +no RISC-V DM module is connected to the DMI device, _i.e._ + +``` ++----------------+ +| Host (OpenOCD) | ++----------------+ + | + | TCP connection ("bitbang mode") + | ++-----|-----------------------------------------------------------------------------------+ +| v | +| +-------------+ +-----+ +----------+ +---------+ +------+ | +| | JTAG server |---->| DTM |-+-->| ot_dm_tl |====D====|S> MBX | DM |---->| PulpDM |============== | +| +----+ +---------+ | +| | ROM/RAM | | +| +---------+ | +| | +| QEMU| ++-----------------------------------------------------------------------------------------+ +``` + +If no RISC-V compatible DM is detected at `$DM_BASE`, OpenOCD enters an infinite loop seeking a +valid DM module. + +DM / PulpDM should be part of an upcoming delivery. Meanwhile it is required to tweak OpenOCD so +that it accepts staying connected to the DMI even if it cannot locate a valud DM: + +```diff +diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c +index 2ab28deac..0e84418d9 100644 +--- a/src/target/riscv/riscv-013.c ++++ b/src/target/riscv/riscv-013.c +@@ -1882,6 +1882,8 @@ static int examine(struct target *target) + return ERROR_FAIL; + } + ++ target->state = TARGET_UNAVAILABLE; ++ return ERROR_OK; + /* Reset the Debug Module. */ + dm013_info_t *dm = get_dm(target); + if (!dm) +diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c +index 5bae01d5f..786f2520a 100644 +--- a/src/target/riscv/riscv.c ++++ b/src/target/riscv/riscv.c +@@ -3167,6 +3167,8 @@ int riscv_openocd_poll(struct target *target) + { + LOG_TARGET_DEBUG_IO(target, "Polling all harts."); + ++ return ERROR_OK; ++ + struct list_head *targets; + + LIST_HEAD(single_target_list); +``` + +## Communicating with the JTAG Mailbox through a DevProxy connection + +DevProxy is a communication tool that enables to control QEMU devices from a remote host, over a +TCP connection. + +It can access QEMU `SysBusDevice` through their `MemoryRegion` API, intercepts or generate IRQs on +those devices, intercepts accesses to plain RAM region and read or modify their content. See the +[devproxy.md](devproxy.md) document for information about the DevProxy communication protocol and +supported features. + +The `devproxy.py` Python module implements the DevProxy protocol and can be used on a host to +remotely control selected devices in the QEMU machine. It includes support for the Mailbox devices +for both the Host and System interfaces. + +``` ++--------------------+ +| Host (Python, ...) | ++--------------------+ + | + | TCP connection + | ++-----|-----------------------------------------+ +| v | +| +-----------------+ | +| | DevProxy server |------ | +| +-----------------+ | | +| | | | +| CTN Private | +| | | | +| | +---------+ | | +| +--->|S> MBX |S> MBX | MBX RAM | | +| | +---------+ | +---------+ | +| +--->|S> MBX | RAM | | +| | | +-----+ | +| ... | | +| | +---------+ | | +| +--->| IPI | | | +| | +---------+ | | +| ... ... | +| QEMU| ++-----------------------------------------------+ +``` + +QEMU should be started with a option pair to enable communication with the DevProxy server: +* `-chardev socket,id=devproxy,host=localhost,port=8003,server=on,wait=off +* `-global ot-dev_proxy.chardev=devproxy` + +Subsequently, a Python script importing the `devproxy.py` module can be used to communicate with +the JTAG mailbox. + +Note: `devproxy.py` needs to be found within the Python path, using for example +```sh +export PYTHONPATH=${QEMU_SOURCE_PATH}/scripts/opentitan +``` + +### Troubleshooting + +See the [Troubleshooting](jtag-dm.md#troubleshooting) section for details. diff --git a/docs/opentitan/keymgr-dpe.md b/docs/opentitan/keymgr-dpe.md new file mode 100644 index 0000000000000..4fed6eb529acc --- /dev/null +++ b/docs/opentitan/keymgr-dpe.md @@ -0,0 +1,244 @@ +# `keymgr-dpe.py` + +`keymgr-dpe.py` is a helper tool that can be used to generate or verify Key Manager DPE keys, using +the same parameters as the QEMU machine and the real HW, for debugging purposes. + +## Usage + +````text +usage: keymgr-dpe.py [-h] -c CFG -j HJSON [-l SV] [-m VMEM] [-R RAW] [-r ROM] + [-e BITS] [-z SIZE] [-v] [-d] + {generate,execute,verify} ... + +QEMU OT tool to generate Key Manager DPE keys. + +positional arguments: + {generate,execute,verify} + Execution mode + generate generate a key + execute execute sqeuence + verify verify execution log + +options: + -h, --help show this help message and exit + +Files: + -c, --config CFG input QEMU OT config file + -j, --otp-map HJSON input OTP controller memory map file + -l, --lifecycle SV input lifecycle system verilog file + -m, --vmem VMEM input VMEM file + -R, --raw RAW input QEMU OTP raw image file + -r, --rom ROM input ROM image file, may be repeated + +Parameters: + -e, --ecc BITS ECC bit count (default: 6) + -z, --rom-size SIZE ROM image size in bytes, may be repeated + +Extras: + -v, --verbose increase verbosity + -d, --debug enable debug mode +```` + +### Arguments + +* `-c` QEMU OT config file, which can be generated with the [`cfggen.py`](cfggen.md) script. + See also predefined files from the `docs/config/opentitan` directory. + +* `-d` only useful to debug the script, reports any Python traceback to the standard error stream. + +* `-e` specify how many bits are used in the HEX and VMEM files to store ECC information. + +* `-j` specify the path to the HJSON OTP controller map file, usually stored in OT + `hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson`, required to decode any OTP file. + +* `-l` specify the life cycle system verilog file that defines the encoding of the life cycle + states, required to decode the Life Cycle state, which is stored in the OTP file. + +* `-m` specify the input VMEM file that contains the OTP fuse content, mutually exclusive with `-R` + +* `-r` specify the path to a ROM file. This option should be repeated for each ROM file. The ROM + file may either be a ELF or a binary file, in which case the same count of `-z` ROM size option, + specified in the same order as the ROM file, is required. When such a ROM file format is used, the + ROM digest is computed from the ROM file content. The ROM file can also be specified a `HEX` + scrambled file, in which case the digest is read from the file itself. `VMEM` format is not yet + supported. + +* `-R` specify the path to the QEMU OTP RAW image file, which can be generated with the + [`otptool.py`](otptool.md), mutually exclusive with option `-m`. + +* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose. + +* `-z` specify the size of each ROM file in bytes. It should be repeated for each specified ROM + file, except if all ROM files are specified as HEX formatted files. It can either be specified as + an integer or an integer with an SI-suffix (Ki, Mi), such as `-z 64Ki`. + +Depending on the execution mode, the following options are available: + +## Generate options + +This mode can be used to generate a single output key, which can be stored into an output file. + +``` +usage: keymgr-dpe.py [-h] -c CFG -j HJSON [-l SV] [-m VMEM] [-R RAW] [-r ROM] + [-e BITS] [-z SIZE] [-v] [-d] + {generate,execute,verify} ... + +QEMU OT tool to generate Key Manager DPE keys. + +positional arguments: + {generate,execute,verify} + Execution mode + generate generate a key + execute execute sequence + verify verify execution log + +options: + -h, --help show this help message and exit + +Files: + -c, --config CFG input QEMU OT config file + -j, --otp-map HJSON input OTP controller memory map file + -l, --lifecycle SV input lifecycle system verilog file + -m, --vmem VMEM input VMEM file + -R, --raw RAW input QEMU OTP raw image file + -r, --rom ROM input ROM image file, may be repeated + +Parameters: + -e, --ecc BITS ECC bit count (default: 6) + -z, --rom-size SIZE ROM image size in bytes, may be repeated + +Extras: + -v, --verbose increase verbosity + -d, --debug enable debug mode +``` + +### Arguments + +* `-b` specify the software binding for an _advance_ stage of the key manager. It should be repeated + for each new stage to execute. Note the first stage does not require a software binding value and + is always executed. The expected format is a hexa-decimal encoded string (without 0x prefix). It + is automatically padded with zero bytes up to the maximum software binding size supported by the + HW. + +* `-c` specify a QEMU [configuration file](otcfg.md) from which to read all the cryptographic + constants. See the [`cfggen.py`](cfggen.md) tool to generate such a file. + +* `-g` specify the kind of generation to perform. If not specified, it is inferred from the `-t` + target option. + +* `-j` specify the path to the HJSON OTP controller map file, usually named `otp_ctrl_mmap.hjson`. + +* `-l` specify the life cycle system verilog file, usually named `lc_ctrl_state_pkg.sv`, that + defines the encoding of the life cycle states. + +* `-k` the version of the key to generate + +* `-o` specify the output file path for the generated key + +* `-R` when specified, the Key Manager output slot is encoded as a Rust constant, whose + name is specified with this option. Default is to print the output slot in plain text. + +* `-s` specify the salt for the _generate_ stage of the key manager. The expected format is a hexa- + decimal encoded string (without 0x prefix). It is automatically padded with zero bytes up to the + maximum salt size supported by the HW. + +* `-t` specify the destination for the _generate_ stage. + +### Examples + +````sh +keymgr-dpe.py -vv -c docs/config/opentitan/darjeeling.cfg \ + -j otp_ctrl_mmap.hjson -m img_otp.vmem -l lc_ctrl_state_pkg.sv \ + -r base_rom.39.scr.hex -r second_rom.39.scr.hex -b 0 -b 0 -t AES -k 0 -s 0 +```` + +````sh +keymgr-dpe.py -vv -c docs/config/opentitan/darjeeling.cfg \ + -j otp_ctrl_mmap.hjson -m img_otp.vmem -l lc_ctrl_state_pkg.sv \ + -r rom0.elf -r keymgr-dpe-basic-test -z 64Ki -z 32Ki -t SW -k 0 -s 0 +```` + +## Execute options [execute-options] + +This mode can be used to execute a sequence of steps, with multiple key generations. + +It requires an input file containing the sequence of steps to execute, which follows the INI file +format. Each section in the file represents a step in the sequence, and the options within each +section specify the parameters for that step. + +``` +usage: keymgr-dpe.py execute [-h] -s INI + +options: + -h, --help show this help message and exit + -s, --sequence INI execution sequence definition +``` + +### Arguments + +* `-s` specify an INI-like configuration file containing the sequence of steps to execute + + Typical input file: + + ````ini + [step_1] + mode = initialize + dst = 0 + + [step_2] + mode = advance + binding = [0] + src = 0 + dst = 1 + allow_child = true + exportable = true + retain_parent = true + + [step_3] + mode = generate + src = 1 + dst = otbn + key_version = 0 + salt = "[49379059ff52399275666880c0e44716999612df80f1a9de481eae4045e2c7f0]" + + [step_4] + mode = generate + src = 1 + dst = none + key_version = 0 + salt = "[49379059ff52399275666880c0e44716999612df80f1a9de481eae4045e2c7f0]" + ```` + +## Verify options + +This mode can be used to verify the execution of a unit test, which is expected to print out the +input parameters it sends to the KeyManger DPE and the output key which is generated by the latter. + +Note that as the generated sideloaded key cannot usually be accessed by the Ibex core, the following +tricks are used: + +* for AES sideloaded key, the AES key is used to encrypt a zeroed plaintext, and the verification is +performed on the ciphertext +* for KMAC sideloaded key, the KMAC key is used to perform a hash on a zeroed input buffer, and the +verification is performed on the resulting hash value. +* for OTBN sideloaded key, the OTBN key is read by the OTBN core and replicated into its data +memory, which is then read back by the Ibex core. In this cas, the direct key is verified. + +``` +usage: keymgr-dpe.py verify [-h] -l LOG + +options: + -h, --help show this help message and exit + -l, --exec-log LOG execution log to verify +``` + +### Arguments + +* `-l` specify the execution log to verify. The execution log is expected to contain the output of + a test that has run on the OpenTitan platform. It should emit a syntax identical to the format + described in the [Execute options](#execute-options) section, _i.e._ an INI-like syntax. To + distinguish INI syntax from any other log output, each line of interest should be prefixed with a + `T> ` marker. + + [`pyot.py`](pyot.md) script may be used to generate the log file, see `--log-file` option or the + `log_file` test parameter. diff --git a/docs/opentitan/lc_ctrl_dmi.md b/docs/opentitan/lc_ctrl_dmi.md new file mode 100644 index 0000000000000..d30137aa4febc --- /dev/null +++ b/docs/opentitan/lc_ctrl_dmi.md @@ -0,0 +1,70 @@ +# LifeCycle Controller over DTM + +## Communicating with the Life Cycle Controller through a JTAG connection + +In QEMU, a bridge between the Debug Transport Module (DTM) and the Life Cycle Controller is +implemented as a Debug Module bridge. + +``` ++----------------+ +| Host (OpenOCD) | ++----------------+ + | + | TCP connection ("bitbang mode") + | ++-----|-----------------------------------------------------------------------------------+ +| v | +| +-------------+ +-----+ +----------+ +---------+ +------+ | +| | JTAG server |---->| DTM |---->| ot_dm_tl |====D====| LC Ctrl |====P====| Hart | | +| +-------------+ +-----+ +----------+ +---------+ +------+ | +| QEMU| ++-----------------------------------------------------------------------------------------+ +``` + +where: + `P` is the private OT bus + `D` is the debug bus + +In Darjeeling, a top-level debug crossbar multiplexes debug access to several devices, including +the Life Cycle Controller. Therefore, there is a single DTM and Debug Module bridge. In the QEMU +implementation of Darjeeling we thus have a single JTAG server, reachable over the `taprbb` +character device. For that machine, QEMU should be started with an option such as: +`-chardev socket,id=taprbb,host=localhost,port=3335,server=on,wait=off` so that the JTAG server is +instantiated and listens for incoming connections on TCP port 3335. + +In Earlgrey, we have multiple JTAG TAPs, including one for the Life Cycle Controller. The Life Cycle +Controller instantiates its own DTM and Debug Module bridge. Therefore, in the QEMU implementation +of Earlgrey we use a separate character device for that JTAG server, named instead `taprbb-lc-ctrl`. + +## Communicating with JTAG server and Life Cycle controller using Python + +OpenTitan implementation provides JTAG/DTM/DMI/Mailbox stack available as Python modules: + +* jtag/tap module is available from `python/qemu/jtag` directory +* dtm/dmi and jtag mailbox modules are available from `scripts/opentitan` directory + +Python snippet to create a communication channel with the VM JTAG mailbox: + +````py +from socket import create_connection +from jtag.bitbang import JtagBitbangController +from jtag.jtag import JtagEngine +from ot.dtm import DebugTransportModule +from ot.lc_ctrl.lcdmi import LifeCycleController + +sock = create_connection(('localhost', 3335), timeout=1.0) +ctrl = JtagBitbangController(sock) +eng = JtagEngine(ctrl) +ctrl.tap_reset(True) +dtm = DebugTransportModule(eng, 5) # IR length depends on the actual machine +version, abits = dtm['dtmcs'].dmi_version, dtm['dtmcs'].abits +print(f'DTM: v{version[0]}.{version[1]}, {abits} bits') +dtm['dtmcs'].dmireset() +lc_ctrl = LifeCycleController(dtm, 0x3000 >> 2) + +# See LifeCycleController for LC controller communication API +```` + +### Troubleshooting + +See the [Troubleshooting](jtag-dm.md#troubleshooting) section for details. diff --git a/docs/opentitan/ot_aes.md b/docs/opentitan/ot_aes.md new file mode 100644 index 0000000000000..16ad9a48f0b88 --- /dev/null +++ b/docs/opentitan/ot_aes.md @@ -0,0 +1,7 @@ +# OpenTitan AES + +* `-global ot-aes.fast-mode=false` can be used to better emulate AES HW IP, as some OT tests expect + the Ibex core to execute while the HW is performing AES rounds. Without this option, the virtual + HW may only give back execution to the vCPU once the AES operation is complete, which make those + OT tests to fail. Disabling fast mode better emulates the HW to the expense of higher AES latency + and throughput. diff --git a/docs/opentitan/ot_darjeeling.md b/docs/opentitan/ot_darjeeling.md new file mode 100644 index 0000000000000..c3980084ade24 --- /dev/null +++ b/docs/opentitan/ot_darjeeling.md @@ -0,0 +1,147 @@ +# Darjeeling + +## Supported version + +Please check out the `ot_darjeeling.c` file header. + +## Supported devices + +### Near feature-complete devices + +* [AES](ot_aes.md) +* Alert controller + * ping mechanism is not supported +* AON Timer +* CSRNG +* EDN +* HMAC +* [IBEX CPU](ibex_cpu.md) +* [JTAG](jtag-dm.md) (compatible with OpenOCD/Spike "remote bitbang" protocol) +* Key manager DPE + * Almost feature complete + * Missing entropy reseeding, and support for KMAC masking (when available) +* Mailbox + * [JTAG mailbox](jtagmbx.md) can be accessed through JTAG using a DM-TL bridge +* [OTBN](ot_otbn.md) +* [OTP controller](ot_otp.md) + * read and write features are supported, + * Present scrambling is supported with digest checks, + * ECC (detection and correction) is supported + * zero-ization is not yet supported +* [RISC-V Debug Module](jtag-dm.md) and Pulp Debug Module +* [ROM controller](ot_rom_ctrl.md) +* [SoC debug controller documentation](ot_soc_dbg_ctrl.md) +* SPI data flash (from QEMU upstream w/ fixes) +* [SPI Host controller](ot_spi_host.md) + * HW bus config is ignored (SPI mode, speed, ...) +* [SPI Device](ot_spi_device.md) +* Timer +* [UART](ot_uart.md) + * missing RX timeout, TX break not supported + * bitrate is not paced vs. selected baurate + +### Partially implemented devices + +Devices in this group implement subset(s) of the real HW. + +* Clock Manager + * Runtime-configurable device, through properties + * Manage clock dividers, groups, hints, software configurable clocks + * Propagate clock signals from source (AST, ...) to devices + * Hint management and measurement are not implemented +* DMA + * Only memory-to-memory transfers (inc. hashing) are supported, Handshake modes are not supported +* Entropy Src + * test/health features are not supported +* [GPIO](ot_gpio.md) + * A CharDev backend can be used to get GPIO outputs and update GPIO inputs +* [I2C controller](ot_i2c.md) + * Supports only one target mode address - ADDRESS1 and MASK1 are not implemented + * Timing features are not implemented + * Loopback mode is not implemented +* [Ibex wrapper](ot_ibex_wrapper.md) + * random source (connected to CSR), FPGA version, virtual remapper, fetch enable can be controlled + from Power Manager +* KMAC + * Masking is not supported +* Lifecycle controller + * [LC controller](lc_ctrl_dmi.md) can be accessed through JTAG using a DM-TL bridge + * Escalation is not supported +* [ROM controller](ot_rom_ctrl.md) +* SRAM controller + * Initialization and scrambling from OTP key supported + * Wait for init completion (bus stall) emulated +* SoC Proxy only supports IRQ routing/gating + +### Sparsely implemented devices + +In this group, device CSRs are supported (w/ partial or full access control & masking) but only some +features are implemented. + +* Analog Sensor Top + * noise source only (from host source) + * configurable clock sources +* Pinmux + * Basic features (pull up/down, open drain) are supported for GPIO pin only +* Power Manager + * Fast FSM is partially supported, Slow FSM is bypassed + * Interactions with other devices (such as the Reset Manager) are limited +* [Reset Manager](ot_rstmgr.md) + * HW and SW reset requests are supported + +### Dummy devices + +Devices in this group are mostly implemented with a RAM backend or real CSRs but do not implement +any useful feature (only allow guest test code to execute as expected). + +* Sensor + +### Additional devices + +* [DevProxy](devproxy.md) is a CharDev-enabled component that can be remotely controlled to enable + communication with the system-side buses of the mailboxes and DMA devices. A Python library is + available as `scripts/opentitan/devproxy.py` and provide an API to remote drive the devproxy + communication interface. + +## Running the virtual machine + +See [OpenTitan machine](ot_machine.md) documentation for options. + +### Arbitrary application + +````sh +qemu-system-riscv32 -M ot-darjeeling,no_epmp_cfg=true -display none -serial mon:stdio \ + -readconfig docs/config/opentitan/darjeeling.cfg \ + -global ot-ibex_wrapper.lc-ignore=on -kernel hello.elf +```` + +### Boot sequence ROM, ROM_EXT, BLO + +````sh +qemu-system-riscv32 -M ot-darjeeling -display none -serial mon:stdio \ + -readconfig docs/config/opentitan/darjeeling.cfg \ + -object ot-rom_img,id=rom,file=rom_with_fake_keys_fpga_cw310.elf \ + -drive if=pflash,file=otp-rma.raw,format=raw \ + -drive if=mtd,bus=0,file=flash.raw,format=raw +```` + +where `otp-rma.raw` contains the RMA OTP image and `flash.raw` contains the signed binary file of +the ROM_EXT and the BL0. See [`otptool.py`](otptool.md) and [`flashgen.py`](flashgen.md) tools to +generate the `.raw` image files. + +## Buses + +Darjeeling emulation supports the following buses: + +| **Type** | **Num** | **Usage** | +| -------- | ------- | -----------------------------------------------------------| +| `mtd` | 0 | [SPI host](ot_spi_host.md), [SPI device](ot_spi_device.md) | +| `pflash` | 0 | [OTP](ot_otp.md) | + +## Tools + +See [`tools.md`](tools.md) + +## Useful debugging options + +See [debug option](debug.md) for details. diff --git a/docs/opentitan/ot_earlgrey.md b/docs/opentitan/ot_earlgrey.md new file mode 100644 index 0000000000000..61489efd39ef5 --- /dev/null +++ b/docs/opentitan/ot_earlgrey.md @@ -0,0 +1,141 @@ +# EarlGrey + +## Supported version + +[Earlgrey 1.0.0](https://github.com/lowRISC/opentitan/tree/earlgrey_1.0.0) + +## Supported devices + +### Near feature-complete devices + +* [AES](ot_aes.md) +* Alert controller + * ping mechanism is not supported +* AON Timer +* CSRNG +* EDN +* [Flash controller](ot_flash.md) + * largely functional but without ECCs/ICVs, scrambling functionality & alerts + * no modelling of erase suspend or RMA entry + * lc_ctrl NVM debug signal not implemented, escalation partially implemented +* HMAC +* [IBEX CPU](ibex_cpu.md) +* [Key manager](ot_keymgr.md) + * Almost feature complete + * Missing entropy reseeding, and support for KMAC masking (when available) +* [OTBN](ot_otbn.md) +* [OTP controller](ot_otp.md) + * read and write features are supported, + * Present scrambling is supported with digest checks, + * ECC (detection and correction) is supported +* [ROM controller](ot_rom_ctrl.md) +* SPI data flash (from QEMU upstream w/ fixes) +* [SPI Host controller](ot_spi_host.md) + * HW bus config is ignored (SPI mode, speed, ...) +* [SPI Device](ot_spi_device.md) +* Timer +* [UART](ot_uart.md) + * missing RX timeout, TX break not supported + * bitrate is not paced vs. selected baurate + +### Partially implemented devices + +Devices in this group implement subset(s) of the real HW. + +* Clock Manager + * Runtime-configurable device, through properties + * Manage clock dividers, groups, hints, software configurable clocks + * Propagate clock signals from source (AST, ...) to devices + * Hint management and measurement are not implemented +* Entropy Src + * test/health features are not supported +* [I2C controller](ot_i2c.md) + * Supports only one target mode address - ADDRESS1 and MASK1 are not implemented + * Timing features are not implemented + * Loopback mode is not implemented +* [Ibex wrapper](ot_ibex_wrapper.md) + * random source (connected to CSR), FPGA version, virtual remapper, fetch enable can be controlled + from Power Manager +* KMAC + * Masking is not supported +* Lifecycle controller + * [LC controller](lc_ctrl_dmi.md) can be accessed through JTAG using a DM-TL bridge +* [ROM controller](ot_rom_ctrl.md) +* SRAM controller + * Initialization and scrambling from OTP key supported + * Wait for init completion (bus stall) emulated +* [USB Device](ot_usbdev.md) + +### Sparsely implemented devices + +In this group, device CSRs are supported (w/ partial or full access control & masking) but only some +features are implemented. + +* Analog Sensor Top + * noise source only (from host source) + * configurable clock sources +* [GPIO](ot_gpio.md) + * Connections with pinmux not implemented (need to be ported from [Darjeeling](ot_darjeeling.md) + version) +* Power Manager + * Fast FSM is partially supported, Slow FSM is bypassed + * Interactions with other devices (such as the Reset Manager) are limited +* [Reset Manager](ot_rstmgr.md) + * HW and SW reset requests are supported + +### Dummy devices + +Devices in this group are mostly implemented with a RAM backend or real CSRs but do not implement +any useful feature (only allow guest test code to execute as expected). +Some just use generic `UNIMP` devices to define a memory region. + +* Pattern Generator +* Pinmux +* PWM +* Sensor Control +* System Reset Controller + +## Running the virtual machine + +See [OpenTitan machine](ot_machine.md) documentation for options. + +### Arbitrary application + +````sh +qemu-system-riscv32 -M ot-earlgrey,no_epmp_cfg=true -display none -serial mon:stdio \ + -readconfig docs/config/opentitan/earlgrey.cfg \ + -global ot-ibex_wrapper.lc-ignore=on -kernel hello.elf +```` + +### Boot sequence ROM, ROM_EXT, BLO + +````sh +qemu-system-riscv32 -M ot-earlgrey -display none -serial mon:stdio \ + -readconfig docs/config/opentitan/earlgrey.cfg \ + -object ot-rom_img,id=rom,file=rom_with_fake_keys_fpga_cw310.elf \ + -drive if=pflash,file=otp-rma.raw,format=raw \ + -drive if=mtd,bus=2,file=flash.raw,format=raw +```` + +where `otp-rma.raw` contains the RMA OTP image and `flash.raw` contains the signed binary file of +the ROM_EXT and the BL0. See [`otptool.py`](otptool.md) and [`flashgen.py`](flashgen.md) tools to +generate the `.raw` image files. + +## Buses + +EarlGrey emulation supports the following buses: + +| **Type** | **Num** | **Usage** | +| -------- | ------- | -------------------------------------------------------------| +| `mtd` | 0 | [SPI host 0](ot_spi_host.md), [SPI device](ot_spi_device.md) | +| `mtd` | 1 | [SPI host 1](ot_spi_host.md) | +| `mtd` | 2 | [Embedded Flash](ot_flash.md) | +| `pflash` | 0 | [OTP](ot_otp.md) | + +## Tools + +See [`tools.md`](tools.md) + +## Useful debugging options + +See [debug option](debug.md) for details. diff --git a/docs/opentitan/ot_eg_pad_ring.md b/docs/opentitan/ot_eg_pad_ring.md new file mode 100644 index 0000000000000..8e7301a8a58dd --- /dev/null +++ b/docs/opentitan/ot_eg_pad_ring.md @@ -0,0 +1,33 @@ +# OpenTitan Earl Grey Pad Ring + +## Power-on Reset (POR) + +The Earl Grey Pad Ring currently only supports the negated Power-on Reset (PoR) pad, which can +be signalled by setting the `por_n` property and resetting the VM to perform a Power-on Reset. +This can for example be done with the QEMU Monitor via the following command sequence: +``` +> qom-set ot-eg-pad-ring.0 por_n low +> system_reset +> qom-set ot-eg-pad-ring.0 por_n high +``` + +Equivalent QMP JSON commands can also be used. + +Note that the current implementation directly invokes a reset request on any reset where a falling +edge is detected (i.e. the reset strapping is asserted), and it is not well supported to "hold" the +device in reset. If it is desired to emulate this time, you should stop and resume the VM for +for the duration of the reset, e.g.: +``` +/* Asserting the POR signal */ +> stop +> qom-set ot-eg-pad-ring.0 por_n low +> system_reset +/* ... wait for the duration of the reset ... */ +/* De-asserting the POR signal */ +> qom-set ot-eg-pad-ring.0 por_n high +> cont +``` + +## MIO Pads + +Currently, Earl Grey's MIO pads are not connected in the Pad Ring / Pinmux. diff --git a/docs/opentitan/ot_flash.md b/docs/opentitan/ot_flash.md new file mode 100644 index 0000000000000..0b223488832f6 --- /dev/null +++ b/docs/opentitan/ot_flash.md @@ -0,0 +1,20 @@ +# OpenTitan embedded flash + +* `-drive if=mtd,id=eflash,bus=,file=,format=raw` should be used to specify a path to + a QEMU RAW image file used as the OpenTitan internal flash controller image. This _RAW_ file + should have been generated with the [`flashgen.py`](flashgen.md) tool. + +## Machine specific options + +### EarlGrey Machine + +MTD bus 2 is assigned to the internal controller with the embedded flash storage, _i.e._ the command +line option should be written `-drive if=mtd,id=eflash,bus=2,file=,format=raw`. + +### Darjeeling Machine + +[Darjeeling](ot_darjeeling.md) machine does not support an embedded flash device. + +## Notes + +For external SPI data flash support, see [SPI host](ot_spi_host.md) documentation. diff --git a/docs/opentitan/ot_gpio.md b/docs/opentitan/ot_gpio.md new file mode 100644 index 0000000000000..67a68785d5130 --- /dev/null +++ b/docs/opentitan/ot_gpio.md @@ -0,0 +1,136 @@ +# OpenTitan GPIO + +## Foreword + +There are two variations of the GPIO device: one for EarlGrey, one for Darjeeling variants. + +In the following document, `OTMACHINE` should be defined as `eg` for EarlGrey machine or as `dj` +for Darjeeling one. + +## Options + +### Darjeeling machine + +When using multiple GPIO IPs, traces may become highly verbose, coming from multiple source. +It is possible to limit the trace to a single GPIO IP, using the following option: + +`-global ot-gpio-dj.log_id=` where _ot_id_ is the OpenTitan identifier of the GPIO device. + +When no `log_id` option is specified, all GPIO IP may emit trace messages. + +#### Note + +This option is not supported on the [EarlGrey](ot_earlgrey.md) machine, since only one GPIO device +instance is available. + +## Initial configuration + +It is possible to configure initial values of the GPIO pins: + +OpenTitan GPIO driver accept global options: + +- `ot-gpio-$OTMACHINE.in` defines the input values of the GPIO port as a 32-bit value +- `ot-gpio-$OTMACHINE.out` defines the output values of the GPIO port as a 32-bit value +- `ot-gpio-$OTMACHINE.oe` defines the output enable of the GPIO port as a 32-bit value + +All values default to zero, that is all GPIOs as input/hi-z, read 0. + +### Example + +``` +-global ot-gpio-dj.in=0x00ffff00 -global ot-gpio-dj.oe=0x1 -global ot-gpio-dj.out=0x1 +``` + +Note: If there were several GPIO instances in a machine, these configurations would apply to all +GPIO instances. + +## Character Device + +OpenTitan GPIO driver can be connected to any CharDev device to expose as a very simple ASCII data +stream the GPIO input and output pins. + +This CharDev device can be used to stimulate the GPIO and perform unit tests. + +To connect the GPIO to its optional character device, use the following QEMU option + +``` +-chardev type,id=gpio -global ot-gpio-$OTMACHINE.chardev=gpio +``` + +where type is one of the supported QEMU chardev type, such as + +- serial to connect to an existing serial communication device +- socket to use a TCP connection +- pipe to use a local pipe +- ... + +`id` is an arbitrary string that should always match the value defined with the `-global` option. + +## Protocol + +The communication protocol is ASCII based and very simple. +Each frame follows the following format: + +### Format + +``` + : +``` + +where: + +1. `TYPE` is a single uppercase char +2. `HEXVALUE` is a 32-bit hex encoded lowercase value +3. `CR` is the carriage return character (0x0d) +4. `LF` is the line feed character, or end-of-line (0x0a) + +Each frame is delimited with `LF` characters. `CR` are ignored and accepted to ease compatibility +with some terminals but are useless. + +The hex value represents the 32-bit GPIO values. + +#### Supported frame types + +A type describes the meaning of the hex value. Supported types are: + +* `C` clear/reset host (at QEMU start up) +* `D` direction, _i.e._ Output Enable in OpenTitan terminology (QEMU -> host) +* `I` input GPIO values (host -> QEMU) +* `M` mask GPIO input values, i.e. non connected input pins (host -> QEMU) +* `O` output GPIO values (QEMU -> host) +* `P` output GPIO pull up/down values (QEMU -> host) +* `Q` query input (QEMU -> host). QEMU may emit this frame, so that the host replies with a new + input `I` frame (hexvalue of `Q` is ignored) +* `R` repeat (host -> QEMU). The host may ask QEMU to repeat the last `D` and `O` frames +* `Y` forwards the GPIO input that QEMU has read to the host (QEMU -> host) for tracking purposes +* `Z` output pull up/down GPIO HiZ values (QEMU -> host). 1 means HiZ, 0 means + pull up/down values apply. + +Frames are only emitted whenever the state of either peer (QEMU, host) change. QEMU should emit `D` +and `O` frames whenever the GPIO configuration or output values are updated. The host should emit +a `I` frame whenever its own input lines change. + +`Q` and `R` are only emitted when a host connects to QEMU or when one side resets its internal +state. + +### Example + +The `scripts/opentitan/trellis` directory contains two Python files that may be copied to an +an Adafruit NeoTrellis M4 Express card initialized with Circuit Python 8.0+ + +These scripts provide a physical, visual interface to the virtual GPIO pins, which is connected to +the QEMU machine over a serial port (a USB CDC VCP in this case). + +To connect to the NeoTrellis board, use a configuration such as: + +``` +-chardev serial,id=gpio,path=$SERIALDEV -global ot-gpio-$OTMACHINE.chardev=gpio +``` + +where `SERIALDEV` is the data serial port of the Neotreillis board, _e.g._ `/dev/ttyACM1` + +Note: the first serial port of the board is reserved to its debug console. + +### Testing + +See the [gpiodev.py](gpiodev.md) script. diff --git a/docs/opentitan/ot_i2c.md b/docs/opentitan/ot_i2c.md new file mode 100644 index 0000000000000..5013a508da905 --- /dev/null +++ b/docs/opentitan/ot_i2c.md @@ -0,0 +1,8 @@ +# OpenTitan I2C + +* `-device ,bus=,address=
` can be used to attach devices at a specific address + to one of the three I2C buses. + + Bus names depends on the platform. They are usually named as `ot-i2c0` ... `ot-i2cN`. + +See also [I2C host proxy](i2c_host_proxy.md) diff --git a/docs/opentitan/ot_ibex_wrapper.md b/docs/opentitan/ot_ibex_wrapper.md new file mode 100644 index 0000000000000..8a45fab0741c3 --- /dev/null +++ b/docs/opentitan/ot_ibex_wrapper.md @@ -0,0 +1,39 @@ +# OpenTitan Ibex Wrapper + +* `-global ot-ibex_wrapper.lc-ignore=on` should be used whenever no OTP image is provided, or if + the current LifeCycle state stored in the OTP image does not allow the Ibex core to fetch data. + This switch forces the Ibex core to execute whatever the LifeCycle broadcasted signal, which + departs from the HW behavior but maybe helpful to run the machine without a full OTP set up. The + alternative to allow the Ibex core to execute guest code is to provide a valid OTP image with one + of the expected LifeCycle state, such as TestUnlock*, Dev, Prod or RMA. + +* `-global ot-ibex_wrapper.lc-ignore-ids=` acts as `lc-ignore`, enabling the selection of + specific ibex wrapper instance based on their unique identifiers. See `ot_id` property in the + machine definition file for a list of valid identifiers. `` should be defined as a comma- + separated list of valid identifiers. It is only possible to ignore LifeCycle states with this + option, not to enforce them. + +The `FPGA_INFO` register of the Ibex Wrapper device is used to report that the HW platform is a QEMU +virtual machine. It contains three ASCII chars `QMU` followed with a configurable _version_ field in +the MSB, whose meaning is not defined. It can be any 8-byte value, and defaults to 0x0. To configure +this version field, use the `qemu_version` property of the Ibex Wrapper device. + +The `DV_SIM_STATUS` register (address 0 of the `DV_SIM_WINDOW`) can be used to exit QEMU with a +passing or failing status code. The lower half of the word is written either `900d` (good) or `baad` +(bad). If an error code is written to the upper half of the word, QEMU will exit with that status +code for failures. The `-global ot-ibex_wrapper.dv-sim-status-exit=[on|off]` can be used to control +whether QEMU shuts down when this register is written. + +There are two modes to handle address remapping, with different limitations: + +- default mode: use an MMU-like implementation (via ot_vmapper) to remap addresses. This mode + enables to remap instruction accesses and data accesses independently, as the real HW. However, + due to QEMU limitations, addresses and mapped region sizes should be aligned and multiple of 4096 + bytes, i.e. a standard MMU page size. This is the recommended mode. + +- legacy mode: This mode has no address nor size limitations, however it cannot distinguish + instruction accesses from data accesses, which means that both kind of accesses must be defined + for each active remapping slot for the remapping to be enabled. Moreover it relies on MemoryRegion + aliasing and may not be as robust as the default mode. It is recommended to use the default mode + whenever possible. To enable this legacy mode, set the `alias-mode` property to true: + `-global ot-ibex_wrapper.alias-mode=true` diff --git a/docs/opentitan/ot_keymgr.md b/docs/opentitan/ot_keymgr.md new file mode 100644 index 0000000000000..f36eb1b8aa7bb --- /dev/null +++ b/docs/opentitan/ot_keymgr.md @@ -0,0 +1,14 @@ +# OpenTitan Key Manager support + +## Properties + +- `-global ot-keymgr.disable-flash-seed-check=true` can be used to disable the +data validity check in the Keymgr for loaded flash secrets (the owner and +creator seed). This validity check ensures that the loaded key is not all-zero +or all-one (and thus probably uninitialized). When emulating OpenTitan, it may +be useful to be able to advance using uninitialized keys due to a lack of flash +info splicing, to bypass the need to run through an entire provisioning flow. + - Note also that the fatal Keymgr alert caused by failing this check should + not appear for unprovisioned flash if flash scrambling is implemented (and + enabled). This is because the garbage unscrambled data that is read will not + pass this check. diff --git a/docs/opentitan/ot_machine.md b/docs/opentitan/ot_machine.md new file mode 100644 index 0000000000000..146a9a3be9079 --- /dev/null +++ b/docs/opentitan/ot_machine.md @@ -0,0 +1,24 @@ +# OpenTitan machine + +### Machine configuration + +To start up an OpenTitan virtual machine, a configuration file is required. See [OT config](otcfg.md) +documentation for details. The configuration file should be specified with the `-readconfig` option. + +### `-M ` optional arguments + +* `no_epmp_cfg=true` can be appended to the machine option switch, _i.e._ + `-M ot-earlgrey,no_epmp_cfg=true` to disable the initial ePMP configuration, which can be very + useful to execute arbitrary code on the Ibex core without requiring an OT ROM image to boot up. + +* `ignore_elf_entry=true` can be appended to the machine option switch, _i.e._ + `-M ot-earlgrey,ignore_elf_entry=true` to prevent the ELF entry point of a loaded application to + update the vCPU reset vector at startup. When this option is used, with `-kernel` option for + example, the application is loaded in memory but the default machine reset vector is used. + +* `verilator=true` can be appended to the machine option switch, to select Verilator lowered clocks: + _i.e._ `-M ot-earlgrey,verilator=true` to select Verilator reduced clock rates. It enables to run + FW which has been built for the Verilator target in OpenTitan main repository. + +See also [ot-ibex_wrapper.lc-ignore option](ot_ibex_wrapper.md) to enable VM start up without a +valid [OTP](ot_otp.md) image file. diff --git a/docs/opentitan/ot_otbn.md b/docs/opentitan/ot_otbn.md new file mode 100644 index 0000000000000..f06ee1683392c --- /dev/null +++ b/docs/opentitan/ot_otbn.md @@ -0,0 +1,9 @@ +# OpenTitan OTBN + +* `-global ot-otbn.logfile=` output OTBN execution message to the specified logfile. When + _logasm_ option (see below) is not enabled, only execution termination and error messages are + logged. `stderr` can be used to log the messages to the standard error stream instead of a file. + +* `-global ot-otbn.logasm=` dumps executed instructions on OTBN core into the _logfile_ + filename. Beware that this further slows down execution speed, which could likely result in the + guest application on the Ibex core to time out. diff --git a/docs/opentitan/ot_otp.md b/docs/opentitan/ot_otp.md new file mode 100644 index 0000000000000..0b03a138a0faf --- /dev/null +++ b/docs/opentitan/ot_otp.md @@ -0,0 +1,10 @@ +# OpenTitan OTP + +* `-drive if=pflash,file=otp.raw,format=raw` should be used to specify a path to a QEMU RAW image + file used as the OpenTitan OTP image. This _RAW_ file should have been generated with the + [`otptool.py`](otptool.md) tool. + +* on LC escalate reception, it is possible to early abort VM execution. Specify + `-global ot-otp-.fatal_escalate=true` to enable this feature. + where `top` should be defined as `eg` for the [EarlGrey](ot_earlgrey.md) machine, or `dj` for the + [Darjeeling](ot_darjeeling.md) machine. diff --git a/docs/opentitan/ot_rom_ctrl.md b/docs/opentitan/ot_rom_ctrl.md new file mode 100644 index 0000000000000..fc7d36c19bb5f --- /dev/null +++ b/docs/opentitan/ot_rom_ctrl.md @@ -0,0 +1,101 @@ +# OpenTitan ROM Controller + +The OpenTitan ROM Controller computes a digest of the ROM content on boot, using one of the +application interfaces of the KMAC. When the ROM check is complete, the ROM Controller sends a +signal to the Power Manager. This triggers CPU startup if the ROM check was successful. + +On real hardware, the ROM digest is computed on the ROM content _including ECC_ and the expected +digest value is stored at the end of the scrambled ROM (with invalid ECC to make sure it's not +accessible by software). + +On the QEMU emulated ROM Controller, if the ROM controller is submitted a scrambled ROM image file, +its digest is used and verified. Otherwise, a fake digest is generated, i.e. no actual ROM content +validation is performed. + +## QEMU ROM Options + +### Supported image file formats + +The type of a ROM image file format is automatically detected from its content. + +The ROM file digest can be provided on the QEMU command line using this option: + +``` +-object ot-rom_img,id=,file=/path/to/rom +``` + +#### ELF ROM file + +ELF32 RISC-V file can be used as a ROM controller image file. Such file format neither supports +digest nor ECC. Digest is faked in this case. + +#### VMEM ROM file + +Two kinds of VMEM files are supported: + +* 32-bit VMEM files, _i.e._ VMEM file without ECC. Such file should contain non-scrambled data. +* 39-bit VMEM files, _i.e._ VMEM file with 7-bit ECC and scrambled data. + +39-bit scrambled ECC VMEM files are only supported when the QEMU machine has instantiated the ROM +controller with `key` and `nonce` arguments. + +#### HEX ROM file + +39-bit HEX files, _i.e._ HEX file with 7-bit ECC and scrambled data. + +39-bit scrambled ECC HEX files are only supported when the QEMU machine has instantiated the ROM +controller with `key` and `nonce` arguments. + +Note that HEX file format differs from IHEX file format. The former only contains hexadecimal- +encoded data, where the two first digits contain the 7-bit ECC value, and the remaining digits +contains the 32-bit data value. + +#### Binary ROM file + +Flat, raw binary file can be used as a ROM controller image file. Such file format neither supports +digest nor ECC. Digest is faked in this case. + +### ROM identifiers [#romid] + +The ROM image ID may depend on the SoC. + +* for EarlGrey which has a single ROM, the ID is expected to be `rom`. +* for a SoC with two ROMs, the IDs would be expected to be `rom0` and `rom1`. +* for a machine with multiple SoCs, the IDs would be additionally prefixed with the SoC name and a + full stop, _e.g._ `soc0.rom0` + +### ROM unscrambling constants + +Each machine and each ROM controller uses a different pair of (key, nonce) constants to unscramble +the ROM content. + +These constants may be defined in the machine, or in an external configuration file so that these +constants are present neither in the QEMU source code nor the QEMU binary. The standard QEMU +`-readconfig ` may be used to load those constants. + +See [OpenTitan configuration file](otcfg.md) for details. + +## Booting with and without ROM + +### With ROM + +This mode is useful to implement the standard OpenTitan boot flow. + +In this mode, the ROM digest is always checked against the expected digest value if a scrambled ROM +image file is submitted. + +### Without ROM + +This mode is useful when starting an application using `-kernel` QEMU option: the application starts +directly at CPU reset. + +If no ROM image is specified on QEMU command line (or if the ROM image does not have the expected ID +for the machine), it does not prevent the CPU from starting: +- ROM Controller provides an empty ROM region +- ROM Controller activates _fake digest_ mode: digest is computed on the empty ROM region and + expected digest value is faked. ROM is "valid" so signal is sent to Power Manager to start the +CPU. + +When the `-kernel` option is used, the default `resetvec` of the machine is overridden with the +entry point defined in the ELF file. The default `mtvec` is not modified - it is expected the ELF +early code updates the `mtvec` with a reachable location if no ROM is used. diff --git a/docs/opentitan/ot_rstmgr.md b/docs/opentitan/ot_rstmgr.md new file mode 100644 index 0000000000000..b825c8c9b7741 --- /dev/null +++ b/docs/opentitan/ot_rstmgr.md @@ -0,0 +1,9 @@ +# OpenTitan Reset Manager + +It is possible to limit the number of times the VM reboots the guest. This option may be useful +during the development process when an issue in the early FW stages - such as the ROM - causes an +endless reboot cycles of the guest. + +To limit the reboot cycles, use the `-global ot-rstmgr.fatal_reset=` option, where `N` is an +unsigned integer. This option forces the QEMU VM to exit the N^th^ time the reset manager receives +a reset request, rather than rebooting the whole machine endlessly as the default behavior. diff --git a/docs/opentitan/ot_soc_dbg_ctrl.md b/docs/opentitan/ot_soc_dbg_ctrl.md new file mode 100644 index 0000000000000..e0fbcc1b1aa05 --- /dev/null +++ b/docs/opentitan/ot_soc_dbg_ctrl.md @@ -0,0 +1,11 @@ +# OpenTitan SoC Debug controller + +SoC debug controller manages SoC debug policies based on external signals - such as GPIO, Power +Manager states and LifeCycle states, the later being defined from the OTP content. If no OTP image +is provided, or a RAW (blank) image is provided, or if the OTP image defines a LifeCycle in any of +TEST* or RMA states, a Darjeeling machine that features a SoC Debug controller may enter the DFT +("Debug For Test") execution mode, where the Ibex core may not resume execution till a JTAG debugger +triggers it. + +To force QEMU to execute an application despite this feature, bypassing the DFT mode, use +`-global ot-socdbg_ctrl.dft-ignore=on` QEMU option. diff --git a/docs/opentitan/ot_spi_device.md b/docs/opentitan/ot_spi_device.md new file mode 100644 index 0000000000000..e5907a639b0fe --- /dev/null +++ b/docs/opentitan/ot_spi_device.md @@ -0,0 +1,131 @@ +# OpenTitan SPI Device + +## Supported modes + +### Flash mode + +This mode is fully supported (to the extent of the understanding of the HW...). + +### Passthrough mode + +This mode is supported, with minor deficiencies: The two-stage read pipeline, and dummy cycle +counts of 1 to 7 are not supported as SPI transfers are modelled with byte-granularity (see the +[CharDev protocol](#spi-device-chardev-protocol)). For commands with 1 to 7 dummy cycles specified, +the maximum 8 dummy cycles (1 dummy byte) will be used. + +### TPM + +This mode is partially supported, TPM commands handled by hw are not supported yet. The CharDev +protocol doesn't support a distinct chip select for TPM, therefore it is sharing the same CS with +the other modes. If CS is asserted and TPM is enabled, the TPM will have priority. + +## Connection with a SPI Host + +### CharDev simple bus header + +To communicate with the SPI device emulation, it is possible to create and use any QEMU CharDev. + +The CharDev is expected to used as a full bi-directional, stream based, asynchronous communication +channel. + +CharDev always output as many payload bytes as it receives, like a regular SPI bus. + +### Creating QEMU SPI Device CharDev + +The most common/useful CharDev for SPI device is to use a TCP communication stream, which can be +instantiated this way from the command line: + +```` +-chardev socket,id=spidev,host=localhost,port=8004,server=on,wait=off +```` + +Note that `opentitantool` and association library do support this protocol when the `qemu` backend +is used: + +```` +opentitantool --interface qemu --help +A tool for interacting with OpenTitan chips. + +Usage: opentitantool [OPTIONS] + +Commands: + ... + spi Commands for interacting with a SPI EEPROM + ... + --qemu-host [default: localhost] + --qemu-spidev-port [default: 8004] +```` + +IT is also possible to use [`spidevflash.py`](spidevflash.md) tool to upload a binary using the same +protocol. + +### SPI Device CharDev protocol + +SPI clock is not emulated, but each byte exchanged over the communication channel represent 8-bit +SPI data. Dual and Quad lines are not emulated, all communications happen over a regular byte +stream - which does not prevent from using dual or quad SPI flash commands. + +As some out-of-band or metadata is required, for example the status of the /CS line, a small header +is inserted by the SPI host for each SPI communication packet in the MOSI stream. There is no such +header inserted into the stream for the MISO channel. Moreover as the SPI header contains the length +of the payload, it also acts as a SPI packet delimiter. Each time the SPI host peer is disconnected, +the /CS line and the SPI device state machine are reset so it is possible to recover from a +corrupted communication w/o exiting QEMU. + +A packet is limited to a payload of 65536 bytes, however an SPI transaction may extend over several +SPI communication packets. + +A CharDev communication is always initiated by the remote SPI host. It transmits the 8-byte SPI +device header described below, where the first word can be considered as a magic number, and +the last word describes the payload that comes right after the header. The payload should contain +the count of bytes (SPI MOSI data). The SPI device should start receiving the very same + count of bytes (SPI MISO data). In other words, the payload in both direction have always +the same amount of bytes. + +The host-to-device stream always starts with a 8-byte header, and there is no header, i.e. only +payload in the device-to-host stream. The header bit defines whether the host releases the /CS +line once the SPI transfer is over, or whether the SPI device should expect a continuation SPI +transfer, which is always prefixed with another header. The last SPI transfer of a SPI transaction +should release the /CS line, i.e. should be 0. + +```` + Time --> + + MOSI: | Header1 | TX Payload1 | Header2 | TX Payload2 | + \ \ \ \ + MISO: | RX Payload1 | | RX Payload2 | +```` + +```` + +---------------+---------------+---------------+---------------+ + | 0 | 1 | 2 | 3 | + +---------------+---------------+---------------+---------------+ + |0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F| + 0x00 -+---------------+---------------+---------------+---------------+ + | '/' | 'C' | 'S' | version | + 0x04 -+---------------+---------------+---------------+---------------+ + |p|a|t|r| - |c| - | length (Byte count) | + 0x08 -+---------------+---------------+---------------+---------------+ + | | | | | + 0x0c -+---------------+---------------+---------------+---------------+ + | . . . | + -+---------------+---------------+---------------+---------------+ + | | + -+---------------+ +```` + + - `version`: protocol version, current version uses 0. + - `length`: count of payload bytes (does not need to be a multiple of 4) + - `p`: polarity, should match `CFG.CPOL` (not yet supported) + - `a`: phase, should match `CFG.CPHA` (not yet supported) + - `t`: tx order, see `CFG.TX_ORDER` (not yet supported) + - `r`: rx order, see `CFG.RX_ORDER` (not yet supported) + - `c`: whether to keep _/CS_ low (=1) or release _/CS_ (=0) when payload has been processed. Any + SPI transaction should end with C=0 packet. However it is possible to use several SPI device + CharDev packets to handle a single SPI transaction: example: JEDEC ID w/ continuation code, + polling for BUSY bit, ... + +Note that SPI device support bit reversing for both TX and RX, the bit configuration in the SPI +device header is only used for debugging (tracking configuration mismatch between the host and the +device). Polarity and Phase are not emulated however SPI stream is explicitly corrupted (bit +inversion) if CPOL/CPHA do not match between host and device. diff --git a/docs/opentitan/ot_spi_host.md b/docs/opentitan/ot_spi_host.md new file mode 100644 index 0000000000000..569e18703bafb --- /dev/null +++ b/docs/opentitan/ot_spi_host.md @@ -0,0 +1,44 @@ +# OpenTitan SPI Host + +* `-drive if=mtd,bus=,file=,format=raw` should be used to specify a path to a QEMU RAW + image file used as the SPI data flash backend file. This _RAW_ file should have been created with + the qemu-img tool. There is no dedicated tool to populate this image file for now. + + ````sh + qemu-img create -f raw spi.raw 16M + ```` + + See the machine section for supported `` values. + +* `-global ot-spi_host.start-delay=