Skip to content

UefiCpuPkg: Add RISC-V IOMMU driver#12314

Open
benjamindoron wants to merge 10 commits intotianocore:masterfrom
9elements:master
Open

UefiCpuPkg: Add RISC-V IOMMU driver#12314
benjamindoron wants to merge 10 commits intotianocore:masterfrom
9elements:master

Conversation

@benjamindoron
Copy link
Copy Markdown
Contributor

Description

This driver follows the RISC-V IOMMU Architecture Spec v1.0[1] and detects IOMMUs
declared in either an FDT or ACPI RIMT[2] table, then installs the EDK2 IOMMU protocol
on them. It handles PCI and system IOMMUs, as well as PCI and system devices
(for a system device, the platform policy protocol is needed to match DeviceHandle).

The driver may need some cleanup, but is otherwise ready.

Other commits are included to show what's needed, but may not be suited for merging.
For example, this requires UefiCpuPkg/BaseRiscVMmuLib: Force entry to 0 when clearing all attributes,
or successive attempts to map some device memory (after the previous operation finished with unmapping)
will fail in the library's loop, detecting that some bits are still set and apparently assume that this means
that the encountered entry is a non-leaf (and, being that we're on the last level, it ASSERTs for this).
I don't fully understand RISC-V page tables, so I don't know if I've written a fix or a workaround.

We may also now want to discuss the best way to integrate BaseRiscVMmuLib with its consumers
in light of the new driver. I recommend some context object: is this good?

  • Breaking change?
    • Breaking change - Does this PR cause a break in build or boot behavior?
    • Examples: Does it add a new library class or move a module to a different repo.
  • Impacts security?
    • Security - Does this PR have a direct security impact?
    • Examples: Crypto algorithm change or buffer overflow fix.
  • Includes tests?
    • Tests - Does this PR include any explicit test code?
    • Examples: Unit tests or integration tests.
  1. https://docs.riscv.org/reference/hardware/iommu/_attachments/riscv-iommu.pdf
  2. https://docs.riscv.org/reference/platform-software/acpi-rimt/_attachments/rimt-spec.pdf

How This Was Tested

This was built against https://github.com/9elements/rise-riscv-iommu-edk2-platforms
and executed with the following:

export WORKSPACE=$(pwd)
export GCC5_RISCV64_PREFIX=riscv64-linux-gnu-
export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms:$WORKSPACE/edk2-platforms/Platform/Intel
export EDK_TOOLS_PATH=$WORKSPACE/edk2/BaseTools

# Set up the build environment
pushd edk2
source edksetup.sh --reconfig
make -C BaseTools
popd

# Clean and build
build -a RISCV64 --buildtarget DEBUG \
  -p edk2-platforms/Platform/SiFive/U5SeriesPkg/FreedomU540HiFiveUnleashedBoard/U540.dsc \
  -t GCC5 cleanall

build -a RISCV64 --buildtarget DEBUG \
  -p edk2-platforms/Platform/SiFive/U5SeriesPkg/FreedomU540HiFiveUnleashedBoard/U540.dsc \
  -t GCC5

# Boot
qemu-system-riscv64 -M virt -smp 4 -m 2G -display none -serial stdio \
  -kernel Build/FreedomU540HiFiveUnleashed/DEBUG_GCC5/FV/U540.fd \
  -drive file=Fedora-Server-Host-Generic-42.20250911-2251ba41cdd3.riscv64.raw,if=none,id=nvm -device nvme,serial=deadbeef,drive=nvm

Integration Instructions

All platforms with IOMMUs must include this driver, and either FDT or ACPI support.
They must publish which of these is in use using the module for this.

To support PCIe IOMMUs and PCIe devices, a platform must implement PCIe support,
including any parsing of PCIe data from a previous firmware, and it must include the base PCIe
stack of modules (CpuIo2Dxe, PciHostBridgeDxe and PciBusDxe).

To support system devices, a platform must implement the new RISC-V IOMMU platform policy
protocol. For any DeviceHandle, it shall return its device_id as in the IOMMU spec,
and it shall return the base address of its upstream IOMMU.

To developers of system devices that will need IOMMU support: be aware that map operations
need to go through the IOMMU. With PCIe devices, that's done for you by the PCIe module stack,
but the PciIo protocol calls cannot be dropped for a system devices, only replaced by a call here.

@github-actions github-actions bot added the impact:security This change has a direct security impact such as changing a crypto algorithm. label Mar 19, 2026
@benjamindoron
Copy link
Copy Markdown
Contributor Author

Okay, so, the CI encounters errors for:

  • Spelling mistakes, I didn't look closely. Some aren't my fault and many aren't mistakes. Whatever.
  • It wants me to do an uncrustify run. Okay.

Those aren't a big deal. But it also won't allow EmbeddedPkg to be depended upon by UefiCpuPkg, but I need it to know whether the platform uses FDT or ACPI (gEdkiiPlatformHasDeviceTreeGuid and gEdkiiPlatformHasAcpiGuid). Is this an allowable dependency? If not, can I move the protocol GUIDs into MdeModulePkg on the basis that FDTs are no longer purely the 'embedded' choice, but also the choice of some architectures? That's a breaking change though.

@mergify
Copy link
Copy Markdown

mergify bot commented Apr 2, 2026

Merge Queue Status

  • Entered queue2026-04-02 07:40 UTC · Rule: default
  • 🚫 Left the queue2026-04-02 19:57 UTC · at aecbc4eb9132140816f0d77fba476d64c289f6e8

This pull request spent 12 hours 16 minutes 42 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

Mergify needs the author permission to update the base branch of the pull request.
@benjamindoron needs to authorize modification on its head branch.

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

@mergify
Copy link
Copy Markdown

mergify bot commented Apr 3, 2026

Merge Queue Status

  • Entered queue2026-04-03 04:28 UTC · Rule: default
  • 🚫 Left the queue2026-04-03 05:33 UTC · at aecbc4eb9132140816f0d77fba476d64c289f6e8

This pull request spent 1 hour 4 minutes 34 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

Mergify needs the author permission to update the base branch of the pull request.
@benjamindoron needs to authorize modification on its head branch.

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Entries with the 'valid' bit set and RWX bits cleared are considered
"table entries" (non-leaves). With the page table in this state, future
map operations will trigger assertions when they reach the final level,
and encounter what looks like a valid non-leaf entry.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This driver follows the RISC-V IOMMU Architecture Spec v1.0 and
detects IOMMUs declared in either an FDT or ACPI RIMT table, then
performs the basic initialisation steps on them.

It also installs the EDK2 IOMMU protocol and implements the boilerplate
to be compatible with the spec (such as the location of device buffers).
The central function, `IoMmuSetAttribute`, is stubbed at this time.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
TODO: Implement command queue

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This information is useful to see in the IOMMU driver, and there's no
need to raise our debug level. For testing only.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This driver is now capable of mapping an NVMe device, enabling commands
to be delivered to it. However, the driver soon asserts on a later command
(when we again call the MMU library), due to some apparent device page table
corruption.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This works. QEMU's virt board with an attached NVMe controller and IOMMU
successfully boots to the UEFI shell.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This commit also implements tear-down at exit BootServices for hand-off.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
Implement support for tearing down the IOMMUs at ExitBootServices
to prepare them for handoff to the OS.

This patch also contains some WIP code to detect the needed device_id
width (for PCI devices only, at this time). However, using PciIo
protocols requires *unconditionally* making initialisation wait on PCI
enumeration, and we'd rather be moving initialisation earlier, not later.
So, it's likely that - along with platform device support - we'll use
the ACPI/FDT information for this purpose.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
This allows platforms to return an IOMMU device_id themselves,
which is required for platform devices. When using this functionality,
the platform code must return the base address of the upstream IOMMU.

Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
Signed-off-by: Benjamin Doron <benjamin.doron@9elements.com>
@mergify
Copy link
Copy Markdown

mergify bot commented Apr 6, 2026

Merge Queue Status

  • Entered queue2026-04-06 19:25 UTC · Rule: default
  • 🚫 Left the queue2026-04-06 19:29 UTC · at 4864e18a968870da013168a2cd3ca25eb24db97e

This pull request spent 3 minutes 42 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

Mergify needs the author permission to update the base branch of the pull request.
@benjamindoron needs to authorize modification on its head branch.

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

@mergify
Copy link
Copy Markdown

mergify bot commented Apr 7, 2026

Merge Queue Status

  • Entered queue2026-04-07 04:23 UTC · Rule: default
  • 🚫 Left the queue2026-04-07 04:25 UTC · at 4864e18a968870da013168a2cd3ca25eb24db97e

This pull request spent 1 minute 19 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

Mergify needs the author permission to update the base branch of the pull request.
@benjamindoron needs to authorize modification on its head branch.

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

@mergify mergify bot added queued and removed queued labels Apr 7, 2026
@mergify
Copy link
Copy Markdown

mergify bot commented Apr 11, 2026

Merge Queue Status

  • Entered queue2026-04-11 00:40 UTC · Rule: default
  • 🚫 Left the queue2026-04-11 00:42 UTC · at 4864e18a968870da013168a2cd3ca25eb24db97e

This pull request spent 2 minutes 6 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

Mergify needs the author permission to update the base branch of the pull request.
@benjamindoron needs to authorize modification on its head branch.

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dequeued impact:security This change has a direct security impact such as changing a crypto algorithm.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants