From 6b85ade34c030bec8648fc8fec1a8c8cf32c7e8b Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Sun, 25 Jun 2017 09:08:03 +0100 Subject: [PATCH] dev pci min works, non pci dev doesnt --- kernel_module/hw_min.c | 75 +++++++++++++++++++++++++++++++ kernel_module/hw_pci_min.c | 90 ++++++++++++++++++++++++++++++++++++++ kernel_module/pci.c | 1 + runqemu | 2 + 4 files changed, 168 insertions(+) create mode 100644 kernel_module/hw_min.c create mode 100644 kernel_module/hw_pci_min.c diff --git a/kernel_module/hw_min.c b/kernel_module/hw_min.c new file mode 100644 index 0000000..30d6d1e --- /dev/null +++ b/kernel_module/hw_min.c @@ -0,0 +1,75 @@ +/* +TODO: how to setup a device with magic addresses without PCI? +https://stackoverflow.com/questions/26965239/board-files-for-x86-based-systems + +request_mem_region returns NULL. + +TODO: which physical address is QEMU mapping? +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* S_IRUSR | S_IWUSR */ + +#define CDEV_NAME "lkmc_hw_min" +#define MMIO_LEN 8 +#define IRQ_RAISE 0 +#define IRQ_ACK 4 + +MODULE_LICENSE("GPL"); + +static unsigned long mmio_addr = 0; +module_param(mmio_addr, ulong, S_IRUSR | S_IWUSR); + +static int major; +static int irq; +static void __iomem *mmio; + +static struct file_operations fops = { + .owner = THIS_MODULE, +}; + +static irqreturn_t irq_handler(int irq, void *dev) +{ + pr_info("irq_handler irq = %d dev = %d\n", irq, *(int *)dev); + iowrite32(0, mmio + IRQ_ACK); + return IRQ_HANDLED; +} + +static int myinit(void) +{ + pr_info("init\n"); + major = register_chrdev(0, CDEV_NAME, &fops); + mmio = (void __iomem *)mmio_addr; + if (request_mem_region(mmio_addr, MMIO_LEN, CDEV_NAME) == NULL) { + pr_info("request_mem_region\n"); + goto error; + } + ioremap(mmio_addr, 8); + irq = 10; + if (request_irq(irq, irq_handler, IRQF_SHARED, CDEV_NAME, &major) < 0) { + pr_info("request_irq\n"); + goto error; + } + iowrite32(0x12345678, mmio + IRQ_RAISE); + return 0; +error: + return -ENODEV; +} + +static void myexit(void) +{ + pr_info("exit\n"); + free_irq(irq, &major); + release_mem_region(mmio_addr, MMIO_LEN); + unregister_chrdev(major, CDEV_NAME); +} + +module_init(myinit); +module_exit(myexit); diff --git a/kernel_module/hw_pci_min.c b/kernel_module/hw_pci_min.c new file mode 100644 index 0000000..5ae471a --- /dev/null +++ b/kernel_module/hw_pci_min.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define BAR 0 +#define CDEV_NAME "lkmc_hw_pci_min" +#define EDU_DEVICE_ID 0x11e9 +#define QEMU_VENDOR_ID 0x1234 + +MODULE_LICENSE("GPL"); + +static struct pci_device_id id_table[] = { + { PCI_DEVICE(QEMU_VENDOR_ID, EDU_DEVICE_ID), }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, id_table); +static int major; +static struct pci_dev *pdev; +static void __iomem *mmio; +static struct file_operations fops = { + .owner = THIS_MODULE, +}; + +static irqreturn_t irq_handler(int irq, void *dev) +{ + pr_info("irq_handler irq = %d dev = %d\n", irq, *(int *)dev); + iowrite32(0, mmio + 4); + return IRQ_HANDLED; +} + +static int probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + pr_info("probe\n"); + major = register_chrdev(0, CDEV_NAME, &fops); + pdev = dev; + if (pci_enable_device(dev) < 0) { + dev_err(&(pdev->dev), "pci_enable_device\n"); + goto error; + } + if (pci_request_region(dev, BAR, "myregion0")) { + dev_err(&(pdev->dev), "pci_request_region\n"); + goto error; + } + mmio = pci_iomap(pdev, BAR, pci_resource_len(pdev, BAR)); + pr_info("dev->irq = %u\n", dev->irq); + if (request_irq(dev->irq, irq_handler, IRQF_SHARED, "pci_irq_handler0", &major) < 0) { + dev_err(&(dev->dev), "request_irq\n"); + goto error; + } + iowrite32(0x12345678, mmio); + return 0; +error: + return 1; +} + +static void remove(struct pci_dev *dev) +{ + pr_info("remove\n"); + free_irq(dev->irq, &major); + pci_release_region(dev, BAR); + unregister_chrdev(major, CDEV_NAME); +} + +static struct pci_driver pci_driver = { + .name = CDEV_NAME, + .id_table = id_table, + .probe = probe, + .remove = remove, +}; + +static int myinit(void) +{ + if (pci_register_driver(&pci_driver) < 0) { + return 1; + } + return 0; +} + +static void myexit(void) +{ + pci_unregister_driver(&pci_driver); +} + +module_init(myinit); +module_exit(myexit); diff --git a/kernel_module/pci.c b/kernel_module/pci.c index a169eb2..81ca101 100644 --- a/kernel_module/pci.c +++ b/kernel_module/pci.c @@ -242,6 +242,7 @@ static int pci_probe(struct pci_dev *dev, const struct pci_device_id *id) pr_info("irq %x\n", pci_irq); /* Initial value of the IO memory. */ + pr_info("mmio %p %llx\n", mmio, (unsigned long long)virt_to_phys(mmio)); for (i = 0; i < 0x28; i += 4) { pr_info("io %x %x\n", i, ioread32((void*)(mmio + i))); } diff --git a/runqemu b/runqemu index 8af5f86..8e93800 100755 --- a/runqemu +++ b/runqemu @@ -53,6 +53,8 @@ case "$arch" in -M pc \ -append 'root=/dev/vda $extra_append' \ -device edu \ + -device lkmc_min \ + -device lkmc_pci_min \ -drive file=${images_dir}/rootfs.ext2,if=virtio,format=raw \ -kernel ${images_dir}/bzImage \ -monitor telnet::45454,server,nowait \