lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <58767D4C-505C-424B-AD08-C042BAA3FC34@collabora.com>
Date: Mon, 9 Feb 2026 11:16:38 -0300
From: Daniel Almeida <daniel.almeida@...labora.com>
To: Liviu Dudau <liviu.dudau@....com>
Cc: Will Deacon <will@...nel.org>, Robin Murphy <robin.murphy@....com>,
 Joerg Roedel <joro@...tes.org>, Rob Clark <robin.clark@....qualcomm.com>,
 Boris Brezillon <boris.brezillon@...labora.com>,
 Steven Price <steven.price@....com>, linux-arm-kernel@...ts.infradead.org,
 iommu@...ts.linux.dev, dri-devel@...ts.freedesktop.org,
 linux-kernel@...r.kernel.org, Karunika Choo <karunika.choo@....com>,
 Liviu Dudau <liviu@...au.co.uk>, Alice Ryhl <aliceryhl@...gle.com>,
 rust-for-linux <rust-for-linux@...r.kernel.org>
Subject: Re: [RFC PATCH] iommu/io-pgtable: Add support for Arm Mali v10+ GPUs page table format




> On 9 Feb 2026, at 08:27, Liviu Dudau <liviu.dudau@....com> wrote:
> 
> From: Liviu Dudau <liviu@...au.co.uk>
> 
> The Arm Mali v10+ GPU drivers have been (ab)using the ARM_64_LPAE_S1
> format as they are mostly compatible with it and some of the gaps
> left in the code to allow for ARM_MALI_LPAE format (pre-v10 GPUs)
> is helping to paper over differences. In preparation for adding support
> for changes introduced in v15 GPUs, add a format specific for modern
> Mali GPUs.
> 
> Signed-off-by: Liviu Dudau <liviu.dudau@....com>
> ---
> 
> This patch is trying to gauge interest in adding proper support for Arm Mali
> CSF GPUs via the simple approach of extending the generic Arm page table code
> to add support for the PTE format of the GPUs. In order to test the changes
> I've decided to add the phba bits to the arm_lpae_s1_cfg struct to validate
> the allocation and setup of the page table entries, but in the end I'm
> targetting the specific arm_mali_csf_cfg structure that will support
> the GPUs PTEs.
> 
> I'm interested to learn if this approach is considered sane and what I need to
> pay attention to when adding a new struct to the io_pgtable_cfg union. The patch
> is intentionally not complete with all the changes that switching to the new
> struct will entail as I didn't wanted to be dragged into a full code review, but
> I can add them if wanted.
> 
> 
> Best regards,
> Liviu
> 
> ---
> drivers/iommu/io-pgtable-arm.c | 161 ++++++++++++++++++++++++++++++++-
> drivers/iommu/io-pgtable.c     |   1 +
> include/linux/io-pgtable.h     |  18 ++++
> 3 files changed, 179 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
> index 05d63fe92e436..48aea598ab0c9 100644
> --- a/drivers/iommu/io-pgtable-arm.c
> +++ b/drivers/iommu/io-pgtable-arm.c
> @@ -482,6 +482,7 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
>    arm_lpae_iopte pte;
> 
>    if (data->iop.fmt == ARM_64_LPAE_S1 ||
> +        data->iop.fmt == ARM_MALI_CSF ||
>        data->iop.fmt == ARM_32_LPAE_S1) {
>        pte = ARM_LPAE_PTE_nG;
>        if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
> @@ -569,6 +570,8 @@ static int arm_lpae_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
>        return -EINVAL;
> 
>    prot = arm_lpae_prot_to_pte(data, iommu_prot);
> +    if (data->iop.fmt == ARM_MALI_CSF)
> +        prot |= cfg->arm_lpae_s1_cfg.pbha;
>    ret = __arm_lpae_map(data, iova, paddr, pgsize, pgcount, prot, lvl,
>                 ptep, gfp, mapped);
>    /*
> @@ -864,7 +867,8 @@ static int arm_lpae_read_and_clear_dirty(struct io_pgtable_ops *ops,
>        return -EINVAL;
>    if (WARN_ON((iova + size - 1) & ~(BIT(cfg->ias) - 1)))
>        return -EINVAL;
> -    if (data->iop.fmt != ARM_64_LPAE_S1)
> +    if (data->iop.fmt != ARM_64_LPAE_S1 ||
> +        data->iop.fmt != ARM_MALI_CSF)
>        return -EINVAL;
> 
>    return __arm_lpae_iopte_walk(data, &walk_data, ptep, lvl);
> @@ -1236,6 +1240,155 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
>    return NULL;
> }
> 
> +static struct io_pgtable *
> +arm_mali_csf_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
> +{
> +    unsigned int max_addr_bits = 48;
> +    unsigned long granule, page_sizes;
> +    struct arm_lpae_io_pgtable *data;
> +    typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr;
> +    int levels, va_bits, pg_shift;
> +    u64 reg;
> +
> +    if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_TTBR1 |
> +                IO_PGTABLE_QUIRK_NO_WARN))
> +        return NULL;
> +
> +    if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K)))
> +        return NULL;
> +
> +    if (cfg->pgsize_bitmap & PAGE_SIZE)
> +        granule = PAGE_SIZE;
> +    else if (cfg->pgsize_bitmap & ~PAGE_MASK)
> +        granule = 1UL << __fls(cfg->pgsize_bitmap & ~PAGE_MASK);
> +    else if (cfg->pgsize_bitmap & PAGE_MASK)
> +        granule = 1UL << __ffs(cfg->pgsize_bitmap & PAGE_MASK);
> +    else
> +        granule = 0;
> +
> +    switch (granule) {
> +    case SZ_4K:
> +        page_sizes = (SZ_4K | SZ_2M | SZ_1G);
> +        break;
> +    case SZ_16K:
> +        page_sizes = (SZ_16K | SZ_32M | SZ_64G);
> +        break;
> +    default:
> +        page_sizes = 0;
> +    }
> +
> +    cfg->pgsize_bitmap &= page_sizes;
> +    cfg->ias = min(cfg->ias, max_addr_bits);
> +    cfg->oas = min(cfg->oas, max_addr_bits);
> +
> +    data = kmalloc(sizeof(*data), GFP_KERNEL);
> +    if (!data)
> +        return NULL;
> +
> +    pg_shift = __ffs(cfg->pgsize_bitmap);
> +    data->bits_per_level = pg_shift - ilog2(sizeof(arm_lpae_iopte));
> +
> +    va_bits = cfg->ias - pg_shift;
> +    levels = DIV_ROUND_UP(va_bits, data->bits_per_level);
> +    data->start_level = ARM_LPAE_MAX_LEVELS - levels;
> +
> +    /* Calculate the actual size of our pgd (without concatenation) */
> +    data->pgd_bits = va_bits - (data->bits_per_level * (levels - 1));
> +
> +    data->iop.ops = (struct io_pgtable_ops) {
> +        .map_pages    = arm_lpae_map_pages,
> +        .unmap_pages    = arm_lpae_unmap_pages,
> +        .iova_to_phys    = arm_lpae_iova_to_phys,
> +        .read_and_clear_dirty = arm_lpae_read_and_clear_dirty,
> +        .pgtable_walk    = arm_lpae_pgtable_walk,
> +    };
> +
> +    /* TCR */
> +    if (cfg->coherent_walk) {
> +        tcr->sh = ARM_LPAE_TCR_SH_IS;
> +        tcr->irgn = ARM_LPAE_TCR_RGN_WBWA;
> +        tcr->orgn = ARM_LPAE_TCR_RGN_WBWA;
> +        if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_OUTER_WBWA)
> +            goto out_free_data;
> +    } else {
> +        tcr->sh = ARM_LPAE_TCR_SH_OS;
> +        tcr->irgn = ARM_LPAE_TCR_RGN_NC;
> +        if (!(cfg->quirks & IO_PGTABLE_QUIRK_ARM_OUTER_WBWA))
> +            tcr->orgn = ARM_LPAE_TCR_RGN_NC;
> +        else
> +            tcr->orgn = ARM_LPAE_TCR_RGN_WBWA;
> +    }
> +
> +    switch (ARM_LPAE_GRANULE(data)) {
> +    case SZ_4K:
> +        tcr->tg = ARM_LPAE_TCR_TG0_4K;
> +        break;
> +    case SZ_16K:
> +        tcr->tg = ARM_LPAE_TCR_TG0_16K;
> +        break;
> +    case SZ_64K:
> +        tcr->tg = ARM_LPAE_TCR_TG0_64K;
> +        break;
> +    }
> +
> +    switch (cfg->oas) {
> +    case 32:
> +        tcr->ips = ARM_LPAE_TCR_PS_32_BIT;
> +        break;
> +    case 36:
> +        tcr->ips = ARM_LPAE_TCR_PS_36_BIT;
> +        break;
> +    case 40:
> +        tcr->ips = ARM_LPAE_TCR_PS_40_BIT;
> +        break;
> +    case 42:
> +        tcr->ips = ARM_LPAE_TCR_PS_42_BIT;
> +        break;
> +    case 44:
> +        tcr->ips = ARM_LPAE_TCR_PS_44_BIT;
> +        break;
> +    case 48:
> +        tcr->ips = ARM_LPAE_TCR_PS_48_BIT;
> +        break;
> +    case 52:
> +        tcr->ips = ARM_LPAE_TCR_PS_52_BIT;
> +        break;
> +    default:
> +        goto out_free_data;
> +    }
> +
> +    tcr->tsz = 64ULL - cfg->ias;
> +
> +    /* MAIRs */
> +    reg = (ARM_LPAE_MAIR_ATTR_NC
> +           << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_NC)) |
> +          (ARM_LPAE_MAIR_ATTR_WBRWA
> +           << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
> +          (ARM_LPAE_MAIR_ATTR_DEVICE
> +           << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)) |
> +          (ARM_LPAE_MAIR_ATTR_INC_OWBRWA
> +           << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE));
> +
> +    cfg->arm_lpae_s1_cfg.mair = reg;
> +
> +    /* Looking good; allocate a pgd */
> +    data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
> +                       GFP_KERNEL, cfg, cookie);
> +    if (!data->pgd)
> +        goto out_free_data;
> +
> +    /* Ensure the empty pgd is visible before any actual TTBR write */
> +    wmb();
> +
> +    /* TTBR */
> +    cfg->arm_lpae_s1_cfg.ttbr = virt_to_phys(data->pgd);
> +    return &data->iop;
> +
> +out_free_data:
> +    kfree(data);
> +    return NULL;
> +}
> +
> struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = {
>    .caps    = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
>    .alloc    = arm_64_lpae_alloc_pgtable_s1,
> @@ -1265,3 +1418,9 @@ struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = {
>    .alloc    = arm_mali_lpae_alloc_pgtable,
>    .free    = arm_lpae_free_pgtable,
> };
> +
> +struct io_pgtable_init_fns io_pgtable_arm_mali_csf_init_fns = {
> +    .caps    = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
> +    .alloc    = arm_mali_csf_alloc_pgtable,
> +    .free    = arm_lpae_free_pgtable,
> +};
> diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
> index 843fec8e8a511..1f43f898a8121 100644
> --- a/drivers/iommu/io-pgtable.c
> +++ b/drivers/iommu/io-pgtable.c
> @@ -20,6 +20,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = {
>    [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns,
>    [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns,
>    [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns,
> +    [ARM_MALI_CSF] = &io_pgtable_arm_mali_csf_init_fns,
> #endif
> #ifdef CONFIG_IOMMU_IO_PGTABLE_DART
>    [APPLE_DART] = &io_pgtable_apple_dart_init_fns,
> diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
> index 7a1516011ccf7..fc9776f71a963 100644
> --- a/include/linux/io-pgtable.h
> +++ b/include/linux/io-pgtable.h
> @@ -17,6 +17,7 @@ enum io_pgtable_fmt {
>    ARM_MALI_LPAE,
>    APPLE_DART,
>    APPLE_DART2,
> +    ARM_MALI_CSF,
>    IO_PGTABLE_NUM_FMTS,
> };
> 
> @@ -148,6 +149,8 @@ struct io_pgtable_cfg {
>                u32    tsz:6;
>            }    tcr;
>            u64    mair;
> +            /* ToDo: remove this when switching to arm_mali_csf_cfg struct */
> +            u64    pbha;
>        } arm_lpae_s1_cfg;
> 
>        struct {
> @@ -175,6 +178,20 @@ struct io_pgtable_cfg {
>            u64    memattr;
>        } arm_mali_lpae_cfg;
> 
> +        /* ToDo: switch to this structure for Mali CSF GPUs
> +          struct {
> +            u64    transtab;
> +            struct {
> +                u32    pbha:4;
> +                u32    ra:1;
> +                u32    sh:2;
> +                u32    memattr:2;
> +                u32    mode:4;
> +            } transcfg;
> +            u64 memattr;
> +        } arm_mali_csf_cfg;
> +        */
> +
>        struct {
>            u64 ttbr[4];
>            u32 n_ttbrs;
> @@ -320,6 +337,7 @@ extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns;
> +extern struct io_pgtable_init_fns io_pgtable_arm_mali_csf_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_amd_iommu_v1_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_amd_iommu_v2_init_fns;
> extern struct io_pgtable_init_fns io_pgtable_apple_dart_init_fns;
> --
> 2.52.0
> 

+cc Alice Ryhl and the rust-for-linux mailing list in light of the Rust abstractions for this component

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ