* [PATCH 0/2] irqchip/gic-v3-its: Mark ITS tables as decrypted
@ 2024-09-05 9:17 Steven Price
2024-09-05 9:17 ` [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor Steven Price
2024-09-05 9:17 ` [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment Steven Price
0 siblings, 2 replies; 8+ messages in thread
From: Steven Price @ 2024-09-05 9:17 UTC (permalink / raw)
To: Marc Zyngier, Thomas Gleixner
Cc: Steven Price, linux-arm-kernel, linux-kernel, Will Deacon,
Suzuki K Poulose
These two patches are taken from the larger series to support running
Linux as a realm guest in CCA[1]. They add support to the GIC for
allocating the ITS pages such that they are decrypted so that the host
can access then for emulation purposes.
Note that there are likely to be future changes to make this more
configurable in the future, as it's possible that in a future
configuration a protected component within the realm could take on the
emulation responsibilities ('Planes support')[2]. But this is a good
building block for the future.
Sorry for the delay in posting this as a separate series!
[1] https://lore.kernel.org/r/20240819131924.372366-1-steven.price%40arm.com
[2] https://lore.kernel.org/r/beff9162-e1ba-4f72-91ea-329eaed48dbc%40arm.com
Steven Price (2):
irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor
irqchip/gic-v3-its: Rely on genpool alignment
drivers/irqchip/irq-gic-v3-its.c | 142 +++++++++++++++++++++++++------
1 file changed, 117 insertions(+), 25 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor 2024-09-05 9:17 [PATCH 0/2] irqchip/gic-v3-its: Mark ITS tables as decrypted Steven Price @ 2024-09-05 9:17 ` Steven Price 2024-09-06 16:36 ` Catalin Marinas 2024-09-09 3:47 ` Michael Kelley 2024-09-05 9:17 ` [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment Steven Price 1 sibling, 2 replies; 8+ messages in thread From: Steven Price @ 2024-09-05 9:17 UTC (permalink / raw) To: Marc Zyngier, Thomas Gleixner Cc: Steven Price, linux-arm-kernel, linux-kernel, Will Deacon, Suzuki K Poulose Within a realm guest the ITS is emulated by the host. This means the allocations must have been made available to the host by a call to set_memory_decrypted(). Introduce an allocation function which performs this extra call. For the ITT use a custom genpool-based allocator that calls set_memory_decrypted() for each page allocated, but then suballocates the size needed for each ITT. Note that there is no mechanism implemented to return pages from the genpool, but it is unlikely the peak number of devices will so much larger than the normal level - so this isn't expected to be an issue. Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Tested-by: Will Deacon <will@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Steven Price <steven.price@arm.com> --- drivers/irqchip/irq-gic-v3-its.c | 139 ++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 23 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 9b34596b3542..557214c774c3 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -12,12 +12,14 @@ #include <linux/crash_dump.h> #include <linux/delay.h> #include <linux/efi.h> +#include <linux/genalloc.h> #include <linux/interrupt.h> #include <linux/iommu.h> #include <linux/iopoll.h> #include <linux/irqdomain.h> #include <linux/list.h> #include <linux/log2.h> +#include <linux/mem_encrypt.h> #include <linux/memblock.h> #include <linux/mm.h> #include <linux/msi.h> @@ -27,6 +29,7 @@ #include <linux/of_pci.h> #include <linux/of_platform.h> #include <linux/percpu.h> +#include <linux/set_memory.h> #include <linux/slab.h> #include <linux/syscore_ops.h> @@ -164,6 +167,7 @@ struct its_device { struct its_node *its; struct event_lpi_map event_map; void *itt; + u32 itt_sz; u32 nr_ites; u32 device_id; bool shared; @@ -199,6 +203,81 @@ static DEFINE_IDA(its_vpeid_ida); #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) +static struct page *its_alloc_pages_node(int node, gfp_t gfp, + unsigned int order) +{ + struct page *page; + int ret = 0; + + page = alloc_pages_node(node, gfp, order); + + if (!page) + return NULL; + + ret = set_memory_decrypted((unsigned long)page_address(page), + 1 << order); + if (WARN_ON(ret)) + return NULL; + + return page; +} + +static struct page *its_alloc_pages(gfp_t gfp, unsigned int order) +{ + return its_alloc_pages_node(NUMA_NO_NODE, gfp, order); +} + +static void its_free_pages(void *addr, unsigned int order) +{ + if (WARN_ON(set_memory_encrypted((unsigned long)addr, 1 << order))) + return; + free_pages((unsigned long)addr, order); +} + +static struct gen_pool *itt_pool; + +static void *itt_alloc_pool(int node, int size) +{ + unsigned long addr; + struct page *page; + + if (size >= PAGE_SIZE) { + page = its_alloc_pages_node(node, + GFP_KERNEL | __GFP_ZERO, + get_order(size)); + + return page_address(page); + } + + do { + addr = gen_pool_alloc(itt_pool, size); + if (addr) + break; + + page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 1); + if (!page) + break; + + gen_pool_add(itt_pool, (unsigned long)page_address(page), + PAGE_SIZE, node); + } while (!addr); + + return (void *)addr; +} + +static void itt_free_pool(void *addr, int size) +{ + if (!addr) + return; + + if (size >= PAGE_SIZE) { + its_free_pages(addr, get_order(size)); + return; + } + + gen_pool_free(itt_pool, (unsigned long)addr, size); +} + /* * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we * always have vSGIs mapped. @@ -2187,7 +2266,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) { struct page *prop_page; - prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ)); + prop_page = its_alloc_pages(gfp_flags, + get_order(LPI_PROPBASE_SZ)); if (!prop_page) return NULL; @@ -2198,8 +2278,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) static void its_free_prop_table(struct page *prop_page) { - free_pages((unsigned long)page_address(prop_page), - get_order(LPI_PROPBASE_SZ)); + its_free_pages(page_address(prop_page), + get_order(LPI_PROPBASE_SZ)); } static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size) @@ -2321,7 +2401,8 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, order = get_order(GITS_BASER_PAGES_MAX * psz); } - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order); + page = its_alloc_pages_node(its->numa_node, + GFP_KERNEL | __GFP_ZERO, order); if (!page) return -ENOMEM; @@ -2334,7 +2415,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, /* 52bit PA is supported only when PageSize=64K */ if (psz != SZ_64K) { pr_err("ITS: no 52bit PA support when psz=%d\n", psz); - free_pages((unsigned long)base, order); + its_free_pages(base, order); return -ENXIO; } @@ -2390,7 +2471,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", &its->phys_base, its_base_type_string[type], val, tmp); - free_pages((unsigned long)base, order); + its_free_pages(base, order); return -ENXIO; } @@ -2529,8 +2610,8 @@ static void its_free_tables(struct its_node *its) for (i = 0; i < GITS_BASER_NR_REGS; i++) { if (its->tables[i].base) { - free_pages((unsigned long)its->tables[i].base, - its->tables[i].order); + its_free_pages(its->tables[i].base, + its->tables[i].order); its->tables[i].base = NULL; } } @@ -2796,7 +2877,8 @@ static bool allocate_vpe_l2_table(int cpu, u32 id) /* Allocate memory for 2nd level table */ if (!table[idx]) { - page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz)); + page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, + get_order(psz)); if (!page) return false; @@ -2915,7 +2997,8 @@ static int allocate_vpe_l1_table(void) pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n", np, npg, psz, epp, esz); - page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE)); + page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, + get_order(np * PAGE_SIZE)); if (!page) return -ENOMEM; @@ -2961,8 +3044,8 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) { struct page *pend_page; - pend_page = alloc_pages(gfp_flags | __GFP_ZERO, - get_order(LPI_PENDBASE_SZ)); + pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, + get_order(LPI_PENDBASE_SZ)); if (!pend_page) return NULL; @@ -2974,7 +3057,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) static void its_free_pending_table(struct page *pt) { - free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); + its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ)); } /* @@ -3309,8 +3392,9 @@ static bool its_alloc_table_entry(struct its_node *its, /* Allocate memory for 2nd level table */ if (!table[idx]) { - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, - get_order(baser->psz)); + page = its_alloc_pages_node(its->numa_node, + GFP_KERNEL | __GFP_ZERO, + get_order(baser->psz)); if (!page) return false; @@ -3405,7 +3489,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, if (WARN_ON(!is_power_of_2(nvecs))) nvecs = roundup_pow_of_two(nvecs); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); /* * Even if the device wants a single LPI, the ITT must be * sized as a power of two (and you need at least one bit...). @@ -3413,7 +3496,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, nr_ites = max(2, nvecs); sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; - itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); + + itt = itt_alloc_pool(its->numa_node, sz); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (alloc_lpis) { lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis); if (lpi_map) @@ -3425,9 +3512,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, lpi_base = 0; } - if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { + if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { kfree(dev); - kfree(itt); + itt_free_pool(itt, sz); bitmap_free(lpi_map); kfree(col_map); return NULL; @@ -3437,6 +3524,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, dev->its = its; dev->itt = itt; + dev->itt_sz = sz; dev->nr_ites = nr_ites; dev->event_map.lpi_map = lpi_map; dev->event_map.col_map = col_map; @@ -3464,7 +3552,7 @@ static void its_free_device(struct its_device *its_dev) list_del(&its_dev->entry); raw_spin_unlock_irqrestore(&its_dev->its->lock, flags); kfree(its_dev->event_map.col_map); - kfree(its_dev->itt); + itt_free_pool(its_dev->itt, its_dev->itt_sz); kfree(its_dev); } @@ -5112,8 +5200,9 @@ static int __init its_probe_one(struct its_node *its) } } - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, - get_order(ITS_CMD_QUEUE_SZ)); + page = its_alloc_pages_node(its->numa_node, + GFP_KERNEL | __GFP_ZERO, + get_order(ITS_CMD_QUEUE_SZ)); if (!page) { err = -ENOMEM; goto out_unmap_sgir; @@ -5177,7 +5266,7 @@ static int __init its_probe_one(struct its_node *its) out_free_tables: its_free_tables(its); out_free_cmd: - free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); + its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); out_unmap_sgir: if (its->sgir_base) iounmap(its->sgir_base); @@ -5663,6 +5752,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, bool has_v4_1 = false; int err; + itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1); + if (!itt_pool) + return -ENOMEM; + gic_rdists = rdists; lpi_prop_prio = irq_prio; -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor 2024-09-05 9:17 ` [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor Steven Price @ 2024-09-06 16:36 ` Catalin Marinas 2024-09-09 3:47 ` Michael Kelley 1 sibling, 0 replies; 8+ messages in thread From: Catalin Marinas @ 2024-09-06 16:36 UTC (permalink / raw) To: Steven Price Cc: Marc Zyngier, Thomas Gleixner, linux-arm-kernel, linux-kernel, Will Deacon, Suzuki K Poulose On Thu, Sep 05, 2024 at 10:17:37AM +0100, Steven Price wrote: > +static struct page *its_alloc_pages_node(int node, gfp_t gfp, > + unsigned int order) > +{ > + struct page *page; > + int ret = 0; > + > + page = alloc_pages_node(node, gfp, order); > + > + if (!page) > + return NULL; > + > + ret = set_memory_decrypted((unsigned long)page_address(page), > + 1 << order); > + if (WARN_ON(ret)) > + return NULL; I think we discussed this but forgot the details. If set_memory_decrypted() failed, I guess it's not safe to free the page back as we don't know the state it is in. It might be worth adding a comment if you respin for other reasons. > +static void *itt_alloc_pool(int node, int size) > +{ > + unsigned long addr; > + struct page *page; > + > + if (size >= PAGE_SIZE) { > + page = its_alloc_pages_node(node, > + GFP_KERNEL | __GFP_ZERO, > + get_order(size)); > + > + return page_address(page); > + } Since its_alloc_pages_node() can return NULL, we should check for this as page_address() would not be valid. Otherwise the patch looks fine: Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor 2024-09-05 9:17 ` [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor Steven Price 2024-09-06 16:36 ` Catalin Marinas @ 2024-09-09 3:47 ` Michael Kelley 2024-10-02 13:43 ` Thomas Gleixner 1 sibling, 1 reply; 8+ messages in thread From: Michael Kelley @ 2024-09-09 3:47 UTC (permalink / raw) To: Steven Price, Marc Zyngier, Thomas Gleixner Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Will Deacon, Suzuki K Poulose From: Steven Price <steven.price@arm.com> Sent: Thursday, September 5, 2024 2:18 AM > > Within a realm guest the ITS is emulated by the host. This means the > allocations must have been made available to the host by a call to > set_memory_decrypted(). Introduce an allocation function which performs > this extra call. > > For the ITT use a custom genpool-based allocator that calls > set_memory_decrypted() for each page allocated, but then suballocates > the size needed for each ITT. Note that there is no mechanism > implemented to return pages from the genpool, but it is unlikely the > peak number of devices will so much larger than the normal level - so > this isn't expected to be an issue. > > Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com> > Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> > Tested-by: Will Deacon <will@kernel.org> > Reviewed-by: Marc Zyngier <maz@kernel.org> > Signed-off-by: Steven Price <steven.price@arm.com> > --- > drivers/irqchip/irq-gic-v3-its.c | 139 ++++++++++++++++++++++++++----- > 1 file changed, 116 insertions(+), 23 deletions(-) > > diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c > index 9b34596b3542..557214c774c3 100644 > --- a/drivers/irqchip/irq-gic-v3-its.c > +++ b/drivers/irqchip/irq-gic-v3-its.c > @@ -12,12 +12,14 @@ > #include <linux/crash_dump.h> > #include <linux/delay.h> > #include <linux/efi.h> > +#include <linux/genalloc.h> > #include <linux/interrupt.h> > #include <linux/iommu.h> > #include <linux/iopoll.h> > #include <linux/irqdomain.h> > #include <linux/list.h> > #include <linux/log2.h> > +#include <linux/mem_encrypt.h> > #include <linux/memblock.h> > #include <linux/mm.h> > #include <linux/msi.h> > @@ -27,6 +29,7 @@ > #include <linux/of_pci.h> > #include <linux/of_platform.h> > #include <linux/percpu.h> > +#include <linux/set_memory.h> > #include <linux/slab.h> > #include <linux/syscore_ops.h> > > @@ -164,6 +167,7 @@ struct its_device { > struct its_node *its; > struct event_lpi_map event_map; > void *itt; > + u32 itt_sz; > u32 nr_ites; > u32 device_id; > bool shared; > @@ -199,6 +203,81 @@ static DEFINE_IDA(its_vpeid_ida); > #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) > #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) > > +static struct page *its_alloc_pages_node(int node, gfp_t gfp, > + unsigned int order) > +{ > + struct page *page; > + int ret = 0; > + > + page = alloc_pages_node(node, gfp, order); > + > + if (!page) > + return NULL; > + > + ret = set_memory_decrypted((unsigned long)page_address(page), > + 1 << order); > + if (WARN_ON(ret)) On the x86 side, the WARN is done in the implementation of set_memory_decrypted()/encrypted() so that each call site doesn't need to do the WARN. Each call site must only leak the memory if the return value indicates other than success. There are call sites in architecture neutral code (such as for swiotlb and DMA direct) that expect the WARN is in set_memory_decrypted()/encrypted(). To recap a previous discussion, we want the WARN for notification, but also so the most security-conscious users can set kernel.panic_on_warn=1 to stop further processing if there are problems in the decryption/encryption operation. > + return NULL; > + > + return page; > +} > + > +static struct page *its_alloc_pages(gfp_t gfp, unsigned int order) > +{ > + return its_alloc_pages_node(NUMA_NO_NODE, gfp, order); > +} > + > +static void its_free_pages(void *addr, unsigned int order) > +{ > + if (WARN_ON(set_memory_encrypted((unsigned long)addr, 1 << order))) Same here. Michael > + return; > + free_pages((unsigned long)addr, order); > +} > + > +static struct gen_pool *itt_pool; > + > +static void *itt_alloc_pool(int node, int size) > +{ > + unsigned long addr; > + struct page *page; > + > + if (size >= PAGE_SIZE) { > + page = its_alloc_pages_node(node, > + GFP_KERNEL | __GFP_ZERO, > + get_order(size)); > + > + return page_address(page); > + } > + > + do { > + addr = gen_pool_alloc(itt_pool, size); > + if (addr) > + break; > + > + page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 1); > + if (!page) > + break; > + > + gen_pool_add(itt_pool, (unsigned long)page_address(page), > + PAGE_SIZE, node); > + } while (!addr); > + > + return (void *)addr; > +} > + > +static void itt_free_pool(void *addr, int size) > +{ > + if (!addr) > + return; > + > + if (size >= PAGE_SIZE) { > + its_free_pages(addr, get_order(size)); > + return; > + } > + > + gen_pool_free(itt_pool, (unsigned long)addr, size); > +} > + > /* > * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we > * always have vSGIs mapped. > @@ -2187,7 +2266,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) > { > struct page *prop_page; > > - prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ)); > + prop_page = its_alloc_pages(gfp_flags, > + get_order(LPI_PROPBASE_SZ)); > if (!prop_page) > return NULL; > > @@ -2198,8 +2278,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) > > static void its_free_prop_table(struct page *prop_page) > { > - free_pages((unsigned long)page_address(prop_page), > - get_order(LPI_PROPBASE_SZ)); > + its_free_pages(page_address(prop_page), > + get_order(LPI_PROPBASE_SZ)); > } > > static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size) > @@ -2321,7 +2401,8 @@ static int its_setup_baser(struct its_node *its, struct > its_baser *baser, > order = get_order(GITS_BASER_PAGES_MAX * psz); > } > > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order); > + page = its_alloc_pages_node(its->numa_node, > + GFP_KERNEL | __GFP_ZERO, order); > if (!page) > return -ENOMEM; > > @@ -2334,7 +2415,7 @@ static int its_setup_baser(struct its_node *its, struct > its_baser *baser, > /* 52bit PA is supported only when PageSize=64K */ > if (psz != SZ_64K) { > pr_err("ITS: no 52bit PA support when psz=%d\n", psz); > - free_pages((unsigned long)base, order); > + its_free_pages(base, order); > return -ENXIO; > } > > @@ -2390,7 +2471,7 @@ static int its_setup_baser(struct its_node *its, struct > its_baser *baser, > pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", > &its->phys_base, its_base_type_string[type], > val, tmp); > - free_pages((unsigned long)base, order); > + its_free_pages(base, order); > return -ENXIO; > } > > @@ -2529,8 +2610,8 @@ static void its_free_tables(struct its_node *its) > > for (i = 0; i < GITS_BASER_NR_REGS; i++) { > if (its->tables[i].base) { > - free_pages((unsigned long)its->tables[i].base, > - its->tables[i].order); > + its_free_pages(its->tables[i].base, > + its->tables[i].order); > its->tables[i].base = NULL; > } > } > @@ -2796,7 +2877,8 @@ static bool allocate_vpe_l2_table(int cpu, u32 id) > > /* Allocate memory for 2nd level table */ > if (!table[idx]) { > - page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz)); > + page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, > + get_order(psz)); > if (!page) > return false; > > @@ -2915,7 +2997,8 @@ static int allocate_vpe_l1_table(void) > > pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n", > np, npg, psz, epp, esz); > - page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE)); > + page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, > + get_order(np * PAGE_SIZE)); > if (!page) > return -ENOMEM; > > @@ -2961,8 +3044,8 @@ static struct page *its_allocate_pending_table(gfp_t > gfp_flags) > { > struct page *pend_page; > > - pend_page = alloc_pages(gfp_flags | __GFP_ZERO, > - get_order(LPI_PENDBASE_SZ)); > + pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, > + get_order(LPI_PENDBASE_SZ)); > if (!pend_page) > return NULL; > > @@ -2974,7 +3057,7 @@ static struct page *its_allocate_pending_table(gfp_t > gfp_flags) > > static void its_free_pending_table(struct page *pt) > { > - free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); > + its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ)); > } > > /* > @@ -3309,8 +3392,9 @@ static bool its_alloc_table_entry(struct its_node *its, > > /* Allocate memory for 2nd level table */ > if (!table[idx]) { > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, > - get_order(baser->psz)); > + page = its_alloc_pages_node(its->numa_node, > + GFP_KERNEL | __GFP_ZERO, > + get_order(baser->psz)); > if (!page) > return false; > > @@ -3405,7 +3489,6 @@ static struct its_device *its_create_device(struct its_node > *its, u32 dev_id, > if (WARN_ON(!is_power_of_2(nvecs))) > nvecs = roundup_pow_of_two(nvecs); > > - dev = kzalloc(sizeof(*dev), GFP_KERNEL); > /* > * Even if the device wants a single LPI, the ITT must be > * sized as a power of two (and you need at least one bit...). > @@ -3413,7 +3496,11 @@ static struct its_device *its_create_device(struct its_node > *its, u32 dev_id, > nr_ites = max(2, nvecs); > sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); > sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; > - itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); > + > + itt = itt_alloc_pool(its->numa_node, sz); > + > + dev = kzalloc(sizeof(*dev), GFP_KERNEL); > + > if (alloc_lpis) { > lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis); > if (lpi_map) > @@ -3425,9 +3512,9 @@ static struct its_device *its_create_device(struct its_node > *its, u32 dev_id, > lpi_base = 0; > } > > - if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { > + if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { > kfree(dev); > - kfree(itt); > + itt_free_pool(itt, sz); > bitmap_free(lpi_map); > kfree(col_map); > return NULL; > @@ -3437,6 +3524,7 @@ static struct its_device *its_create_device(struct its_node > *its, u32 dev_id, > > dev->its = its; > dev->itt = itt; > + dev->itt_sz = sz; > dev->nr_ites = nr_ites; > dev->event_map.lpi_map = lpi_map; > dev->event_map.col_map = col_map; > @@ -3464,7 +3552,7 @@ static void its_free_device(struct its_device *its_dev) > list_del(&its_dev->entry); > raw_spin_unlock_irqrestore(&its_dev->its->lock, flags); > kfree(its_dev->event_map.col_map); > - kfree(its_dev->itt); > + itt_free_pool(its_dev->itt, its_dev->itt_sz); > kfree(its_dev); > } > > @@ -5112,8 +5200,9 @@ static int __init its_probe_one(struct its_node *its) > } > } > > - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, > - get_order(ITS_CMD_QUEUE_SZ)); > + page = its_alloc_pages_node(its->numa_node, > + GFP_KERNEL | __GFP_ZERO, > + get_order(ITS_CMD_QUEUE_SZ)); > if (!page) { > err = -ENOMEM; > goto out_unmap_sgir; > @@ -5177,7 +5266,7 @@ static int __init its_probe_one(struct its_node *its) > out_free_tables: > its_free_tables(its); > out_free_cmd: > - free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); > + its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); > out_unmap_sgir: > if (its->sgir_base) > iounmap(its->sgir_base); > @@ -5663,6 +5752,10 @@ int __init its_init(struct fwnode_handle *handle, struct > rdists *rdists, > bool has_v4_1 = false; > int err; > > + itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1); > + if (!itt_pool) > + return -ENOMEM; > + > gic_rdists = rdists; > > lpi_prop_prio = irq_prio; > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor 2024-09-09 3:47 ` Michael Kelley @ 2024-10-02 13:43 ` Thomas Gleixner 2024-10-02 13:59 ` Steven Price 0 siblings, 1 reply; 8+ messages in thread From: Thomas Gleixner @ 2024-10-02 13:43 UTC (permalink / raw) To: Michael Kelley, Steven Price, Marc Zyngier Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Will Deacon, Suzuki K Poulose On Mon, Sep 09 2024 at 03:47, Michael Kelley wrote: >> + ret = set_memory_decrypted((unsigned long)page_address(page), >> + 1 << order); >> + if (WARN_ON(ret)) > > On the x86 side, the WARN is done in the implementation of > set_memory_decrypted()/encrypted() so that each call site doesn't > need to do the WARN. Each call site must only leak the memory > if the return value indicates other than success. There are call sites > in architecture neutral code (such as for swiotlb and DMA direct) > that expect the WARN is in set_memory_decrypted()/encrypted(). > To recap a previous discussion, we want the WARN for notification, > but also so the most security-conscious users can set > kernel.panic_on_warn=1 to stop further processing if there are > problems in the decryption/encryption operation. What's the resolution of this? Thanks, tglx ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor 2024-10-02 13:43 ` Thomas Gleixner @ 2024-10-02 13:59 ` Steven Price 0 siblings, 0 replies; 8+ messages in thread From: Steven Price @ 2024-10-02 13:59 UTC (permalink / raw) To: Thomas Gleixner, Michael Kelley, Marc Zyngier Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Will Deacon, Suzuki K Poulose On 02/10/2024 14:43, Thomas Gleixner wrote: > On Mon, Sep 09 2024 at 03:47, Michael Kelley wrote: >>> + ret = set_memory_decrypted((unsigned long)page_address(page), >>> + 1 << order); >>> + if (WARN_ON(ret)) >> >> On the x86 side, the WARN is done in the implementation of >> set_memory_decrypted()/encrypted() so that each call site doesn't >> need to do the WARN. Each call site must only leak the memory >> if the return value indicates other than success. There are call sites >> in architecture neutral code (such as for swiotlb and DMA direct) >> that expect the WARN is in set_memory_decrypted()/encrypted(). >> To recap a previous discussion, we want the WARN for notification, >> but also so the most security-conscious users can set >> kernel.panic_on_warn=1 to stop further processing if there are >> problems in the decryption/encryption operation. > > What's the resolution of this? Sorry, I should have replied. Moving the WARN into set_memory_decrypted/encrypted() makes sense, and I'll make that change when I post the next version of the Arm CCA patches. I'll post an updated version of this series with the WARN_ONs removed shortly. Thanks, Steve ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment 2024-09-05 9:17 [PATCH 0/2] irqchip/gic-v3-its: Mark ITS tables as decrypted Steven Price 2024-09-05 9:17 ` [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor Steven Price @ 2024-09-05 9:17 ` Steven Price 2024-09-06 16:46 ` Catalin Marinas 1 sibling, 1 reply; 8+ messages in thread From: Steven Price @ 2024-09-05 9:17 UTC (permalink / raw) To: Marc Zyngier, Thomas Gleixner Cc: Steven Price, linux-arm-kernel, linux-kernel, Will Deacon, Suzuki K Poulose its_create_device() over-allocated by ITS_ITT_ALIGN - 1 bytes to ensure that an aligned area was available within the allocation. The new genpool allocator has its min_alloc_order set to get_order(ITS_ITT_ALIGN) so all allocations from it should be appropriately aligned. Remove the over-allocation from its_create_device() and alignment from its_build_mapd_cmd(). Tested-by: Will Deacon <will@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Steven Price <steven.price@arm.com> --- drivers/irqchip/irq-gic-v3-its.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 557214c774c3..49aacf96ade2 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -700,7 +700,6 @@ static struct its_collection *its_build_mapd_cmd(struct its_node *its, u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites); itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt); - itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN); its_encode_cmd(cmd, GITS_CMD_MAPD); its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id); @@ -3495,7 +3494,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, */ nr_ites = max(2, nvecs); sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); - sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; + sz = max(sz, ITS_ITT_ALIGN); itt = itt_alloc_pool(its->numa_node, sz); -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment 2024-09-05 9:17 ` [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment Steven Price @ 2024-09-06 16:46 ` Catalin Marinas 0 siblings, 0 replies; 8+ messages in thread From: Catalin Marinas @ 2024-09-06 16:46 UTC (permalink / raw) To: Steven Price Cc: Marc Zyngier, Thomas Gleixner, linux-arm-kernel, linux-kernel, Will Deacon, Suzuki K Poulose On Thu, Sep 05, 2024 at 10:17:38AM +0100, Steven Price wrote: > diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c > index 557214c774c3..49aacf96ade2 100644 > --- a/drivers/irqchip/irq-gic-v3-its.c > +++ b/drivers/irqchip/irq-gic-v3-its.c > @@ -700,7 +700,6 @@ static struct its_collection *its_build_mapd_cmd(struct its_node *its, > u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites); > > itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt); > - itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN); > > its_encode_cmd(cmd, GITS_CMD_MAPD); > its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id); > @@ -3495,7 +3494,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, > */ > nr_ites = max(2, nvecs); > sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); > - sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; > + sz = max(sz, ITS_ITT_ALIGN); Even without the gen_pool patch, I think the only problem was the slob allocator which we got rid of. > itt = itt_alloc_pool(its->numa_node, sz); With gen_pool created with a min order of get_order(ITS_ITT_ALIGN), I don't think we even need the sz = max(...) above. It's harmless though. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-10-02 14:03 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-05 9:17 [PATCH 0/2] irqchip/gic-v3-its: Mark ITS tables as decrypted Steven Price 2024-09-05 9:17 ` [PATCH 1/2] irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor Steven Price 2024-09-06 16:36 ` Catalin Marinas 2024-09-09 3:47 ` Michael Kelley 2024-10-02 13:43 ` Thomas Gleixner 2024-10-02 13:59 ` Steven Price 2024-09-05 9:17 ` [PATCH 2/2] irqchip/gic-v3-its: Rely on genpool alignment Steven Price 2024-09-06 16:46 ` Catalin Marinas
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).