[SeaBIOS] [PATCH 01/14] pci: Add helper functions for internal driver BAR handling

Kevin O'Connor kevin at koconnor.net
Wed Feb 3 05:18:44 CET 2016


Add functions to verify and obtain PCI BARs (Base Address Registers).
These new functions check that the requested BAR is of the right type
and appears valid.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/hw/pci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/hw/pci.h |  3 +++
 2 files changed, 61 insertions(+)

diff --git a/src/hw/pci.c b/src/hw/pci.c
index a241d06..86b7d54 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -10,6 +10,7 @@
 #include "pci.h" // pci_config_writel
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "romfile.h" // romfile_loadint
+#include "stacks.h" // wait_preempt
 #include "string.h" // memset
 #include "util.h" // udelay
 #include "x86.h" // outl
@@ -271,6 +272,63 @@ int pci_bridge_has_region(struct pci_device *pci,
     return pci_config_readb(pci->bdf, base) != 0;
 }
 
+// Enable PCI bus-mastering (ie, DMA) support on a pci device
+void
+pci_enable_busmaster(struct pci_device *pci)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+}
+
+// Verify an IO bar and return it to the caller
+u16
+pci_enable_iobar(struct pci_device *pci, u32 addr)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
+        warn_internalerror();
+        return 0;
+    }
+    bar &= PCI_BASE_ADDRESS_IO_MASK;
+    if (bar == 0 || bar > 0xffff) {
+        warn_internalerror();
+        return 0;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+    return bar;
+}
+
+// Verify a memory bar and return it to the caller
+void *
+pci_enable_membar(struct pci_device *pci, u32 addr)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+        warn_internalerror();
+        return NULL;
+    }
+    if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        u32 high = pci_config_readl(pci->bdf, addr+4);
+        if (high) {
+            dprintf(1, "Can not map memory bar over 4Gig\n");
+            return NULL;
+        }
+    }
+    bar &= PCI_BASE_ADDRESS_MEM_MASK;
+    if (bar + 4*1024*1024 < 20*1024*1024) {
+        // Bar doesn't look valid (it is in last 4M or first 16M)
+        warn_internalerror();
+        return NULL;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+    return (void*)bar;
+}
+
 void
 pci_reboot(void)
 {
diff --git a/src/hw/pci.h b/src/hw/pci.h
index fc5e7b9..8e39753 100644
--- a/src/hw/pci.h
+++ b/src/hw/pci.h
@@ -126,6 +126,9 @@ struct pci_device *pci_find_init_device(const struct pci_device_id *ids
 u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
 int pci_bridge_has_region(struct pci_device *pci,
                           enum pci_region_type region_type);
+void pci_enable_busmaster(struct pci_device *pci);
+u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
+void *pci_enable_membar(struct pci_device *pci, u32 addr);
 void pci_reboot(void);
 
 #endif
-- 
2.5.0




More information about the SeaBIOS mailing list