Skip to content

Commit b08e2f4

Browse files
Steven PriceKAGA-KOKO
authored andcommitted
irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor
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 that the peak number of devices will be 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> Signed-off-by: Steven Price <steven.price@arm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Will Deacon <will@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/all/20241002141630.433502-2-steven.price@arm.com
1 parent 40d7af5 commit b08e2f4

File tree

1 file changed

+115
-23
lines changed

1 file changed

+115
-23
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
#include <linux/crash_dump.h>
1313
#include <linux/delay.h>
1414
#include <linux/efi.h>
15+
#include <linux/genalloc.h>
1516
#include <linux/interrupt.h>
1617
#include <linux/iommu.h>
1718
#include <linux/iopoll.h>
1819
#include <linux/irqdomain.h>
1920
#include <linux/list.h>
2021
#include <linux/log2.h>
22+
#include <linux/mem_encrypt.h>
2123
#include <linux/memblock.h>
2224
#include <linux/mm.h>
2325
#include <linux/msi.h>
@@ -27,6 +29,7 @@
2729
#include <linux/of_pci.h>
2830
#include <linux/of_platform.h>
2931
#include <linux/percpu.h>
32+
#include <linux/set_memory.h>
3033
#include <linux/slab.h>
3134
#include <linux/syscore_ops.h>
3235

@@ -164,6 +167,7 @@ struct its_device {
164167
struct its_node *its;
165168
struct event_lpi_map event_map;
166169
void *itt;
170+
u32 itt_sz;
167171
u32 nr_ites;
168172
u32 device_id;
169173
bool shared;
@@ -199,6 +203,87 @@ static DEFINE_IDA(its_vpeid_ida);
199203
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
200204
#define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
201205

206+
static struct page *its_alloc_pages_node(int node, gfp_t gfp,
207+
unsigned int order)
208+
{
209+
struct page *page;
210+
int ret = 0;
211+
212+
page = alloc_pages_node(node, gfp, order);
213+
214+
if (!page)
215+
return NULL;
216+
217+
ret = set_memory_decrypted((unsigned long)page_address(page),
218+
1 << order);
219+
/*
220+
* If set_memory_decrypted() fails then we don't know what state the
221+
* page is in, so we can't free it. Instead we leak it.
222+
* set_memory_decrypted() will already have WARNed.
223+
*/
224+
if (ret)
225+
return NULL;
226+
227+
return page;
228+
}
229+
230+
static struct page *its_alloc_pages(gfp_t gfp, unsigned int order)
231+
{
232+
return its_alloc_pages_node(NUMA_NO_NODE, gfp, order);
233+
}
234+
235+
static void its_free_pages(void *addr, unsigned int order)
236+
{
237+
/*
238+
* If the memory cannot be encrypted again then we must leak the pages.
239+
* set_memory_encrypted() will already have WARNed.
240+
*/
241+
if (set_memory_encrypted((unsigned long)addr, 1 << order))
242+
return;
243+
free_pages((unsigned long)addr, order);
244+
}
245+
246+
static struct gen_pool *itt_pool;
247+
248+
static void *itt_alloc_pool(int node, int size)
249+
{
250+
unsigned long addr;
251+
struct page *page;
252+
253+
if (size >= PAGE_SIZE) {
254+
page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, get_order(size));
255+
256+
return page ? page_address(page) : NULL;
257+
}
258+
259+
do {
260+
addr = gen_pool_alloc(itt_pool, size);
261+
if (addr)
262+
break;
263+
264+
page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 1);
265+
if (!page)
266+
break;
267+
268+
gen_pool_add(itt_pool, (unsigned long)page_address(page), PAGE_SIZE, node);
269+
} while (!addr);
270+
271+
return (void *)addr;
272+
}
273+
274+
static void itt_free_pool(void *addr, int size)
275+
{
276+
if (!addr)
277+
return;
278+
279+
if (size >= PAGE_SIZE) {
280+
its_free_pages(addr, get_order(size));
281+
return;
282+
}
283+
284+
gen_pool_free(itt_pool, (unsigned long)addr, size);
285+
}
286+
202287
/*
203288
* Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
204289
* always have vSGIs mapped.
@@ -2181,7 +2266,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
21812266
{
21822267
struct page *prop_page;
21832268

2184-
prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
2269+
prop_page = its_alloc_pages(gfp_flags,
2270+
get_order(LPI_PROPBASE_SZ));
21852271
if (!prop_page)
21862272
return NULL;
21872273

@@ -2192,8 +2278,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
21922278

21932279
static void its_free_prop_table(struct page *prop_page)
21942280
{
2195-
free_pages((unsigned long)page_address(prop_page),
2196-
get_order(LPI_PROPBASE_SZ));
2281+
its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ));
21972282
}
21982283

21992284
static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
@@ -2315,7 +2400,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
23152400
order = get_order(GITS_BASER_PAGES_MAX * psz);
23162401
}
23172402

2318-
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
2403+
page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
23192404
if (!page)
23202405
return -ENOMEM;
23212406

@@ -2328,7 +2413,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
23282413
/* 52bit PA is supported only when PageSize=64K */
23292414
if (psz != SZ_64K) {
23302415
pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
2331-
free_pages((unsigned long)base, order);
2416+
its_free_pages(base, order);
23322417
return -ENXIO;
23332418
}
23342419

@@ -2384,7 +2469,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
23842469
pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
23852470
&its->phys_base, its_base_type_string[type],
23862471
val, tmp);
2387-
free_pages((unsigned long)base, order);
2472+
its_free_pages(base, order);
23882473
return -ENXIO;
23892474
}
23902475

@@ -2523,8 +2608,7 @@ static void its_free_tables(struct its_node *its)
25232608

25242609
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
25252610
if (its->tables[i].base) {
2526-
free_pages((unsigned long)its->tables[i].base,
2527-
its->tables[i].order);
2611+
its_free_pages(its->tables[i].base, its->tables[i].order);
25282612
its->tables[i].base = NULL;
25292613
}
25302614
}
@@ -2790,7 +2874,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
27902874

27912875
/* Allocate memory for 2nd level table */
27922876
if (!table[idx]) {
2793-
page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
2877+
page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
27942878
if (!page)
27952879
return false;
27962880

@@ -2909,7 +2993,7 @@ static int allocate_vpe_l1_table(void)
29092993

29102994
pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n",
29112995
np, npg, psz, epp, esz);
2912-
page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
2996+
page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
29132997
if (!page)
29142998
return -ENOMEM;
29152999

@@ -2955,8 +3039,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
29553039
{
29563040
struct page *pend_page;
29573041

2958-
pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
2959-
get_order(LPI_PENDBASE_SZ));
3042+
pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, get_order(LPI_PENDBASE_SZ));
29603043
if (!pend_page)
29613044
return NULL;
29623045

@@ -2968,7 +3051,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
29683051

29693052
static void its_free_pending_table(struct page *pt)
29703053
{
2971-
free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
3054+
its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ));
29723055
}
29733056

29743057
/*
@@ -3303,8 +3386,8 @@ static bool its_alloc_table_entry(struct its_node *its,
33033386

33043387
/* Allocate memory for 2nd level table */
33053388
if (!table[idx]) {
3306-
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
3307-
get_order(baser->psz));
3389+
page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
3390+
get_order(baser->psz));
33083391
if (!page)
33093392
return false;
33103393

@@ -3399,15 +3482,18 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
33993482
if (WARN_ON(!is_power_of_2(nvecs)))
34003483
nvecs = roundup_pow_of_two(nvecs);
34013484

3402-
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
34033485
/*
34043486
* Even if the device wants a single LPI, the ITT must be
34053487
* sized as a power of two (and you need at least one bit...).
34063488
*/
34073489
nr_ites = max(2, nvecs);
34083490
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
34093491
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
3410-
itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
3492+
3493+
itt = itt_alloc_pool(its->numa_node, sz);
3494+
3495+
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
3496+
34113497
if (alloc_lpis) {
34123498
lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
34133499
if (lpi_map)
@@ -3419,9 +3505,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
34193505
lpi_base = 0;
34203506
}
34213507

3422-
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
3508+
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
34233509
kfree(dev);
3424-
kfree(itt);
3510+
itt_free_pool(itt, sz);
34253511
bitmap_free(lpi_map);
34263512
kfree(col_map);
34273513
return NULL;
@@ -3431,6 +3517,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
34313517

34323518
dev->its = its;
34333519
dev->itt = itt;
3520+
dev->itt_sz = sz;
34343521
dev->nr_ites = nr_ites;
34353522
dev->event_map.lpi_map = lpi_map;
34363523
dev->event_map.col_map = col_map;
@@ -3458,7 +3545,7 @@ static void its_free_device(struct its_device *its_dev)
34583545
list_del(&its_dev->entry);
34593546
raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
34603547
kfree(its_dev->event_map.col_map);
3461-
kfree(its_dev->itt);
3548+
itt_free_pool(its_dev->itt, its_dev->itt_sz);
34623549
kfree(its_dev);
34633550
}
34643551

@@ -5116,8 +5203,9 @@ static int __init its_probe_one(struct its_node *its)
51165203
}
51175204
}
51185205

5119-
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
5120-
get_order(ITS_CMD_QUEUE_SZ));
5206+
page = its_alloc_pages_node(its->numa_node,
5207+
GFP_KERNEL | __GFP_ZERO,
5208+
get_order(ITS_CMD_QUEUE_SZ));
51215209
if (!page) {
51225210
err = -ENOMEM;
51235211
goto out_unmap_sgir;
@@ -5181,7 +5269,7 @@ static int __init its_probe_one(struct its_node *its)
51815269
out_free_tables:
51825270
its_free_tables(its);
51835271
out_free_cmd:
5184-
free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
5272+
its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
51855273
out_unmap_sgir:
51865274
if (its->sgir_base)
51875275
iounmap(its->sgir_base);
@@ -5667,6 +5755,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
56675755
bool has_v4_1 = false;
56685756
int err;
56695757

5758+
itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1);
5759+
if (!itt_pool)
5760+
return -ENOMEM;
5761+
56705762
gic_rdists = rdists;
56715763

56725764
lpi_prop_prio = irq_prio;

0 commit comments

Comments
 (0)