0

I want to find all PCI devices with as little Linux use as possible because of exercise.

I find in scattered docs to read address 0xCF8 or maybe there is some protocol where I write to that address in RAM but I haven't been able to hack it.

Any attempts to read that address or write some config address to write to it segfault in simple C/C++ programs. I thought I might need ring 0 so I created a Linux kernel module but the program got killed just trying to read that 0xCF8 address as a MULL pointer dereference?

I am aware of lspci, /sys/bus, etc... This is a little more advanced please.

4
  • 0xCF8 is not a memory mapped address, it's an IO port, and if you don't want to rely on linux functions to access it, you will need to use assembly, in particular the instructions out and in Commented Nov 28, 2023 at 23:08
  • Modern systems have PCI config space mapped to memory (MMIO) addresses; that makes it a lot easier and quicker to access. The ACPI table "MCFG" has the MMIO address. Commented Nov 29, 2023 at 4:40
  • To use CF8/CFC, you have to write the address of the PCI register that you want to access to I/O port CF8h using out and then access the register by reading or writing to CFCh using in or out. See wikipedia.org/wiki/PCI_configuration_space. Commented Nov 29, 2023 at 4:52
  • I have the IO port working now. Didn't get IO port vs. mem map init. I'll get the mem map. Is there a reason for pref? Docs are '05 like Wales Commented Nov 30, 2023 at 22:26

1 Answer 1

1

You can probably do everything you want in userspace using pcilib, which is used by lspci, etc., but isn't well documented. If you must use kernel code, carry on reading…

Linux kernel code can use the for_each_pci_dev() macro and pointers to struct pci_dev (both defined by #include <linux/pci.h>) to iterate over all PCI device like this:

struct pci_dev *pdev;

pdev = NULL; /* IMPORTANT: Start with NULL unless continuing a previous loop. */
for_each_pci_dev(pdev) {
    /* Examine pdev-> members here. */
}

Each iteration of the loop will decrement ("put") the reference count of the current struct pci_dev pointed to by pdev (if it is not NULL) and will increment ("get") the reference count of the next struct pci_dev pointed to by pdev. When the loop terminates naturally after the last PCI device has been seen, pdev will be NULL. If the code breaks out of the loop early so that pdev is still valid, it may need to decrement ("put") the reference with pci_dev_put(pdev); when it has finished with it.

for_each_pci_dev(pdev) uses pci_get_device() internally, so you could replace for_each_pci_dev(pdev) with the following while loop:

struct pci_dev *pdev;

pdev = NULL; /* IMPORTANT: Start with NULL unless continuing a previous loop. */
while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev) != NULL) {
    /* Examine pdev-> members here. */
}

The PCI_ANY_ID value matches any PCI vendor ID or PCI device ID, so you can change the first two arguments of pci_get_device() to only iterate over PCI devices with a specific vendor and/or device ID.

Using your own while (or for) loop also allows you to change the pci_get_device() calls to similar functions. For example pci_get_subsys() can match devices with specific PCI vendor, device, subsystem vendor, and/or subsystem device IDs, and pci_get_class() can match devices with specific PCI class codes.

Sign up to request clarification or add additional context in comments.

3 Comments

I think I got it. I didn't get it
You need to take pci_rescan_remove_lock. PCI is hotpluggable bus. Also even after getting a pointer to a PCI device object it may be already stale.
@0andriy It should work fine without using the rescan remove lock, although the list of PCI devices may be slightly fuzzy if devices are added or removed during the traversal through the list. The pointers to the struct pci_dev objects will not go stale, although it is possible that the underlying hardware may have been surprise removed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.