Shared-memory allocator services (e.g., Android's gralloc)
allocate dma-bufs on behalf of client processes in different
cgroups. Today those allocations are charged to the allocator's
own cgroup, leaving client cgroups with no visibility into their
actual memory consumption and defeating resource limits.
This series adds memory cgroup accounting for dma-buf allocations,
building on T.J. Mercier's earlier series [1] and incorporating
feedback from previous versions and LPC discussions [2].
Patch 1 introduces the MEMCG_DMABUF stat and reserve/commit/cancel
and uncharge helpers. Rather than charging at the page level via
__GFP_ACCOUNT (which would require every dma-buf exporter to implement
charging, and makes cross-cgroup transfer impractical without access
to backing pages), we track charges externally on struct dma_buf via
a MEMCG_DMABUF stat counter and route all accounting through a single
path, removing the __GFP_ACCOUNT flag from system-heap allocations
to avoid double counting.
Patch 2 adds a charge_fd field to DMA_HEAP_IOCTL_ALLOC, accepting
either a pidfd or a cgroupfd to identify the target cgroup at
allocation time. If the target cgroup cannot accommodate the charge,
the allocation returns -ENOMEM.
Patches 3-6 add access control for cross-cgroup charging. Letting
userspace decide who to charge needs to be a privileged operation
because it has material impact on OOM decission and resource limits.
We gate it via LSM hooks for the two charge_fd flavours:
security_dma_buf_charge_task() gates the pidfd path (target
identified by task credentials) and security_dma_buf_charge_cgroup()
gates the cgroupfd path (target identified by cgroup directory label),
with SELinux implementations under a dma_buf object class.
Patch 7 adds DMA_BUF_IOCTL_XFER_CHARGE, a general ioctl on any
dma-buf fd to transfer charges post-allocation. This covers the
double-hop allocator case (SurfaceFlinger -> gralloc -> kernel)
and works for buffers from any exporter (DRM, V4L2, etc.). A new
memcg_account flag is added for dma_buf_export() to ensure that
transfer/charge is only applied for buffers backed by reclaimable
system memory. If the receiving cgroup lacks capacity for the charge,
the ioctl returns -ENOMEM and the original charge is preserved.
Patch 8 adds selftests.
Known limitations:
- Single-owner model: a dma-buf carries one memcg charge regardless
of how many processes share it.
- Only memcg accounting. CMA heaps would additionally need dmem
controller integration.
- If a transfer of an uncharged buffer fails, it remains uncharged.
The allocator (userspace) is expected to handle this (retry, free, ...).
- The LSM hooks are intentionally narrow. Broader cgroup access controls
(e.g. for the memfd/kexec handover case [2]) could be a separate effort
reusing the same pattern.
- Only system heap sets memcg_account today. Other exporters
(DRM, V4L2, etc.) can opt in by setting the flag, but are not
covered by this series.
[1] https://lore.kernel.org/cgroups/20230109213809.418135-1-tjmercier@google.co…
[2] https://lpc.events/event/20/contributions/2416/
Signed-off-by: Albert Esteve <aesteve(a)redhat.com>
---
Changes in v3:
- Split mem_cgroup_charge_dmabuf() into reserve/commit/cancel three-phase API
- Extract mem_cgroup_get_from_fd() helper shared by allocate and xfer paths
- Rename __padding to flags in struct dma_buf_transfer_charge
- Fix UAF race: move mod_memcg_state() before cmpxchg in transfer
- Add memcg_account opt-in flag; xfer returns -EOPNOTSUPP if unset
- Wrap dma_buf_charge_cgroup hook in #ifdef CONFIG_CGROUPS
- Fix TOCTOU in SELinux charge_cgroup xattr length handling
- Link to v2: https://lore.kernel.org/r/20261021-v2_20230123_tjmercier_google_com-v2-0-ef…
Changes in v2:
- Move charge_pid_fd to charge_fd, accepting cgroupfd in addition
to pidfd per Christian König.
- New DMA_BUF_IOCTL_XFER_CHARGE ioctl for post-allocation charge
transfer on any dma-buf, not just dma-heap buffers per Christian König
and T.J. Mercier.
- Moved __GFP_ACCOUNT removal to patch 1 per Barry Song.
- dma-buf charge/uncharge helpers take struct dma_buf * directly
to avoid the need for caller to manage size calculations.
- Added test_xfer_charge_cgroupfd_self to dmabuf-heap selftests.
- Added LSM and SELinux hooks for cgroupfd-based charging.
- Rebased to v7.3-rc7.
- Link to v1: https://lore.kernel.org/r/20260512-v2_20230123_tjmercier_google_com-v1-0-63…
---
Albert Esteve (7):
dma-heap: charge dma-buf memory via explicit memcg
security: dma-buf: Add dma_buf_charge_task LSM hook
security: dma-buf: Add dma_buf_charge_cgroup LSM hook
selinux: Restrict cross-cgroup dma-buf charging
selinux: Restrict dma-buf direct cgroup charging
dma-buf: transfer memcg charges via DMA_BUF_IOCTL_XFER_CHARGE
selftests/dmabuf-heaps: Add dma-buf memcg accounting tests
T.J. Mercier (1):
memcg: Add MEMCG_DMABUF accounting infrastructure
Documentation/admin-guide/cgroup-v2.rst | 5 +
drivers/dma-buf/dma-buf.c | 46 ++++
drivers/dma-buf/dma-heap.c | 28 +-
drivers/dma-buf/heaps/cma_heap.c | 3 +-
drivers/dma-buf/heaps/system_heap.c | 22 +-
drivers/tee/tee_heap.c | 3 +-
include/linux/dma-buf.h | 9 +
include/linux/dma-heap.h | 3 +-
include/linux/lsm_hook_defs.h | 4 +
include/linux/memcontrol.h | 52 ++++
include/linux/security.h | 18 ++
include/uapi/linux/dma-buf.h | 26 ++
include/uapi/linux/dma-heap.h | 7 +
mm/memcontrol.c | 192 ++++++++++++++
security/security.c | 34 +++
security/selinux/hooks.c | 44 ++++
security/selinux/include/classmap.h | 1 +
tools/testing/selftests/cgroup/Makefile | 2 +-
tools/testing/selftests/cgroup/test_memcontrol.c | 290 ++++++++++++++++++++-
tools/testing/selftests/dmabuf-heaps/config | 1 +
tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c | 227 +++++++++++++++-
tools/testing/selftests/dmabuf-heaps/vmtest.sh | 226 ++++++++++++++++
22 files changed, 1228 insertions(+), 15 deletions(-)
---
base-commit: 24a19b953e2a3d0ea5a8c4951a0ab8f32720c907
change-id: 20260508-v2_20230123_tjmercier_google_com-f44fcfb16530
Best regards,
--
Albert Esteve <aesteve(a)redhat.com>
This series is a follow-up to the discussion that has started here [1].
When memory is lent to the Secure world via FF-A, CPU speculative
accesses from NS to the lent pages can still occur as long as it retains
a cacheable mapping to it.
Ideally, lent memory would be "no-map" but that would mean giving up
MiBs of useful memory, so let's try to do better with the help of a CMA
pool.
On arm64, modifying the direct map at runtime is generally restricted
because the linear map defaults to block mapping and splitting blocks at
runtime may trigger fatal page fault, unless the CPU implements BBML3
or the entire direct map was mapped at page granularity from boot.
Forcing last-level mappings system-wide incurs a severe penalty we want
to avoid. Instead, this series introduces targeted last-level mappings
for designated memory regions, along with the "arm,ffa-lend-pool" CMA
driver to manage unmapping and remapping on lend/reclaim transitions:
1. memblock:
- Introduce MEMBLOCK_PTEMAP to force PTE mappings only for a specific region.
2. set_memory infrastructure:
- Introduce can_set_direct_map_range() to check if a specific address
range is mapped with last-level entries and can be modified safely.
- Introduce __set_direct_map_*() variants that bypass redundant checks
when the caller has already validated the range.
3. "arm,ffa-lend-pool" driver
- Introduce the "arm,ffa-lend-pool" CMA reserved-memory driver, which
unmaps pages prior to lending (ffa_prepare_lend()) and restores them
when reclaimed (ffa_lend_reclaimed()).
4. Optee support
- Hook OP-TEE dynamic protected memory pools to "arm,ffa-lend-pool" for
both SMC (via DT memory-region phandle) and FF-A (via
ffa_lend_pool_attach()) transports.
Testing:
========
Tested with QEMU v8 using OP-TEE OS (built with CFG_CORE_DYN_PROTMEM=y)
under both SMC and FF-A transports [2]
static void dump_direct_map(const char *label)
{
printf("\n=== %s ===\n", label);
fflush(stdout);
system("sed -n '/Linear Mapping start/,/Linear Mapping end/p' /sys/kernel/debug/kernel_page_tables");
fflush(stdout);
}
int main(int argc, char *argv[])
{
int heap_fd;
int dmabuf_fd;
struct dma_heap_allocation_data data = { 0 };
size_t size = 1024 * 1024; /* 1MB */
if (argc > 1)
size = strtoul(argv[1], NULL, 0);
dump_direct_map("BEFORE ALLOCATION");
heap_fd = open("/dev/dma_heap/protected,secure-video", O_RDWR);
if (heap_fd < 0) {
perror("open /dev/dma_heap/protected,secure-video");
return 1;
}
printf("\nOpened /dev/dma_heap/protected,secure-video\n");
printf("Allocating %zu bytes of protected memory via DMA heap...\n", size);
data.len = size;
data.fd_flags = O_RDWR | O_CLOEXEC;
if (ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &data) < 0) {
perror("ioctl DMA_HEAP_IOCTL_ALLOC");
close(heap_fd);
return 1;
}
dmabuf_fd = data.fd;
printf("Successfully allocated %zu bytes! dmabuf_fd = %d\n", size, dmabuf_fd);
dump_direct_map("DURING LEND (EXPECT HOLE IN DIRECT MAP)");
printf("\nReleasing dmabuf_fd...\n");
close(dmabuf_fd);
close(heap_fd);
dump_direct_map("AFTER RECLAIM (RESTORED DIRECT MAP)");
return 0;
}
[1] https://lore.kernel.org/all/20260807-tegra-vpr-v4-7-5510d16af89e@nvidia.com/
[2] https://optee.readthedocs.io/en/latest/building/gits/build.html#qemu-v8
Changelog:
v2:
- Rename MEMBLOCK_LLMAP to MEMBLOCK_PTEMAP (Mike)
- Warn on conflicting MEMBLOCK_NOMAP and MEMBLOCK_PTEMAP flags (Mike)
- Drop DT "ll-map" property and mark MEMBLOCK_PTEMAP from ffa_lend_pool_setup() (Rob, Thierry)
- Drop "reusable" and "no-map" property checks from ffa_lend_pool_setup() (Rob)
- dt-bindings: Document arm,ffa-lend-pool (Rob)
- Rework the Optee support with a separate ffa_lend_pool.c file.
- use walk_kernel_page_table_range_lockless() for
can_set_direct_map_range() to fix folded page table (Sashiko)
- Add missing TLB flush in ffa_prepare_lend()
- Disable hibernation
- Rebase on linux-next (next-20260918) to use the new set_direct_map*() ranges (Mike)
v1 (https://lore.kernel.org/all/20260902104712.2399797-1-vdonnefort@google.com/)
Vincent Donnefort (8):
memblock: Introduce MEMBLOCK_PTEMAP
arm64: Introduce can_set_direct_map_range()
arm64: Introduce __set_direct_map*()
arm64: Add support for MEMBLOCK_PTEMAP
firmware: arm_ffa: Introduce ffa-lend-pool
optee: Add support for arm,ffa-lend-pool
dt-bindings: reserved-memory: Add Arm FF-A lend pool
dt-bindings: firmware: optee: Add memory-region property
.../arm/firmware/linaro,optee-tz.yaml | 5 +
.../reserved-memory/arm,ffa-lend-pool.yaml | 55 ++++
arch/arm64/include/asm/set_memory.h | 7 +
arch/arm64/mm/mmu.c | 23 +-
arch/arm64/mm/pageattr.c | 72 ++++-
drivers/firmware/arm_ffa/Kconfig | 5 +
drivers/firmware/arm_ffa/Makefile | 1 +
drivers/firmware/arm_ffa/lend_pool.c | 261 ++++++++++++++++++
drivers/tee/optee/Makefile | 1 +
drivers/tee/optee/core.c | 6 +
drivers/tee/optee/ffa_abi.c | 13 +-
drivers/tee/optee/ffa_lend_pool.c | 72 +++++
drivers/tee/optee/optee_private.h | 4 +
drivers/tee/optee/protmem.c | 20 +-
drivers/tee/optee/smc_abi.c | 21 +-
include/linux/arm_ffa.h | 23 ++
include/linux/memblock.h | 18 ++
mm/memblock.c | 30 ++
18 files changed, 608 insertions(+), 29 deletions(-)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/arm,ffa-lend-pool.yaml
create mode 100644 drivers/firmware/arm_ffa/lend_pool.c
create mode 100644 drivers/tee/optee/ffa_lend_pool.c
base-commit: 3f2425f5b5bbbdd991ca9cdfd5502e68d8895998
--
2.55.0.1082.g2b9226bbc0-goog
This adds a driver on top of the rpmb subsystem for virtio-rpmb devices.
Alex Bennée had an earlier virtio-rpmb driver in his RPMB series [1]
but that stalled due to the user space API.
The one that merged later has no user space API and OP-TEE routes frames
through it so this driver only needs to implement route_frames().
I added patch 1 to fix a use-after-free that I hit while testing
removing the device (OP-TEE can still route frames after driver unregisters
the rpmb device).
I tested this with UML (virtio_uml) and a vhost-user backend I wrote
for this on top of rust-vmm's vhost-device with KASAN, lockdep:
- key programming
- write counter
- single and multi block write and read
- MAC and counter failures
- max_wr_cnt
- unbinding the driver when the rpmb device is held
With OP-TEE 4.11 on QEMU virt arm64 the secure_storage example TA keeps
its objects in RPMB through the driver and an object written to in one
boot is found in the one after.
I have added myself in MAINTAINERS. I would like to maintain the driver.
Changes in v2:
- Use guard() and scoped_guard() for the locks in both patches (Greg)
- Call virtio_device_ready() before vr->vq is set, so a request on
restore can not kick the queue before DRIVER_OK (sashiko)
- v1: https://lore.kernel.org/all/20261029081317.2264887-1-harukak@zohomail.eu/
- haruka
[1] https://lore.kernel.org/all/20220405093759.1126835-1-alex.bennee@linaro.org/
Haruka Kuze (2):
rpmb: stop the routing after unregister
rpmb: add a virtio RPMB device driver
MAINTAINERS | 7 +
drivers/misc/Kconfig | 10 ++
drivers/misc/Makefile | 1 +
drivers/misc/rpmb-core.c | 14 +-
drivers/misc/virtio_rpmb.c | 286 +++++++++++++++++++++++++++++++
include/linux/rpmb.h | 4 +
include/uapi/linux/virtio_rpmb.h | 56 ++++++
7 files changed, 377 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/virtio_rpmb.c
create mode 100644 include/uapi/linux/virtio_rpmb.h
base-commit: c339f4010dea8b0d754f84ace70cd1b089878ef8
--
2.55.0
This adds a driver on top of the rpmb subsystem for virtio-rpmb devices.
Alex Bennée had an earlier virtio-rpmb driver in his RPMB series [1]
but that stalled due to the user space API.
The one that merged later has no user space API and OP-TEE routes frames
through it so this driver only needs to implement route_frames().
I added patch 1 to fix a use-after-free that I hit while testing
removing the device (OP-TEE can still route frames after driver unregisters
the rpmb device).
I tested this with UML (virtio_uml) and a vhost-user backend I wrote
for this on top of rust-vmm's vhost-device with KASAN, lockdep:
- key programming
- write counter
- single and multi block write and read
- MAC and counter failures
- max_wr_cnt
- unbinding the driver when the rpmb device is held
With OP-TEE 4.11 on QEMU virt arm64 the secure_storage example TA keeps
its objects in RPMB through the driver and an object written to in one
boot is found in the one after.
I have added myself in MAINTAINERS. I would like to maintain the driver.
- haruka
[1] https://lore.kernel.org/all/20220405093759.1126835-1-alex.bennee@linaro.org/
Haruka Kuze (2):
rpmb: stop the routing after unregister
rpmb: add a virtio RPMB device driver
MAINTAINERS | 7 +
drivers/misc/Kconfig | 10 ++
drivers/misc/Makefile | 1 +
drivers/misc/rpmb-core.c | 22 ++-
drivers/misc/virtio_rpmb.c | 294 +++++++++++++++++++++++++++++++
include/linux/rpmb.h | 4 +
include/uapi/linux/virtio_rpmb.h | 56 ++++++
7 files changed, 391 insertions(+), 3 deletions(-)
create mode 100644 drivers/misc/virtio_rpmb.c
create mode 100644 include/uapi/linux/virtio_rpmb.h
base-commit: c339f4010dea8b0d754f84ace70cd1b089878ef8
--
2.55.0
From: Sumit Garg <sumit.garg(a)oss.qualcomm.com>
As per testing the SCM backend just ignores it while OP-TEE makes
use of it to for proper book keeping purpose.
Reviewed-by: Mukesh Ojha <mukesh.ojha(a)oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha(a)oss.qualcomm.com> # Lemans
Reviewed-by: Vikash Garodia <vikash.garodia(a)oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio(a)oss.qualcomm.com>
Signed-off-by: Sumit Garg <sumit.garg(a)oss.qualcomm.com>
---
Changes in v10:
- Resent standalone, as all the earlier patches of the series are merged.
- Link to v9: https://lore.kernel.org/all/20260702115835.167602-11-sumit.garg@kernel.org/
---
drivers/media/platform/qcom/iris/iris_firmware.c | 2 +-
drivers/media/platform/qcom/venus/firmware.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
index 21f57d37da18..ed2bd0e83797 100644
--- a/drivers/media/platform/qcom/iris/iris_firmware.c
+++ b/drivers/media/platform/qcom/iris/iris_firmware.c
@@ -262,5 +262,5 @@ int iris_fw_unload(struct iris_core *core)
int iris_set_hw_state(struct iris_core *core, bool resume)
{
- return qcom_pas_set_remote_state(resume, 0);
+ return qcom_pas_set_remote_state(resume, IRIS_PAS_ID);
}
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 3a38ff985822..3c0727ea137d 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -59,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume)
int ret;
if (core->use_tz) {
- ret = qcom_pas_set_remote_state(resume, 0);
+ ret = qcom_pas_set_remote_state(resume, VENUS_PAS_ID);
if (resume && ret == -EINVAL)
ret = 0;
return ret;
---
base-commit: d135ab453a7400a34930bdda1ef4bdc8acfac80e
change-id: 20261027-pas-id-media-7cc70fc5716f
Best regards,
--
Sumit Garg <sumit.garg(a)oss.qualcomm.com>
tee_dyn_shm_alloc_helper() passes the size from TEE_IOC_SHM_ALLOC to
alloc_pages_exact(), which needs one physically contiguous block. A size
above 4 MiB (MAX_PAGE_ORDER with 4 KiB pages) is more than the page
allocator can serve, so it trips its order warning; on a panic_on_warn
kernel that is a panic.
The size comes from userspace and the request fails with -ENOMEM anyway,
so pass __GFP_NOWARN.
Fixes: abd135ba215c ("tee: optee: add optee-specific shared pool implementation")
Cc: stable(a)vger.kernel.org
Cc: lvc-project(a)linuxtesting.org
Signed-off-by: Georgiy Osokin <g.osokin(a)auroraos.dev>
---
v2: Fixes now points to abd135ba215c, the commit that introduced the
unchecked allocation; cf4441503e20 only moved the code.
v1: https://lore.kernel.org/all/20261026105209.161195-1-g.osokin@auroraos.dev/
drivers/tee/tee_shm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index daa4af1..8b117d6 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -352,7 +352,7 @@ int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align,
* and there's no need for any larger alignment.
*/
shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE,
- GFP_KERNEL | __GFP_ZERO);
+ GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
if (!shm->kaddr)
return -ENOMEM;
--
2.54.0
tee_dyn_shm_alloc_helper() passes the size from TEE_IOC_SHM_ALLOC to
alloc_pages_exact(), which needs one physically contiguous block. A size
above 4 MiB (MAX_PAGE_ORDER with 4 KiB pages) is more than the page
allocator can serve, so it trips its order warning; on a panic_on_warn
kernel that is a panic.
The size comes from userspace and the request fails with -ENOMEM anyway,
so pass __GFP_NOWARN.
Fixes: cf4441503e20 ("tee: optee: Move pool_op helper functions")
Cc: stable(a)vger.kernel.org
Cc: lvc-project(a)linuxtesting.org
Signed-off-by: Georgiy Osokin <g.osokin(a)auroraos.dev>
---
drivers/tee/tee_shm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index daa4af1..8b117d6 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -352,7 +352,7 @@ int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align,
* and there's no need for any larger alignment.
*/
shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE,
- GFP_KERNEL | __GFP_ZERO);
+ GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
if (!shm->kaddr)
return -ENOMEM;
--
2.54.0
On Qualcomm SoC based platforms, UEFI stores EFI variables within the
Replay Protected Memory Block (RPMB) located within either the UFS,
eMMC or SPI-NOR storage. The RPMB key which is one-time programmed into
the storage controller to allow authentication of the RPMB frames is
generated by and only available to the Qualcomm Trusted Execution
Environment (QTEE). Thus, only QTEE can prepare the RPMB frames which
will be accepted by the storage controller.
The legacy QSEECOM protocol used for communicating with the QTEE is
deprecated and replaced with the use-case agnostic SMCInvoke protocol
starting with the Qualcomm SM8x50 series. On platforms where the QSEECOM
protocol still works (the QSEECOM driver probes) the driver does not
support a listener interface with QTEE to enable writing of non-volatile
EFI variables (via listener requests to Linux from QTEE) to the RPMB
for UFS and eMMC storage. (Qualcomm Compute platforms with SPI-NOR storage
are an exception to this and work with QSEECOM, see the NOTE below)
Therefore on such platforms, a TEE client driver (which communicates with
QTEE via the SMCInvoke protocol implemented by the QCOMTEE driver
registered with the TEE subsystem) must be used to update such EFI variables
through the RPMB service hosted in the QTEE supplicant user-space daemon
[1] which forwards RPMB packets to the RPMB device.
This series introduces such a uefisecapp TEE client driver for the
aforementioned Qualcomm platforms which installs efi-var operations _if_
the QCOMTEE driver registers support for an object-IPC based uefisecapp
service on the TEE bus during its probe. Only new QTEE firmware versions
available at [2] provide access to the uefisecapp service via the SMCInvoke
protocol.
Thus, QCOMTEE now maintains a static list of always-available object-IPC
based secure services exposed by QTEE. These services are implemented either
within the QTEE kernel or within a pre-loaded Trusted Application (TA)
usually loaded by the bootloader. The uefisecapp TA is an example of a
preloaded TA loaded by UEFI. A static list is required since QTEE does not
yet expose any way to dynamically query and enumerate the services exposed
by it.
To facilitate object-IPC interactions from the kernel-space, this
series also introduces a tee_client_object_invoke_func() to allow
invocation of TEE objects similar to the existing tee_client_invoke_func()
API exported by the TEE subsystem which allows invocation of TEE functions.
Some suporting changes are also introduced to track and handle operations
for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
driver.
Finally and as previously mentioned, access to the object-IPC based uefisecapp
service is restricted on older QTEE firmware versions. A new QTEE firmware
release must be picked up from QArtifactory [2] for all upstream supported
Qualcomm SoCs to enable access to uefisecapp service via the TEE client
driver.
This patch series has been validated on Kodiak RB3Gen2 platform with UFS
storage by attempting to read/write EFI variables via the efivar tool [3]
after mounting the efivarfs filesystem. See [4] for an example.
NOTE: Since Compute platforms do not have a firmware running on their SPI-NOR
storage controller which must be programmed with a RPMB key, QTEE has a
SPI-NOR driver which holds the key, and so the QSEECOM driver can be used
for updating EFI variables on these platforms because QTEE never makes a
listener request to Linux (QTEE doesn't need the Linux SPI-NOR driver).
Such platforms are outlined in the following static list [5].
Merge Strategy:
This patch series could either be taken from the OP-TEE tree or the
QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
all except the uefisecapp TEE client driver patch in this series make
changes relevant to the TEE subsystem. It would be great if the QCOM soc
tree maintainers can Ack the uefisecapp driver patch.
[1] https://github.com/qualcomm/minkipc
[2] https://shorturl.at/zQU07
[3] https://github.com/rhboot/efivar
[4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_var…
[5] https://elixir.bootlin.com/linux/v7.3-rc5/source/drivers/firmware/qcom/qcom…
Signed-off-by: Harshal Dev <harshal.dev(a)oss.qualcomm.com>
---
Changes in v5:
- Fixed comment in qcomtee_object.h to drop '+'.
- Removed duplicate function doc for tee_generate_uuid_v5() in .c file.
- Fixed qtee_register_services() doc.
- Dropped unused QTEE_UUID_NS_NAME_SIZE macro.
- Optimized qcomtee_uefi_query_variable_info() to drop redundant stack variables.
- Migrated to block comment format everywhere in qcom_tee_uefisecapp.c.
- Drop comments which highlight obvious stuff in qcomtee_uefisecapp_probe().
- Collected Reviewed-by tags from Amir.
- Link to v4: https://lore.kernel.org/r/20261006-qcom_uefisecapp_migrate_qcomtee-v4-0-bf1…
Changes in v4:
- Fixed kernel test robot warnings with gcc v16.1.0 [-Wvla-larger-than].
- Update parameter docs for qcomtee_object_invoke() and param_to/from_args().
- Split the defconfig change enabling the UefiSecApp TEE driver into a separate
commit.
- Use pr_debug() instead of pr_err() when QTEE says it does not implement a
service being enumerated.
- Re-name qtee_enumerate_service*() functions to qtee_register_service*().
- Collected Reviewed/Acked-by tags from Sumit.
- Link to v3: https://lore.kernel.org/r/20261001-qcom_uefisecapp_migrate_qcomtee-v3-0-13d…
Changes in v3:
- Updated the cover letter and commit messages to highlight the following:
1. Only QTEE has the ability to prepare RPMB frames since it generates and
holds the RPMB key.
2. The QSEECOM protocol is deprecated on new platforms and so this series
migrates the uefisecapp to SMCInvoke which is a use-case agnostic, transport
focused and easier to maintain protocol.
- Use single if statement to update both flags and addr/uaddr.
- Remove redundant use of new error variable in qcomtee_get_qtee_feature_list().
- Minor fixes such as concise error prints and use of better error codes.
- Fix a double free in qtee_enumerate_service().
- Re-org the qcomtee_enumerate_services() function to re-use the same oic and
client_env object.
- Remove depends on !QCOM_QSEECOM_UEFISECAPP from Kconfig since both drivers
can co-exist even on platforms that support both QSEECOM and SMCInvoke protocols.
- Update the Kconfig description to better help the user understand when to enable
the TEE based uefisecapp driver.
- Removed qcom_tee_uefisecapp.h file and inline the header in qcom_tee_uefisecapp.c
- Rebased patch series onto the latest linux next tag: next-20260930.
- Link to v2: https://lore.kernel.org/r/20260722-qcom_uefisecapp_migrate_qcomtee-v2-0-b8a…
Changes in v2:
- Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
- Introduce enum tee_object_invoke_origin to check the context of object invocation.
- Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f65…
---
Amirreza Zarrabi (2):
tee: Add kernel client object invoke helper
tee: qcomtee: Allow object invokes from kernel clients
Harshal Dev (5):
tee: qcomtee: Track the object invocation context
tee: Export uuidv5 generation for TEE backends
tee: qcomtee: Add support for registering QTEE services on TEE bus
firmware: qcom: Add support for TEE based EFI-var client driver
arm64: defconfig: Enable UefiSecApp TEE client driver for Qualcomm SoCs
MAINTAINERS | 6 +
arch/arm64/configs/defconfig | 1 +
drivers/firmware/qcom/Kconfig | 31 ++
drivers/firmware/qcom/Makefile | 1 +
drivers/firmware/qcom/qcom_tee_uefisecapp.c | 644 ++++++++++++++++++++++++++++
drivers/tee/qcomtee/call.c | 210 ++++++++-
drivers/tee/qcomtee/core.c | 9 +-
drivers/tee/qcomtee/qcomtee.h | 10 +
drivers/tee/qcomtee/qcomtee_msg.h | 1 +
drivers/tee/qcomtee/qcomtee_object.h | 16 +-
drivers/tee/tee_core.c | 34 +-
include/linux/tee_core.h | 23 +-
include/linux/tee_drv.h | 18 +-
13 files changed, 959 insertions(+), 45 deletions(-)
---
base-commit: 6c2cb8b8b843d216ab549b678a0d8831c43153e0
change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014
Best regards,
--
Harshal Dev <harshal.dev(a)oss.qualcomm.com>
From: Christian Stefan Kövér-Draxl <ckoever(a)outlook.de>
The X98Q's vendor BL32 runs OP-TEE 3.8 and reports sec_caps 0x5, that is
HAVE_RESERVED_SHM | DYNAMIC_SHM, with neither UNREGISTERED_SHM nor
RPC_ARG.
For that combination optee_probe() picks the dynamic pool and sets
OPTEE_SHM_ARG_ALLOC_PRIV, so every message argument is an unregistered
private page passed to secure world by physical address via
OPTEE_SMC_CALL_WITH_ARG. This OP-TEE will not accept that: every call
comes back OPTEE_SMC_RETURN_EBADADDR (4), which optee_open_session()
converts into TEEC_ERROR_COMMUNICATION / TEEC_ORIGIN_COMMS. The result
is that no session can be opened at all - not to the Amlogic firmware
loading PTA the video decoder needs, and not to any built-in PTA either.
Registering memory works fine, and HAVE_RESERVED_SHM is set, so the
existing static pool path is usable. Add optee.no_dyn_shm to select it.
With the reserved pool the device enumeration PTA opens cleanly and the
system PTA answers with its own ACCESS_DENIED, so the ABI is healthy.
The driver arguably should not use unregistered arguments unless secure
world advertised UNREGISTERED_SHM; a parameter keeps the change local
until that is confirmed upstream.
Signed-off-by: Christian Stefan Kövér-Draxl <ckoever(a)outlook.de>
---
Tool use (Documentation/process/generated-content.rst):
This work was done with the help of an AI coding assistant, Claude
(Anthropic), used through Claude Code over many sessions. It did a large
part of the hands-on work: it read the vendor kernel and the firmware
interfaces, probed registers on the board, drafted the code and the
changelogs, and ran the builds, checkpatch, dt_binding_check and the
tests on the hardware. I directed the work, reviewed every change and
the final patches, and take responsibility for them. There is no single
prompt to quote; the sessions were of the form "find out why X fails on
this board, fix it, test it on the box".
Tested on an Amediatech X98Q TV box (Amlogic S905W2, S4 family, 2 GiB),
vendor U-Boot and BL31/OP-TEE, Linux 7.3 plus this work.
drivers/tee/optee/smc_abi.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 51624443359b..1824aead78a6 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -34,6 +34,11 @@
#define CREATE_TRACE_POINTS
#include "optee_trace.h"
+static bool optee_no_dyn_shm;
+module_param_named(no_dyn_shm, optee_no_dyn_shm, bool, 0444);
+MODULE_PARM_DESC(no_dyn_shm,
+ "Ignore the secure world's dynamic shared memory capability and use the reserved pool instead");
+
/*
* This file implement the SMC ABI used when communicating with secure world
* OP-TEE OS via raw SMCs.
@@ -1770,7 +1775,7 @@ static int optee_probe(struct platform_device *pdev)
/*
* Try to use dynamic shared memory if possible
*/
- if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
+ if ((sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) && !optee_no_dyn_shm) {
/*
* If we have OPTEE_SMC_SEC_CAP_RPC_ARG we can ask
* optee_get_msg_arg() to pre-register (by having
base-commit: 7be4bc52fd9e0e55dc9a2e0232b89427d2c4b614
--
2.56.0
register_shm_helper() sizes shm->pages from the length passed to
TEE_IOC_SHM_REGISTER and allocates it with kzalloc_objs(). A length above
2 GiB makes the array larger than the page allocator can serve in one
block (MAX_PAGE_ORDER), so it trips its order warning; on a panic_on_warn
kernel that is a panic.
The size comes from userspace and the request fails with -ENOMEM anyway,
so pass __GFP_NOWARN. kvzalloc_objs() would not help since kvmalloc
warns above INT_MAX as well.
Fixes: 033ddf12bcf5 ("tee: add register user memory")
Cc: stable(a)vger.kernel.org
Cc: lvc-project(a)linuxtesting.org
Signed-off-by: Georgiy Osokin <g.osokin(a)auroraos.dev>
---
drivers/tee/tee_shm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 6742b35..d539988 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -438,7 +438,8 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
goto err_free_shm;
}
- shm->pages = kzalloc_objs(*shm->pages, num_pages);
+ shm->pages = kzalloc_objs(*shm->pages, num_pages,
+ GFP_KERNEL | __GFP_NOWARN);
if (!shm->pages) {
ret = ERR_PTR(-ENOMEM);
goto err_free_shm;
base-commit: 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e
--
2.54.0