Created
March 5, 2022 21:06
-
-
Save TobleMiner/78fa225dc20a15b4bfb29eb948646ed3 to your computer and use it in GitHub Desktop.
Simple Linux kernel module to test device vs normal memory PCI BAR accesses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/errno.h> | |
#include <linux/init.h> | |
#include <linux/ioport.h> | |
#include <linux/kernel.h> | |
#include <linux/mm.h> | |
#include <linux/module.h> | |
#include <linux/pci.h> | |
#include <linux/string.h> | |
static int vendor_id = -1; | |
module_param(vendor_id, int, S_IRUGO); | |
MODULE_PARM_DESC(vendor_id, "PCI vendor id"); | |
static int device_id = -1; | |
module_param(device_id, int, S_IRUGO); | |
MODULE_PARM_DESC(device_id, "PCI device id"); | |
static int bar = -1; | |
module_param(bar, int, S_IRUGO); | |
MODULE_PARM_DESC(bar, "PCI bar"); | |
static bool device_mem = false; | |
module_param(device_mem, bool, S_IRUGO); | |
MODULE_PARM_DESC(device_mem, "Map bar as device memory"); | |
static int bar_test_pci_probe(struct pci_dev *pdev, | |
const struct pci_device_id *ent) | |
{ | |
int err; | |
resource_size_t start; | |
resource_size_t len; | |
void __iomem* mmio; | |
unsigned int shift; | |
/* enable device */ | |
err = pcim_enable_device(pdev); | |
if (err) { | |
return err; | |
} | |
/* get specified bar */ | |
err = pci_request_region(pdev, bar, "bar_write_test"); | |
if (err) { | |
pr_err("Failed to request PCI region\n"); | |
return err; | |
} | |
start = pci_resource_start(pdev, bar); | |
len = pci_resource_len(pdev, bar); | |
pr_info("BAR%d has size 0x%08llx\n", bar, len); | |
if (device_mem) { | |
pr_info("Mapping BAR%d as device memory\n", bar); | |
mmio = ioremap(start, len); | |
} else { | |
pr_info("Mapping BAR%d as regular memory\n", bar); | |
mmio = ioremap_wc(start, len); | |
} | |
if (!mmio) { | |
pr_err("Failed to map BAR %d\n", bar); | |
goto out; | |
} | |
pr_info("Testing BAR write sizes\n"); | |
for (shift = 2; (1ull << shift) <= len; shift++) { | |
pr_info("Trying 2^%u...\n", shift); | |
if (device_mem) { | |
memset_io(mmio, 0, 1ull << shift); | |
__iowmb(); | |
} else { | |
memset(mmio, 0, 1ull << shift); | |
wmb(); | |
} | |
} | |
pr_info("BAR seems to be writable at all sizes\n"); | |
iounmap(mmio); | |
out: | |
pci_release_region(pdev, bar); | |
return -1; | |
} | |
static struct pci_device_id pci_id_table[] = { | |
{ PCI_DEVICE(0, 0), }, | |
{ 0, } | |
}; | |
static struct pci_driver bar_test_driver = { | |
.name = "bar_write_test", | |
.id_table = pci_id_table, | |
.probe = bar_test_pci_probe, | |
.remove = NULL, | |
}; | |
static int __init bar_test_driver_init(void) | |
{ | |
if (vendor_id < 0) { | |
pr_err("Invalid vendor id %d\n", vendor_id); | |
return -EINVAL; | |
} | |
if (device_id < 0) { | |
pr_err("Invalid device id %d\n", device_id); | |
return -EINVAL; | |
} | |
if (bar < 0) { | |
pr_err("Invalid bar %d\n", bar); | |
return -EINVAL; | |
} | |
pci_id_table[0].vendor = vendor_id; | |
pci_id_table[0].device = device_id; | |
return pci_register_driver(&bar_test_driver); | |
} | |
module_init(bar_test_driver_init); | |
static void __exit bar_test_driver_exit(void) | |
{ | |
pci_unregister_driver(&bar_test_driver); | |
} | |
module_exit(bar_test_driver_exit); | |
MODULE_AUTHOR("Tobias Schramm <[email protected]>"); | |
MODULE_DESCRIPTION("PCI BAR write size test driver"); | |
MODULE_LICENSE("Dual BSD/GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
obj-m += bar-write-test.o |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment