Skip to content

Commit b11408a

Browse files
author
Charles Mirabile
committed
irqchip/gic-v3-its: Share ITS tables with a non-trusted hypervisor
JIRA: https://issues.redhat.com/browse/RHEL-62922 commit b08e2f4 Author: Steven Price <steven.price@arm.com> Date: Wed, 2 Oct 2024 15:16:29 +0100 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 Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
1 parent 9dbc22f commit b11408a

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

@@ -163,6 +166,7 @@ struct its_device {
163166
struct its_node *its;
164167
struct event_lpi_map event_map;
165168
void *itt;
169+
u32 itt_sz;
166170
u32 nr_ites;
167171
u32 device_id;
168172
bool shared;
@@ -198,6 +202,87 @@ static DEFINE_IDA(its_vpeid_ida);
198202
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
199203
#define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
200204

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

2183-
prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
2268+
prop_page = its_alloc_pages(gfp_flags,
2269+
get_order(LPI_PROPBASE_SZ));
21842270
if (!prop_page)
21852271
return NULL;
21862272

@@ -2191,8 +2277,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
21912277

21922278
static void its_free_prop_table(struct page *prop_page)
21932279
{
2194-
free_pages((unsigned long)page_address(prop_page),
2195-
get_order(LPI_PROPBASE_SZ));
2280+
its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ));
21962281
}
21972282

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

2317-
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
2402+
page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
23182403
if (!page)
23192404
return -ENOMEM;
23202405

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

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

@@ -2522,8 +2607,7 @@ static void its_free_tables(struct its_node *its)
25222607

25232608
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
25242609
if (its->tables[i].base) {
2525-
free_pages((unsigned long)its->tables[i].base,
2526-
its->tables[i].order);
2610+
its_free_pages(its->tables[i].base, its->tables[i].order);
25272611
its->tables[i].base = NULL;
25282612
}
25292613
}
@@ -2789,7 +2873,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
27892873

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

@@ -2908,7 +2992,7 @@ static int allocate_vpe_l1_table(void)
29082992

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

@@ -2954,8 +3038,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
29543038
{
29553039
struct page *pend_page;
29563040

2957-
pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
2958-
get_order(LPI_PENDBASE_SZ));
3041+
pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, get_order(LPI_PENDBASE_SZ));
29593042
if (!pend_page)
29603043
return NULL;
29613044

@@ -2967,7 +3050,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
29673050

29683051
static void its_free_pending_table(struct page *pt)
29693052
{
2970-
free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
3053+
its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ));
29713054
}
29723055

29733056
/*
@@ -3302,8 +3385,8 @@ static bool its_alloc_table_entry(struct its_node *its,
33023385

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

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

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

3421-
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
3507+
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
34223508
kfree(dev);
3423-
kfree(itt);
3509+
itt_free_pool(itt, sz);
34243510
bitmap_free(lpi_map);
34253511
kfree(col_map);
34263512
return NULL;
@@ -3430,6 +3516,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
34303516

34313517
dev->its = its;
34323518
dev->itt = itt;
3519+
dev->itt_sz = sz;
34333520
dev->nr_ites = nr_ites;
34343521
dev->event_map.lpi_map = lpi_map;
34353522
dev->event_map.col_map = col_map;
@@ -3457,7 +3544,7 @@ static void its_free_device(struct its_device *its_dev)
34573544
list_del(&its_dev->entry);
34583545
raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
34593546
kfree(its_dev->event_map.col_map);
3460-
kfree(its_dev->itt);
3547+
itt_free_pool(its_dev->itt, its_dev->itt_sz);
34613548
kfree(its_dev);
34623549
}
34633550

@@ -5127,8 +5214,9 @@ static int __init its_probe_one(struct its_node *its)
51275214
}
51285215
}
51295216

5130-
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
5131-
get_order(ITS_CMD_QUEUE_SZ));
5217+
page = its_alloc_pages_node(its->numa_node,
5218+
GFP_KERNEL | __GFP_ZERO,
5219+
get_order(ITS_CMD_QUEUE_SZ));
51325220
if (!page) {
51335221
err = -ENOMEM;
51345222
goto out_unmap_sgir;
@@ -5192,7 +5280,7 @@ static int __init its_probe_one(struct its_node *its)
51925280
out_free_tables:
51935281
its_free_tables(its);
51945282
out_free_cmd:
5195-
free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
5283+
its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
51965284
out_unmap_sgir:
51975285
if (its->sgir_base)
51985286
iounmap(its->sgir_base);
@@ -5678,6 +5766,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
56785766
bool has_v4_1 = false;
56795767
int err;
56805768

5769+
itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1);
5770+
if (!itt_pool)
5771+
return -ENOMEM;
5772+
56815773
gic_rdists = rdists;
56825774

56835775
lpi_prop_prio = irq_prio;

0 commit comments

Comments
 (0)