On 1/6/22 14:24, Maciej W. Rozycki wrote: > Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP > (BIOS Configuration Program) external tool meant for tweaking BIOS > structures without the need to rebuild it from sources[1]. > > The $IRT format has been invented by AMI before Microsoft has come up > with its $PIR format and a $IRT table is therefore there in some systems > that lack a $PIR table, such as the DataExpert EXP8449 mainboard based > on the ALi FinALi 486 chipset (M1489/M1487), which predates DMI 2.0 and > cannot therefore be easily identified at run time. > > Unlike with the $PIR format there is no alignment guarantee as to the > placement of the $IRT table, so scan the whole BIOS area bytewise. > > Credit to Michal Necasek for helping me chase documentation for the > format. > > References: > > [1] "What is BCP? - AMI", <https://www.ami.com/what-is-bcp/> > > Signed-off-by: Maciej W. Rozycki <macro@xxxxxxxxxxx> > Cc: Michal Necasek <mnecasek@xxxxxxxxx> > --- > New change in v3. > --- > arch/x86/include/asm/pci_x86.h | 9 +++++ > arch/x86/pci/irq.c | 71 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 80 insertions(+) > > linux-x86-pirq-irt.diff > Index: linux-macro/arch/x86/include/asm/pci_x86.h > =================================================================== > --- linux-macro.orig/arch/x86/include/asm/pci_x86.h > +++ linux-macro/arch/x86/include/asm/pci_x86.h > @@ -90,6 +90,15 @@ struct irq_routing_table { > struct irq_info slots[0]; > } __attribute__((packed)); > > +struct irt_routing_table { > + u32 signature; /* IRT_SIGNATURE should be here */ > + u8 size; /* Number of entries provided */ > + u8 used; /* Number of entries actually used */ > + u16 exclusive_irqs; /* IRQs devoted exclusively to > + PCI usage */ > + struct irq_info slots[0]; > +} __attribute__((packed)); > + > extern unsigned int pcibios_irq_mask; > > extern raw_spinlock_t pci_config_lock; > Index: linux-macro/arch/x86/pci/irq.c > =================================================================== > --- linux-macro.orig/arch/x86/pci/irq.c > +++ linux-macro/arch/x86/pci/irq.c > @@ -25,6 +25,8 @@ > #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) > #define PIRQ_VERSION 0x0100 > > +#define IRT_SIGNATURE (('$' << 0) + ('I' << 8) + ('R' << 16) + ('T' << 24)) > + > static int broken_hp_bios_irq9; > static int acer_tm360_irqrouting; > > @@ -91,7 +93,69 @@ static inline struct irq_routing_table * > return NULL; > } > > +/* > + * Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP > + * (BIOS Configuration Program) external tool meant for tweaking BIOS > + * structures without the need to rebuild it from sources. The $IRT > + * format has been invented by AMI before Microsoft has come up with its > + * $PIR format and a $IRT table is therefore there in some systems that > + * lack a $PIR table. > + * > + * It uses the same PCI BIOS 2.1 format for interrupt routing entries > + * themselves but has a different simpler header prepended instead, > + * occupying 8 bytes, where a `$IRT' signature is followed by one byte > + * specifying the total number of interrupt routing entries allocated in > + * the table, then one byte specifying the actual number of entries used > + * (which the BCP tool can take advantage of when modifying the table), > + * and finally a 16-bit word giving the IRQs devoted exclusively to PCI. > + * Unlike with the $PIR table there is no alignment guarantee. > + * > + * Given the similarity of the two formats the $IRT one is trivial to > + * convert to the $PIR one, which we do here, except that obviously we > + * have no information as to the router device to use, but we can handle > + * it by matching PCI device IDs actually seen on the bus against ones > + * that our individual routers recognise. > + * > + * Reportedly there is another $IRT table format where a 16-bit word > + * follows the header instead that points to interrupt routing entries > + * in a $PIR table provided elsewhere. In that case this code will not > + * be reached though as the $PIR table will have been chosen instead. > + */ > +static inline struct irq_routing_table *pirq_convert_irt_table(u8 *addr) > +{ > + struct irt_routing_table *ir; > + struct irq_routing_table *rt; > + u16 size; > + u8 sum; > + int i; > + > + ir = (struct irt_routing_table *)addr; > + if (ir->signature != IRT_SIGNATURE || !ir->used || ir->size < ir->used) > + return NULL; > > + DBG(KERN_DEBUG "PCI: $IRT Interrupt Routing Table found at 0x%lx\n", > + __pa(ir)); > + > + size = sizeof(*rt) + ir->used * sizeof(rt->slots[0]); > + rt = kzalloc(size, GFP_KERNEL); > + if (!rt) > + return NULL; > + > + rt->signature = PIRQ_SIGNATURE; > + rt->version = PIRQ_VERSION; > + rt->size = size; > + rt->exclusive_irqs = ir->exclusive_irqs; > + for (i = 0; i < ir->used; i++) > + rt->slots[i] = ir->slots[i]; > + > + addr = (u8 *)rt; > + sum = 0; > + for (i = 0; i < size; i++) > + sum += addr[i]; > + rt->checksum = -sum; > + > + return rt; > +} > > /* > * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. > @@ -113,6 +177,13 @@ static struct irq_routing_table * __init > if (rt) > return rt; > } > + for (addr = (u8 *)__va(0xf0000); > + addr < (u8 *)__va(0x100000); > + addr++) { > + rt = pirq_convert_irt_table(addr); > + if (rt) > + return rt; > + } > return NULL; > } > Hi, This patch broke crosvm using recent linux-next. The "ir = (struct irt_routing_table *)addr;" contains invalid pointer. Any ideas why? PCI: Probing PCI hardware BUG: unable to handle page fault for address: ffffed1000020000 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 12fff4067 P4D 12fff4067 PUD 12fff3067 PMD 12fff2067 PTE 0 Oops: 0000 [#1] PREEMPT SMP KASAN CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.17.0-rc7-next-20220310+ #226 Hardware name: ChromiumOS crosvm, BIOS 0 RIP: 0010:kasan_check_range+0xe6/0x1a0 Code: 00 74 ee 48 89 c2 b8 01 00 00 00 48 85 d2 75 5d 5b 41 5c 41 5d 5d c3 48 85 d2 74 63 4c 01 e2 eb 09 48 83 c0 01 48 39 d0 74 55 <80> 38 00 74 f2 eb d2 41 bd 08 00 00 00 45 29 dd 4b 8d 54 25 00 eb RSP: 0000:ffff8881002c7d98 EFLAGS: 00010297 RAX: ffffed1000020000 RBX: ffffed1000020001 RCX: ffffffff8440db66 RDX: ffffed1000020001 RSI: 0000000000000004 RDI: ffff8880000ffffd RBP: ffff8881002c7db0 R08: 0000000000000000 R09: ffff888000100000 R10: ffffed1000020000 R11: 0000000000000001 R12: ffffed100001ffff R13: ffff888000100000 R14: 0000000000000000 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88810b200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffed1000020000 CR3: 0000000003a29001 CR4: 0000000000170ef0 Call Trace: <TASK> __asan_loadN+0xf/0x20 pcibios_irq_init+0xd7/0x484 ? pci_legacy_init+0x3b/0x3b pci_subsys_init+0x88/0x92 do_one_initcall+0xba/0x3e0 ? trace_event_raw_event_initcall_level+0x140/0x140 ? rcu_read_lock_sched_held+0x46/0x80 kernel_init_freeable+0x33c/0x395 ? rest_init+0x280/0x280 kernel_init+0x1e/0x130 ret_from_fork+0x1f/0x30 </TASK> Modules linked in: CR2: ffffed1000020000 ---[ end trace 0000000000000000 ]---