Unbinding apple_sep triggers two IOMMU WARNs and leaves the SEP firmware mapped in the device's DART. remove() unmaps the firmware region with its physical address instead of the IOVA that dma_map_resource() returned, so the unmap tears down page table entries that were never present and the real mapping survives.
drivers/soc/apple/sep.rs keeps only the shifted IOVA that MSG_BOOT_IMG4 needs and discards the IOVA itself:
let res = bindings::dma_map_resource(
self.dev.as_raw(),
self.region_params.addr,
...
);
self.fw_mapped.store(true, Relaxed);
res >> IOVA_SHIFT // res is never stored
remove() then passes the physical address of the reserved region:
bindings::dma_unmap_resource(
self.dev.as_raw(),
self.region_params.addr, // should be the IOVA from dma_map_resource()
self.region_params.size,
...
);
Impact
- Two WARNs per unbind, which taint the kernel.
- The firmware region stays mapped in the SEP's DART until reboot.
- Reachable on shipping configurations: the
sep node is enabled by default on t8103-j293, t8103-j313, t8103-j456, and t8103-j457.
- Anyone debugging the SEP hits this immediately, because unbind and rebind is the natural way to re-run
probe().
Steps to reproduce
-
Boot a machine whose sep node is enabled and confirm the driver is bound:
ls -l /sys/bus/platform/devices/396400000.sep/driver
-
Unbind the driver:
echo 396400000.sep | sudo tee /sys/bus/platform/drivers/apple_sep/unbind
-
Read dmesg.
Expected: the firmware mapping is torn down and dmesg stays quiet.
Actual: two WARNs, and the mapping is still present.
WARNING: drivers/iommu/io-pgtable-dart.c:308 at dart_unmap_pages+0x11c/0x140, CPU#1
pc : dart_unmap_pages+0x11c/0x140
lr : dart_unmap_pages+0x44/0x140
dart_unmap_pages+0x11c/0x140 (P)
apple_dart_unmap_pages+0x24/0x30
__iommu_dma_unmap+0x94/0x140
iommu_dma_unmap_phys+0xf8/0x118
_RNvMs0_...3sep9SepDriverEE20post_unbind_callback+0x34/0x70
WARNING: drivers/iommu/dma-iommu.c:844 at __iommu_dma_unmap+0x128/0x140, CPU#1
pc : __iommu_dma_unmap+0x128/0x140
lr : __iommu_dma_unmap+0x94/0x140
__iommu_dma_unmap+0x128/0x140 (P)
iommu_dma_unmap_phys+0xf8/0x118
_RNvMs0_...3sep9SepDriverEE20post_unbind_callback+0x34/0x70
The reserved region on this machine is at 0x10006340000, outside the device's DART address space, which is why the unmap finds nothing:
OF: reserved mem: 0x0000010006340000..0x00000100068b7fff (5600 KiB) map non-reusable sep-firmware
A rebind afterwards sends MSG_BOOT_TZ0 and never receives an ack, because SEPOS is already running. That is expected, but it makes unbind one-way.
Environment
|
|
| Machine |
Apple MacBook Pro (16-inch, 2021), apple,j316s / apple,t6000 |
| Kernel |
7.1.6-1-1-ARCH (linux-asahi 7.1.6.asahi1-1), aarch64 |
| Distribution |
Arch Linux ARM (Omarchy) |
| Config |
CONFIG_APPLE_SEP=y |
t600x does not enable the sep node, so reproducing here required adding aliases { sep = &sep; } and status = "okay" to t6000-j316s.dtb. The bug is in the unmap path and does not depend on that change.
Fix
Store the IOVA that dma_map_resource() returns and unmap that. Fix in #592.
Unbinding
apple_septriggers two IOMMU WARNs and leaves the SEP firmware mapped in the device's DART.remove()unmaps the firmware region with its physical address instead of the IOVA thatdma_map_resource()returned, so the unmap tears down page table entries that were never present and the real mapping survives.drivers/soc/apple/sep.rskeeps only the shifted IOVA thatMSG_BOOT_IMG4needs and discards the IOVA itself:remove()then passes the physical address of the reserved region:Impact
sepnode is enabled by default ont8103-j293,t8103-j313,t8103-j456, andt8103-j457.probe().Steps to reproduce
Boot a machine whose
sepnode is enabled and confirm the driver is bound:Unbind the driver:
Read
dmesg.Expected: the firmware mapping is torn down and
dmesgstays quiet.Actual: two WARNs, and the mapping is still present.
The reserved region on this machine is at
0x10006340000, outside the device's DART address space, which is why the unmap finds nothing:A rebind afterwards sends
MSG_BOOT_TZ0and never receives an ack, because SEPOS is already running. That is expected, but it makes unbind one-way.Environment
apple,j316s/apple,t60007.1.6-1-1-ARCH(linux-asahi7.1.6.asahi1-1), aarch64CONFIG_APPLE_SEP=yt600x does not enable the
sepnode, so reproducing here required addingaliases { sep = &sep; }andstatus = "okay"tot6000-j316s.dtb. The bug is in the unmap path and does not depend on that change.Fix
Store the IOVA that
dma_map_resource()returns and unmap that. Fix in #592.