From 5a6cc6868a22528c17a4f3b142a5509f407c5867 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Wed, 12 Sep 2018 11:45:52 +0900 Subject: [PATCH] add /proc/pci, lspci --- apps/lspci.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ modules/procfs.c | 63 +++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 apps/lspci.c diff --git a/apps/lspci.c b/apps/lspci.c new file mode 100644 index 00000000..b2e355f3 --- /dev/null +++ b/apps/lspci.c @@ -0,0 +1,131 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * lspci - Print information about connected PCI devices. + * + */ +#include +#include +#include +#include + +struct device_class { + char * code; + char * name; +} device_classes[] = { + {"0101", "IDE interface"}, + {"0102", "Floppy disk controller"}, + {"0105", "ATA controller"}, + {"0106", "SATA controller"}, + {"0200", "Ethernet controller"}, + {"0280", "Network controller"}, + {"0300", "VGA compatible controller"}, + {"0380", "Display controller"}, + {"0401", "Multimedia audio controller"}, + {"0403", "Audio device"}, + {"0480", "Multimedia controller"}, + {"0600", "Host bridge"}, + {"0601", "ISA bridge"}, + {"0680", "Bridge"}, + {"0880", "System peripheral"}, + {NULL, NULL}, +}; + +static void show_usage(char * argv[]) { + fprintf(stderr, + "lspci - show information about PCI devices\n" + "\n" + "usage: %s [-n]\n" + "\n" + " -n \033[3mshow numeric device codes\033[0m\n" + " -? \033[3mshow this help text\033[0m\n" + "\n", argv[0]); +} + +int main(int argc, char * argv[]) { + int numeric = 0; + int opt; + while ((opt = getopt(argc, argv, "n?")) != -1) { + switch (opt) { + case '?': + show_usage(argv); + return 0; + case 'n': + numeric = 1; + break; + } + } + + FILE * f = fopen("/proc/pci","r"); + if (!f) { + fprintf(stderr, "%s: %s: %s\n", argv[0], "/proc/pci", strerror(errno)); + return 1; + } + + while (!feof(f)) { + char line[1024]; + fgets(line, 1024, f); + if (line[0] == ' ') { + /* Skip; don't care about this information */ + continue; + } + /* Read bus, etc. verbatim */ + char * device_bus = line; + + /* Read device class */ + char * device_class = strstr(line," ("); + if (!device_class) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_class = '\0'; + device_class++; /* space */ + device_class++; /* ( */ + + char * device_vendor = strstr(device_class, ", "); + if (!device_vendor) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_vendor = '\0'; + device_vendor++; /* comma */ + device_vendor++; /* space */ + + char * device_code = strstr(device_vendor, ":"); + if (!device_code) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_code = '\0'; + device_code++; /* colon */ + + char * device_name = strstr(device_code, ") "); + if (!device_name) { + fprintf(stderr, "%s: parse error\n", argv[0]); + return 1; + } + *device_name = '\0'; + device_name++; /* ) */ + device_name++; /* space */ + + char * linefeed = strstr(device_name, "\n"); + if (linefeed) *linefeed = '\0'; + + if (numeric) { + fprintf(stdout, "%s %s: %s:%s\n", device_bus, device_class, device_vendor, device_code); + } else { + for (struct device_class * c = device_classes; c->code; ++c) { + if (!strcmp(device_class, c->code)) { + device_class = c->name; + break; + } + } + /* TODO: We should also look up vendor + device names ourselves and possibly remove them from the kernel */ + fprintf(stdout, "%s %s: %s\n", device_bus, device_class, device_name); + } + } + + return 0; +} diff --git a/modules/procfs.c b/modules/procfs.c index d1a89f73..de1aa3cb 100644 --- a/modules/procfs.c +++ b/modules/procfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry)) #define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry)) @@ -620,6 +621,67 @@ static uint32_t irq_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_ return size; } +/** + * Basically the same as the kdebug `pci` command. + */ +struct _pci_buf { + size_t offset; + char *buffer; +}; + +static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + + struct _pci_buf * b = extra; + + b->offset += sprintf(b->buffer + b->offset, "%2x:%2x.%d (%4x, %4x:%4x) %s %s\n", + (int)pci_extract_bus(device), + (int)pci_extract_slot(device), + (int)pci_extract_func(device), + (int)pci_find_type(device), + vendorid, + deviceid, + pci_vendor_lookup(vendorid), + pci_device_lookup(vendorid,deviceid)); + + b->offset += sprintf(b->buffer + b->offset, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); + b->offset += sprintf(b->buffer + b->offset, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); + + b->offset += sprintf(b->buffer + b->offset, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); + b->offset += sprintf(b->buffer + b->offset, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); + b->offset += sprintf(b->buffer + b->offset, " Interrupt: %d", pci_get_interrupt(device)); + b->offset += sprintf(b->buffer + b->offset, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); +} + +static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + size_t * count = extra; + (*count)++; +} + +static uint32_t pci_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + size_t count = 0; + pci_scan(&scan_count, -1, &count); + + struct _pci_buf b = {0,NULL}; + b.buffer = malloc(count * 512); + + pci_scan(&scan_hit_list, -1, &b); + + size_t _bsize = b.offset; + if (offset > _bsize) { + free(b.buffer); + return 0; + } + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, b.buffer, size); + free(b.buffer); + return size; +} + static struct procfs_entry std_entries[] = { {-1, "cpuinfo", cpuinfo_func}, {-2, "meminfo", meminfo_func}, @@ -634,6 +696,7 @@ static struct procfs_entry std_entries[] = { {-11,"loader", loader_func}, {-12,"irq", irq_func}, {-13,"pat", pat_func}, + {-14,"pci", pci_func}, }; static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) {