diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b21dfbb..8ec3a4e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Install build tools - run: sudo apt update && sudo apt install build-essential crossbuild-essential-i386 xz-utils + run: sudo apt update && sudo apt install build-essential crossbuild-essential-i386 gcc-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-i686-dev gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-x86-64-dev xz-utils - name: Download OpenWatcom if: steps.cache.outputs.cache-hit != 'true' run: | @@ -31,6 +31,10 @@ jobs: cd /opt/pciutils-* make CC=i686-linux-gnu-gcc ZLIB=no DNS=no SHARED=no sudo make install-lib + make clean all CROSS_COMPILE=i686-w64-mingw32- HOST=i586-windows ZLIB=no DNS=no SHARED=no IDSDIR="" + sudo make install-lib PREFIX=/usr/i686-w64-mingw32 + make clean all CROSS_COMPILE=x86_64-w64-mingw32- HOST=x86_64-windows ZLIB=no DNS=no SHARED=no IDSDIR="" + sudo make install-lib PREFIX=/usr/x86_64-w64-mingw32 - uses: actions/checkout@v4 - name: Build `cp437` run: | @@ -57,7 +61,9 @@ jobs: cd ${{ github.workspace }}/pcireg wmake make -f Makefile.uefi ARCH=x86_64 - make -f Makefile.gcc clean default CC=i686-linux-gnu-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static + make -f Makefile.gcc clean all CC=i686-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 DEST=pciregw + make -f Makefile.gcc clean all CC=x86_64-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 DEST=pciregw64 + make -f Makefile.gcc clean all CC=i686-linux-gnu-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static python3 pciids.py - name: Build `usblgoff` run: | diff --git a/clib/clib_pci.c b/clib/clib_pci.c index f0ff8c1..3da73e0 100644 --- a/clib/clib_pci.c +++ b/clib/clib_pci.c @@ -20,6 +20,9 @@ #else # include #endif +#ifdef PCI_LIB_VERSION +# include +#endif #include "clib_pci.h" #include "clib_sys.h" @@ -27,6 +30,8 @@ uint8_t pci_mechanism = 0, pci_device_count = 0; #ifdef PCI_LIB_VERSION static struct pci_access *pacc; static struct pci_dev *pdev; +static uint32_t last_addr = -1; +static const char win_notice[] = "NOTICE: These are dummy configuration registers generated by libpci, as it cannot access the real ones under Windows. It does not reflect the device's actual configuration."; #endif /* Configuration functions. */ @@ -116,8 +121,67 @@ pci_get_mem_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t si #ifdef PCI_LIB_VERSION static void -dummy_print(char *msg, ...) +pci_printf(char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + putc('\n', stderr); + va_end(ap); +} + +static void +pci_init_dev(uint8_t bus, uint8_t dev, uint8_t func) +{ + struct pci_dev *other; + uint32_t addr = (bus << 16) | (dev << 8) | func; + if (addr != last_addr) { + last_addr = addr; + + if (!pacc->devices) { + libpci_scan_bus(pacc); + + /* Generate additional configuration values not generated by + libpci's emulated configuration space code on Windows. */ + if (pacc->method == PCI_ACCESS_WIN32_CFGMGR32) { + /* Create cache and read generated values for every device. */ + for (pdev = pacc->devices; pdev; pdev = pdev->next) { + pdev->cache = malloc(0x40 + sizeof(win_notice)); + pci_setup_cache(pdev, pdev->cache, 0x40 + sizeof(win_notice)); + pci_read_block(pdev, 0, pdev->cache, 64); + if (pdev->cache[0x0e] & 0x7f) + pdev->cache[0x19] = -1; + strcpy(&pdev->cache[0x40], win_notice); + } + + /* Perform scan to fill in some values. */ + for (pdev = pacc->devices; pdev; pdev = pdev->next) { + /* Perform recursive scan to set multi-function bit if another function is present. */ + for (other = pacc->devices; other; other = other->next) { + if (!pdev->func && (other->domain == pdev->domain) && (other->bus == pdev->bus) && (other->dev == pdev->dev) && other->func) { + pdev->cache[0x0e] |= 0x80; + break; + } + } + + /* Set secondary bus value and cascade subordinate bus value to parents. */ + other = pdev; + while (other->parent) { + other->parent->cache[0x19] = other->bus; + if (other->parent->cache[0x1a] < pdev->bus) + other->parent->cache[0x1a] = pdev->bus; + other = other->parent; + } + } + } + } + + for (pdev = pacc->devices; pdev; pdev = pdev->next) { + if (!pdev->domain && (pdev->bus == bus) && (pdev->dev == dev) && (pdev->func == func)) + break; + } + } } #endif @@ -125,21 +189,23 @@ int pci_init() { #ifdef PCI_LIB_VERSION +# ifndef _WIN32 if (iopl(3)) { perror("iopl"); + goto pci_init_fail; + } +# endif + + pacc = pci_alloc(); + if (!pacc) { + printf("Failed to allocate pci_access structure.\n"); pci_init_fail: pci_mechanism = 0; return pci_mechanism; } - pacc = pci_alloc(); - if (!pacc) { - printf("Failed to allocate pci_access structure.\n"); - goto pci_init_fail; - } - + pacc->error = pacc->warning = pacc->debug = pci_printf; libpci_init(pacc); - pacc->error = pacc->warning = pacc->debug = dummy_print; pci_mechanism = 1; pci_device_count = 32; @@ -174,7 +240,7 @@ uint8_t pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); return pdev ? pci_read_byte(pdev, reg) : 0xff; #else uint8_t ret; @@ -209,7 +275,7 @@ uint16_t pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); return pdev ? pci_read_word(pdev, reg) : 0xffff; #else uint16_t ret, data_port; @@ -243,7 +309,7 @@ uint32_t pci_readl(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); return pdev ? pci_read_long(pdev, reg) : 0xffffffff; #else uint16_t data_port; @@ -281,7 +347,7 @@ void pci_writeb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t val) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); if (pdev) pci_write_byte(pdev, reg, val); #else @@ -314,7 +380,7 @@ void pci_writew(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t val) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); if (pdev) pci_write_word(pdev, reg, val); #else @@ -347,7 +413,7 @@ void pci_writel(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val) { #ifdef PCI_LIB_VERSION - pdev = pci_get_dev(pacc, 0, bus, dev, func); + pci_init_dev(bus, dev, func); if (pdev) pci_write_long(pdev, reg, val); #else @@ -382,7 +448,8 @@ pci_scan_bus(uint8_t bus, uint16_t ven_id, uint16_t dev_id)) { #ifdef PCI_LIB_VERSION - libpci_scan_bus(pacc); + if (!pacc->devices) + libpci_scan_bus(pacc); for (pdev = pacc->devices; pdev; pdev = pdev->next) { if (pdev->domain || (pdev->bus != bus)) continue; diff --git a/clib/clib_sys.h b/clib/clib_sys.h index c992728..bd25ccd 100644 --- a/clib/clib_sys.h +++ b/clib/clib_sys.h @@ -64,7 +64,7 @@ void outl(uint16_t port, uint32_t data); parm[dx][ax cx] modify[ax cx]; # endif #else -# if defined(__GNUC__) && !defined(__POSIX_UEFI__) +# if defined(__GNUC__) && !defined(__POSIX_UEFI__) && !defined(_WIN32) # define inb sys_inb # define outb sys_outb # define inw sys_inw diff --git a/clib/clib_term.c b/clib/clib_term.c index 519bc4a..a48f924 100644 --- a/clib/clib_term.c +++ b/clib/clib_term.c @@ -17,6 +17,9 @@ */ #ifdef __POSIX_UEFI__ # include +#elif defined(_WIN32) +# include +# include #else # include # ifdef __GNUC__ @@ -127,6 +130,54 @@ term_set_cursor_pos(uint8_t x, uint8_t y) fflush(stdout); return 1; } +#elif defined(_WIN32) +static CONSOLE_SCREEN_BUFFER_INFO info_cache; + +static CONSOLE_SCREEN_BUFFER_INFO * +term_get_info() +{ + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (h && GetConsoleScreenBufferInfo(h, &info_cache)) + return &info_cache; + return NULL; +} + +int +term_get_size_x() +{ + CONSOLE_SCREEN_BUFFER_INFO *info = term_get_info(); + return info ? (info->srWindow.Right - info->srWindow.Left + 1) : 80; +} + +int +term_get_size_y() +{ + CONSOLE_SCREEN_BUFFER_INFO *info = term_get_info(); + return info ? (info->srWindow.Bottom - info->srWindow.Top + 1) : 25; +} + +int +term_get_cursor_pos(uint8_t *x, uint8_t *y) +{ + CONSOLE_SCREEN_BUFFER_INFO *info = term_get_info(); + if (!info) + return 0; + *x = info->dwCursorPosition.X; + *y = info->dwCursorPosition.Y; + return 1; +} + +int +term_set_cursor_pos(uint8_t x, uint8_t y) +{ + COORD coords; + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (!h) + return 0; + coords.X = x; + coords.Y = y; + return !!SetConsoleCursorPosition(h, coords); +} #else int term_get_size_x() @@ -170,6 +221,9 @@ term_final_linebreak() void term_unbuffer_stdout() { +#ifdef _WIN32 + SetConsoleOutputCP(65001); +#endif } void diff --git a/clib/gcc.mk b/clib/gcc.mk index c3b799e..3afd6e6 100644 --- a/clib/gcc.mk +++ b/clib/gcc.mk @@ -18,13 +18,13 @@ VPATH = . ../clib CC ?= "gcc" -default: $(DEST) +all: $(DEST) %.o: %.c $(HEADERS) $(CC) -I../clib $(CFLAGS) -c $< -o $@ $(DEST): $(OBJS) - $(CC) $(OBJS) $(LDFLAGS) -o $@ + $(CC) $(OBJS) $(LDFLAGS) $(LDAPPEND) -o $@ chmod +x $@ || true clean: diff --git a/pcireg/Makefile.gcc b/pcireg/Makefile.gcc index 69d1e85..e314b04 100644 --- a/pcireg/Makefile.gcc +++ b/pcireg/Makefile.gcc @@ -17,6 +17,6 @@ export OBJS = pcireg.o clib_pci.o clib_std.o clib_sys.o clib_term.o export DEST = pcireg -override LDFLAGS += -lpci +override LDFLAGS += -lpci $(LDAPPEND) include ../clib/gcc.mk diff --git a/pcireg/README.md b/pcireg/README.md index 0803056..76fdada 100644 --- a/pcireg/README.md +++ b/pcireg/README.md @@ -1,6 +1,6 @@ pcireg ====== -DOS, UEFI and Linux tool for reading, writing and dumping PCI configuration space registers; scanning the PCI bus; and more. +DOS, UEFI, Windows and Linux tool for reading, writing (where supported) and dumping PCI configuration space registers; scanning the PCI bus; and more. Usage ----- @@ -42,6 +42,29 @@ Building * **Linux:** Run `make -f Makefile.uefi ARCH=x86_64` with a GCC toolchain installed. * Note that 32-bit UEFI targets are not supported yet. +### Windows target + +* **Windows:** Currently not supported due to issues building `pciutils` on MSYS2. +* **Linux:** Build `pciutils` then `pcireg` itself with a MinGW toolchain installed. + * 32-bit: + ``` + git clone https://github.com/pciutils/pciutils.git pciutils + cd pciutils + make CROSS_COMPILE=i686-w64-mingw32- HOST=i586-windows ZLIB=no DNS=no SHARED=no IDSDIR="" + sudo make install-lib PREFIX=/usr/i686-w64-mingw32 + cd .. + make -f Makefile.gcc CC=i686-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 DEST=pciregw + ``` + * 64-bit: + ``` + git clone https://github.com/pciutils/pciutils.git pciutils + cd pciutils + make CROSS_COMPILE=x86_64-w64-mingw32- HOST=x86_64-windows ZLIB=no DNS=no SHARED=no IDSDIR="" + sudo make install-lib PREFIX=/usr/x86_64-w64-mingw32 + cd .. + make -f Makefile.gcc CC=x86_64-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 DEST=pciregw64 + ``` + ### Linux target * **Linux:** Run `make -f Makefile.gcc` with a GCC toolchain and development files for `libpci` installed.