Skip to content

Commit 8d08713

Browse files
spersvoldgregkh
authored andcommitted
PCI: host-generic: Fix NULL pointer dereference on 32-bit CAM systems
commit 008cb88 upstream. On 32-bit systems the config space is too large to ioremap in one go, so pci_ecam_create() maps each bus segment separately and relies on the ->add_bus callback (pci_ecam_add_bus) to populate the per-bus mapping in cfg->winp[]. pci_ecam_map_bus() then uses that mapping as the base for every config access. The generic ECAM ops (pci_generic_ecam_ops) already provide the ->add_bus and ->remove_bus callbacks, but the CAM (legacy) ops in pci-host-generic.c do not. As a result, on a 32-bit host using "pci-host-cam-generic" the per-bus mapping is never set up and the first config read dereferences a NULL base, crashing during bus enumeration: Unable to handle kernel NULL pointer dereference at virtual address 00000800 Oops [#1] CPU: 0 PID: 1 Comm: swapper Not tainted 6.9.7+ #43 Hardware name: Digilent Nexys-Video-A7 RV32 (DT) epc : pci_generic_config_read+0x40/0xb0 ra : pci_generic_config_read+0x2c/0xb0 [<c038db9c>] pci_generic_config_read+0x40/0xb0 [<c038da04>] pci_bus_read_config_dword+0x50/0xb0 [<c0391e94>] pci_bus_generic_read_dev_vendor_id+0x3c/0x1ec [<c039245c>] pci_scan_single_device+0xa4/0x11c [<c0392570>] pci_scan_slot+0x9c/0x23c [<c039388c>] pci_scan_child_bus_extend+0x58/0x2f4 [<c0393db0>] pci_scan_root_bus_bridge+0x64/0xe8 [<c0393e54>] pci_host_probe+0x20/0xc8 [<c03bc6f4>] pci_host_common_probe+0x144/0x1e4 Fix this by giving the CAM ops the same ->add_bus/->remove_bus callbacks. Since pci_ecam_add_bus() and pci_ecam_remove_bus() are static to ecam.c, move the CAM ops definition there as pci_generic_cam_ops (mirroring pci_generic_ecam_ops) and export it for pci-host-generic.c to reference. Fixes: 8fe55ef ("PCI: Dynamically map ECAM regions") Signed-off-by: Steffen Persvold <spersvold@gmail.com> [mani: removed timestamp from log] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260709122446.3151899-1-spersvold@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent dc61602 commit 8d08713

3 files changed

Lines changed: 17 additions & 10 deletions

File tree

drivers/pci/controller/pci-host-generic.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@
1414
#include <linux/pci-ecam.h>
1515
#include <linux/platform_device.h>
1616

17-
static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
18-
.bus_shift = 16,
19-
.pci_ops = {
20-
.map_bus = pci_ecam_map_bus,
21-
.read = pci_generic_config_read,
22-
.write = pci_generic_config_write,
23-
}
24-
};
25-
2617
static bool pci_dw_valid_device(struct pci_bus *bus, unsigned int devfn)
2718
{
2819
struct pci_config_window *cfg = bus->sysdata;
@@ -58,7 +49,7 @@ static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
5849

5950
static const struct of_device_id gen_pci_of_match[] = {
6051
{ .compatible = "pci-host-cam-generic",
61-
.data = &gen_pci_cfg_cam_bus_ops },
52+
.data = &pci_generic_cam_ops },
6253

6354
{ .compatible = "pci-host-ecam-generic",
6455
.data = &pci_generic_ecam_ops },

drivers/pci/ecam.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,19 @@ const struct pci_ecam_ops pci_generic_ecam_ops = {
208208
};
209209
EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
210210

211+
/* CAM ops */
212+
const struct pci_ecam_ops pci_generic_cam_ops = {
213+
.bus_shift = 16,
214+
.pci_ops = {
215+
.add_bus = pci_ecam_add_bus,
216+
.remove_bus = pci_ecam_remove_bus,
217+
.map_bus = pci_ecam_map_bus,
218+
.read = pci_generic_config_read,
219+
.write = pci_generic_config_write,
220+
}
221+
};
222+
EXPORT_SYMBOL_GPL(pci_generic_cam_ops);
223+
211224
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
212225
/* ECAM ops for 32-bit access only (non-compliant) */
213226
const struct pci_ecam_ops pci_32b_ops = {

include/linux/pci-ecam.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
7777
/* default ECAM ops */
7878
extern const struct pci_ecam_ops pci_generic_ecam_ops;
7979

80+
/* default CAM ops */
81+
extern const struct pci_ecam_ops pci_generic_cam_ops;
82+
8083
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
8184
extern const struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */
8285
extern const struct pci_ecam_ops pci_32b_read_ops; /* 32-bit read only */

0 commit comments

Comments
 (0)