Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic-v3-its: Avoid truncating memory addresses

On 32-bit machines with CONFIG_ARM_LPAE, it is possible for lowmem
allocations to be backed by addresses physical memory above the 32-bit
address limit, as found while experimenting with larger VMSPLIT
configurations.

This caused the qemu virt model to crash in the GICv3 driver, which
allocates the 'itt' object using GFP_KERNEL. Since all memory below
the 4GB physical address limit is in ZONE_DMA in this configuration,
kmalloc() defaults to higher addresses for ZONE_NORMAL, and the
ITS driver stores the physical address in a 32-bit 'unsigned long'
variable.

Change the itt_addr variable to the correct phys_addr_t type instead,
along with all other variables in this driver that hold a physical
address.

The gicv5 driver correctly uses u64 variables, while all other irqchip
drivers don't call virt_to_phys or similar interfaces. It's expected that
other device drivers have similar issues, but fixing this one is
sufficient for booting a virtio based guest.

Fixes: cc2d3216f53c ("irqchip: GICv3: ITS command queue")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260119201603.2713066-1-arnd@kernel.org

authored by

Arnd Bergmann and committed by
Thomas Gleixner
8d76a7d8 cd4a3ced

+4 -4
+4 -4
drivers/irqchip/irq-gic-v3-its.c
··· 709 709 struct its_cmd_block *cmd, 710 710 struct its_cmd_desc *desc) 711 711 { 712 - unsigned long itt_addr; 712 + phys_addr_t itt_addr; 713 713 u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites); 714 714 715 715 itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt); ··· 879 879 struct its_cmd_desc *desc) 880 880 { 881 881 struct its_vpe *vpe = valid_vpe(its, desc->its_vmapp_cmd.vpe); 882 - unsigned long vpt_addr, vconf_addr; 882 + phys_addr_t vpt_addr, vconf_addr; 883 883 u64 target; 884 884 bool alloc; 885 885 ··· 2477 2477 baser->psz = psz; 2478 2478 tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; 2479 2479 2480 - pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", 2480 + pr_info("ITS@%pa: allocated %d %s @%llx (%s, esz %d, psz %dK, shr %d)\n", 2481 2481 &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / (int)tmp), 2482 2482 its_base_type_string[type], 2483 - (unsigned long)virt_to_phys(base), 2483 + (u64)virt_to_phys(base), 2484 2484 indirect ? "indirect" : "flat", (int)esz, 2485 2485 psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); 2486 2486