diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 325887f..60ddea3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,7 +66,6 @@ jobs: make -f Makefile.gcc clean all CC=i686-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 CP437_CONV=y DEST=pciregw make -f Makefile.gcc clean all CC=x86_64-w64-mingw32-gcc CFLAGS=-I/usr/local/include LDFLAGS=-static LDAPPEND=-lcfgmgr32 CP437_CONV=y 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: | cd ${{ github.workspace }}/usblgoff diff --git a/.gitignore b/.gitignore index 5de3fef..44b336b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,4 @@ pci?????.bin *.efi pcireg/pcireg ac97/ac97 -PCIIDS.BIN +PCIIDS_*.BIN diff --git a/pcireg/Makefile b/pcireg/Makefile index a6e6054..259d00b 100644 --- a/pcireg/Makefile +++ b/pcireg/Makefile @@ -16,7 +16,7 @@ # SYSTEM = PMODEW -OBJS = pcireg.obj clib_pci.obj clib_std.obj clib_sys.obj clib_term.obj +OBJS = pcireg.obj lh5_extract.obj clib_pci.obj clib_std.obj clib_sys.obj clib_term.obj DEST = PCIREG.EXE !include ../clib/watcom.mk diff --git a/pcireg/Makefile.gcc b/pcireg/Makefile.gcc index e314b04..4576cbb 100644 --- a/pcireg/Makefile.gcc +++ b/pcireg/Makefile.gcc @@ -15,7 +15,7 @@ # Copyright 2023 RichardG. # -export OBJS = pcireg.o clib_pci.o clib_std.o clib_sys.o clib_term.o +export OBJS = pcireg.o lh5_extract.o clib_pci.o clib_std.o clib_sys.o clib_term.o export DEST = pcireg override LDFLAGS += -lpci $(LDAPPEND) diff --git a/pcireg/Makefile.uefi b/pcireg/Makefile.uefi index 265f92a..84d3b32 100644 --- a/pcireg/Makefile.uefi +++ b/pcireg/Makefile.uefi @@ -15,7 +15,7 @@ # Copyright 2021 RichardG. # -export OBJS = pcireg.o clib_pci.o clib_std.o clib_sys.o clib_term.o +export OBJS = pcireg.o lh5_extract.o clib_pci.o clib_std.o clib_sys.o clib_term.o export DEST = PCIREG.EFI include ../clib/uefi.mk diff --git a/pcireg/PCIIDS.LHA b/pcireg/PCIIDS.LHA new file mode 100644 index 0000000..cec13b8 Binary files /dev/null and b/pcireg/PCIIDS.LHA differ diff --git a/pcireg/README.md b/pcireg/README.md index 8fca133..2cb78bb 100644 --- a/pcireg/README.md +++ b/pcireg/README.md @@ -71,5 +71,5 @@ Building ### PCI ID database -* Run `python3 pciids.py` to update the `PCIIDS.BIN` file. +* Run `python3 pciids.py` to update the PCI ID files, then `lha a1o5 PCIIDS.LHA PCIIDS_*.BIN` to compress them in the expected format. * The latest version of `pci.ids` is automatically downloaded and used to update the database. diff --git a/pcireg/lh5_extract.c b/pcireg/lh5_extract.c new file mode 100644 index 0000000..d740f3d --- /dev/null +++ b/pcireg/lh5_extract.c @@ -0,0 +1,562 @@ +/* + * This file is a severely cut down and cleaned up version of lha. + * + * All changes compared to lha-svn894 are: + * + * Copyright 2009 Luc Verhaegen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * LHA has a terrible history... It dates back to 1988, has had many different + * authors and has been mostly Public Domain Software. + * + * Since 1999, Koji Arai has been doing most of + * the work at http://sourceforge.jp/projects/lha/. + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include "lh5_extract.h" + +#ifndef le16toh +# define le16toh(x) x +#endif +#ifndef le32toh +# define le32toh(x) x +#endif + +/* + * LHA header parsing. + */ +static int calc_sum(unsigned char *p, int len) +{ + int sum = 0; + + while (len--) + sum += *p++; + + return sum & 0xff; +} + +/* + * level 1 header + * + * + * offset size field name + * ----------------------------------- + * 0 1 header size [*1] + * 1 1 header sum + * ------------------------------------- + * 2 5 method ID ^ + * 7 4 skip size [*2] | + * 11 4 original size | + * 15 2 time | + * 17 2 date | + * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25) + * 20 1 level (0x01 fixed) | + * 21 1 name length | + * 22 X filename | + * X+ 22 2 file crc (CRC-16) | + * X+ 24 1 OS ID | + * X +25 Y ??? | + * X+Y+25 2 next-header size v + * ------------------------------------------------- + * X+Y+27 Z ext-header ^ + * : | + * ----------------------------------- | [*2] skip size + * X+Y+Z+27 data | + * : v + * ------------------------------------------------- + * + */ +unsigned int +LH5HeaderParse(unsigned char *Buffer, int BufferSize, + unsigned int *original_size, unsigned int *packed_size, + char **name, unsigned short *crc) +{ + unsigned int offset; + unsigned char header_size, checksum, name_length; + + if (BufferSize < 27) { + fprintf(stderr, + "Error: Packed Buffer is too small to contain an lha header.\n"); + return 0; + } + + /* check attribute */ + if (Buffer[19] != 0x20) { + fprintf(stderr, "Error: Invalid lha header attribute byte.\n"); + return 0; + } + + /* check method */ + if (memcmp(Buffer + 2, "-lh5-", 5) != 0) { + fprintf(stderr, "Error: Compression method is not LZHUFF5.\n"); + return 0; + } + + /* check header level */ + if (Buffer[20] != 1) { + fprintf(stderr, "Error: Header level %d is not supported\n", + Buffer[20]); + return 0; + } + + /* read in the full header */ + header_size = Buffer[0]; + if (BufferSize < (header_size + 2)) { + fprintf(stderr, + "Error: Packed Buffer is too small to contain the full header.\n"); + return 0; + } + + /* verify checksum */ + checksum = Buffer[1]; + if (calc_sum(Buffer + 2, header_size) != checksum) + fprintf(stderr, "Warning: Invalid lha header checksum.\n"); + + *packed_size = le32toh(*(unsigned int *)(Buffer + 7)); + *original_size = le32toh(*(unsigned int *)(Buffer + 11)); + + name_length = Buffer[21]; + *name = malloc(name_length + 1); + if (*name) { + memcpy(*name, (char *)Buffer + 22, name_length); + (*name)[name_length] = '\0'; + } + + *crc = le16toh(*(unsigned short *)(Buffer + 22 + name_length)); + + offset = header_size + 2; + /* Skip extended headers */ + while (1) { + unsigned short extend_size = + le16toh(*(unsigned short *)(Buffer + offset - 2)); + + if (!extend_size) + break; + + *packed_size -= extend_size; + offset += extend_size; + + if (BufferSize < offset) { + fprintf(stderr, + "Warning: Buffer to small to contain extended header.\n"); + offset = header_size + 2; + break; + } + } + + return offset; +} + +/* + * CRC Calculation. + */ +#define CRCPOLY 0xA001 /* CRC-16 (x^16+x^15+x^2+1) */ + +unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize) +{ + unsigned short CRCTable[0x100]; + unsigned short crc; + int i; + + /* First, initialise our CRCTable */ + for (i = 0; i < 0x100; i++) { + unsigned short r = i; + unsigned int j; + + for (j = 0; j < 8; j++) { + if (r & 1) + r = (r >> 1) ^ CRCPOLY; + else + r >>= 1; + } + CRCTable[i] = r; + } + + /* now go over the entire Buffer */ + crc = 0; + for (i = 0; i < BufferSize; i++) + crc = CRCTable[(crc ^ Buffer[i]) & 0xFF] ^ (crc >> 8); + + return crc; +} + +/* + * Bit handling code. + */ +static unsigned char *CompressedBuffer; +static int CompressedSize; +static int CompressedOffset; + +static unsigned short bitbuf; +static unsigned char subbitbuf, bitcount; + +static void BitBufInit(unsigned char *Buffer, int BufferSize) +{ + CompressedBuffer = Buffer; + CompressedOffset = 0; + CompressedSize = BufferSize; + + bitbuf = 0; + subbitbuf = 0; + bitcount = 0; +} + +static void fillbuf(unsigned char n) +{ /* Shift bitbuf n bits left, read n bits */ + while (n > bitcount) { + n -= bitcount; + bitbuf = (bitbuf << bitcount) + (subbitbuf >> (8 - bitcount)); + + if (CompressedOffset < CompressedSize) { + subbitbuf = CompressedBuffer[CompressedOffset]; + CompressedOffset++; + } else + subbitbuf = 0; + + bitcount = 8; + } + bitcount -= n; + bitbuf = (bitbuf << n) + (subbitbuf >> (8 - n)); + subbitbuf <<= n; +} + +static unsigned short getbits(unsigned char n) +{ + unsigned short x; + + x = bitbuf >> (16 - n); + fillbuf(n); + + return x; +} + +static unsigned short peekbits(unsigned char n) +{ + unsigned short x; + + x = bitbuf >> (16 - n); + + return x; +} + +/* + * + * LHA extraction. + * + */ +#define MIN(a,b) ((a) <= (b) ? (a) : (b)) + +#define LZHUFF5_DICBIT 13 /* 2^13 = 8KB sliding dictionary */ +#define MAXMATCH 256 /* formerly F (not more than 255 + 1) */ +#define THRESHOLD 3 /* choose optimal value */ +#define NP (LZHUFF5_DICBIT + 1) +#define NT (16 + 3) /* USHORT + THRESHOLD */ +#define NC (255 + MAXMATCH + 2 - THRESHOLD) + +#define PBIT 4 /* smallest integer such that (1 << PBIT) > * NP */ +#define TBIT 5 /* smallest integer such that (1 << TBIT) > * NT */ +#define CBIT 9 /* smallest integer such that (1 << CBIT) > * NC */ + +/* #if NT > NP #define NPT NT #else #define NPT NP #endif */ +#define NPT 0x80 + +static unsigned short left[2 * NC - 1], right[2 * NC - 1]; + +static unsigned short c_table[4096]; /* decode */ +static unsigned short pt_table[256]; /* decode */ + +static unsigned char c_len[NC]; +static unsigned char pt_len[NPT]; + +static int +make_table(short nchar, unsigned char bitlen[], short tablebits, + unsigned short table[]) +{ + unsigned short count[17]; /* count of bitlen */ + unsigned short weight[17]; /* 0x10000ul >> bitlen */ + unsigned short start[17]; /* first code of bitlen */ + unsigned short total; + unsigned int i, l; + int j, k, m, n, avail; + unsigned short *p; + + avail = nchar; + + /* initialize */ + for (i = 1; i <= 16; i++) { + count[i] = 0; + weight[i] = 1 << (16 - i); + } + + /* count */ + for (i = 0; i < nchar; i++) { + if (bitlen[i] > 16) { + /* CVE-2006-4335 */ + fprintf(stderr, "Error: Bad table (case a)\n"); + return -1; + } else + count[bitlen[i]]++; + } + + /* calculate first code */ + total = 0; + for (i = 1; i <= 16; i++) { + start[i] = total; + total += weight[i] * count[i]; + } + if (((total & 0xffff) != 0) || (tablebits > 16)) { /* 16 for weight below */ + fprintf(stderr, "Error: make_table(): Bad table (case b)\n"); + return -1; + } + + /* shift data for make table. */ + m = 16 - tablebits; + for (i = 1; i <= tablebits; i++) { + start[i] >>= m; + weight[i] >>= m; + } + + /* initialize */ + j = start[tablebits + 1] >> m; + k = MIN(1 << tablebits, 4096); + if (j != 0) + for (i = j; i < k; i++) + table[i] = 0; + + /* create table and tree */ + for (j = 0; j < nchar; j++) { + k = bitlen[j]; + if (k == 0) + continue; + l = start[k] + weight[k]; + if (k <= tablebits) { + /* code in table */ + l = MIN(l, 4096); + for (i = start[k]; i < l; i++) + table[i] = j; + } else { + /* code not in table */ + i = start[k]; + if ((i >> m) > 4096) { + /* CVE-2006-4337 */ + fprintf(stderr, "Error: Bad table (case c)"); + exit(1); + } + p = &table[i >> m]; + i <<= tablebits; + n = k - tablebits; + /* make tree (n length) */ + while (--n >= 0) { + if (*p == 0) { + right[avail] = left[avail] = 0; + *p = avail++; + } + if (i & 0x8000) + p = &right[*p]; + else + p = &left[*p]; + i <<= 1; + } + *p = j; + } + start[k] = l; + } + return 0; +} + +static int read_pt_len(short nn, short nbit, short i_special) +{ + int i, c, n; + + n = getbits(nbit); + if (n == 0) { + c = getbits(nbit); + for (i = 0; i < nn; i++) + pt_len[i] = 0; + for (i = 0; i < 256; i++) + pt_table[i] = c; + } else { + i = 0; + while (i < MIN(n, NPT)) { + c = peekbits(3); + if (c != 7) + fillbuf(3); + else { + unsigned short mask = 1 << (16 - 4); + while (mask & bitbuf) { + mask >>= 1; + c++; + } + fillbuf(c - 3); + } + + pt_len[i++] = c; + if (i == i_special) { + c = getbits(2); + while (--c >= 0 && i < NPT) + pt_len[i++] = 0; + } + } + while (i < nn) + pt_len[i++] = 0; + + if (make_table(nn, pt_len, 8, pt_table) == -1) + return -1; + } + return 0; +} + +static int read_c_len(void) +{ + short i, c, n; + + n = getbits(CBIT); + if (n == 0) { + c = getbits(CBIT); + for (i = 0; i < NC; i++) + c_len[i] = 0; + for (i = 0; i < 4096; i++) + c_table[i] = c; + } else { + i = 0; + while (i < MIN(n, NC)) { + c = pt_table[peekbits(8)]; + if (c >= NT) { + unsigned short mask = 1 << (16 - 9); + do { + if (bitbuf & mask) + c = right[c]; + else + c = left[c]; + mask >>= 1; + } while (c >= NT && (mask || c != left[c])); /* CVE-2006-4338 */ + } + fillbuf(pt_len[c]); + if (c <= 2) { + if (c == 0) + c = 1; + else if (c == 1) + c = getbits(4) + 3; + else + c = getbits(CBIT) + 20; + while (--c >= 0) + c_len[i++] = 0; + } else + c_len[i++] = c - 2; + } + while (i < NC) + c_len[i++] = 0; + + if (make_table(NC, c_len, 12, c_table) == -1) + return -1; + } + return 0; +} + +static unsigned short decode_c_st1(void) +{ + unsigned short j, mask; + + j = c_table[peekbits(12)]; + if (j < NC) + fillbuf(c_len[j]); + else { + fillbuf(12); + mask = 1 << (16 - 1); + do { + if (bitbuf & mask) + j = right[j]; + else + j = left[j]; + mask >>= 1; + } while (j >= NC && (mask || j != left[j])); /* CVE-2006-4338 */ + fillbuf(c_len[j] - 12); + } + return j; +} + +static unsigned short decode_p_st1(void) +{ + unsigned short j, mask; + + j = pt_table[peekbits(8)]; + if (j < NP) + fillbuf(pt_len[j]); + else { + fillbuf(8); + mask = 1 << (16 - 1); + do { + if (bitbuf & mask) + j = right[j]; + else + j = left[j]; + mask >>= 1; + } while (j >= NP && (mask || j != left[j])); /* CVE-2006-4338 */ + fillbuf(pt_len[j] - 8); + } + if (j != 0) + j = (1 << (j - 1)) + getbits(j - 1); + return j; +} + +int +LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize, + unsigned char *OutputBuffer, int OutputBufferSize) +{ + unsigned short blocksize = 0; + unsigned int i, c; + int n = 0; + + BitBufInit(PackedBuffer, PackedBufferSize); + fillbuf(2 * 8); + + while (n < OutputBufferSize) { + if (blocksize == 0) { + blocksize = getbits(16); + + if (read_pt_len(NT, TBIT, 3) == -1) + return -1; + if (read_c_len() == -1) + return -1; + if (read_pt_len(NP, PBIT, -1) == -1) + return -1; + } + blocksize--; + c = decode_c_st1(); + + if (c < 256) + OutputBuffer[n++] = c; + else { + int length = c - 256 + THRESHOLD; + int offset = 1 + decode_p_st1(); + + if (offset > n) + return -1; + + for (i = 0; (i < length) && (n < OutputBufferSize); i++) { + OutputBuffer[n] = OutputBuffer[n - offset]; + n++; + } + } + } + return CompressedOffset; +} diff --git a/pcireg/lh5_extract.h b/pcireg/lh5_extract.h new file mode 100644 index 0000000..fbcd4e9 --- /dev/null +++ b/pcireg/lh5_extract.h @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Luc Verhaegen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef LH5_EXTRACT_H +#define LH5_EXTRACT_H + +unsigned int LH5HeaderParse(unsigned char *Buffer, int BufferSize, + unsigned int *original_size, + unsigned int *packed_size, + char **name, unsigned short *crc); + +unsigned short CRC16Calculate(unsigned char *Buffer, int BufferSize); + +int LH5Decode(unsigned char *PackedBuffer, int PackedBufferSize, + unsigned char *OutputBuffer, int OutputBufferSize); + +extern int lzari_in_bruteforce; +int unlzari(unsigned char *in, int insz, unsigned char *out, int outsz, char common); + +int unlzh(unsigned char *in, int insz, unsigned char *out, int outsz); + +#endif /* LH5_EXTRACT_H */ diff --git a/pcireg/pciids.py b/pcireg/pciids.py index 42299c1..ae31c3a 100644 --- a/pcireg/pciids.py +++ b/pcireg/pciids.py @@ -13,7 +13,7 @@ # # Authors: RichardG, # -# Copyright 2021 RichardG. +# Copyright 2021-2024 RichardG. # import pciutil, struct, sys @@ -26,8 +26,19 @@ def main(): vendor_db = device_db = subdevice_db = class_db = subclass_db = progif_db = string_db = b'' vendor_devices_offset = {} string_db_lookup = {} + device_db_pos = subdevice_db_pos = 0 vendor_has_termination = device_has_termination = class_has_termination = subclass_has_termination = progif_has_termination = False + def string_db_add(s): + if not s: + return 0xffffffff + string_db_pos = string_db_lookup.get(s, None) + if string_db_pos == None: + nonlocal string_db + string_db_pos = string_db_lookup[s] = len(string_db) + string_db += s + b'\x00' + return string_db_pos + # Enumerate device IDs, while also going through subdevice IDs. print('Enumerating devices and subdevices...') current_vendor_id = None @@ -37,15 +48,16 @@ def main(): # Add termination device entry if one isn't already present. if current_vendor_id != None and not device_has_termination: device_db += struct.pack('> 16 # Store the device entries offset for this vendor. - vendor_devices_offset[current_vendor_id] = len(device_db) + vendor_devices_offset[current_vendor_id] = device_db_pos # Enumerate this device's subdevices. - subdevice_db_pos = len(subdevice_db) + subdevice_db_pos_start = subdevice_db_pos subdevice_has_termination = False for pci_subid in sorted(pciutil._pci_subdevices.get(pci_id, {})): # Store a null device entries offset for this vendor if one isn't already present. @@ -57,42 +69,31 @@ def main(): subdevice = pciutil.clean_device(pciutil._pci_subdevices[pci_id][pci_subid]).encode('cp437', 'ignore')[:256] # Add to string database if a valid result was found. - if subdevice: - string_db_pos = string_db_lookup.get(subdevice, None) - if string_db_pos == None: - string_db_pos = string_db_lookup[subdevice] = len(string_db) - string_db += struct.pack('> 8) & 0xff, pci_subclass & 0xff, string_db_pos) @@ -166,50 +146,32 @@ def main(): progif_name = pciutil._pci_progifs[pci_progif].encode('cp437', 'ignore')[:256] # Add to string database if a valid result was found. - if progif_name: - string_db_pos = string_db_lookup.get(progif_name, None) - if string_db_pos == None: - string_db_pos = string_db_lookup[progif_name] = len(string_db) - string_db += struct.pack('> 16) & 0xff, (pci_progif >> 8) & 0xff, pci_progif & 0xff, string_db_pos) progif_has_termination = pci_progif == 0xffffff - # Create binary file. - print('Writing binary database...') - f = open('PCIIDS.BIN', 'wb') + # Create binary files. + print('Writing binary databases...') # List all databases with their respective termination flags. dbs = [ - (vendor_db, 14, vendor_has_termination), - (device_db, 10, device_has_termination), - (subdevice_db, 8, True), - (class_db, 5, class_has_termination), - (subclass_db, 6, subclass_has_termination), - (progif_db, 7, progif_has_termination), - (string_db, None, True), + ('V', vendor_db, 14, vendor_has_termination), + ('D', device_db, 10, device_has_termination), + ('S', subdevice_db, 8, True), + ('C', class_db, 5, class_has_termination), + ('U', subclass_db, 6, subclass_has_termination), + ('P', progif_db, 7, progif_has_termination), + ('T', string_db, None, True), ] - # Write header containing database offsets. - db_len = 4 * (len(dbs) - 1) - for db, entry_length, has_termination in dbs[:-1]: - db_len += len(db) - if not has_termination: - db_len += entry_length - f.write(struct.pack(' # endif #endif +#include "lh5_extract.h" #include "clib_pci.h" #include "clib_std.h" #include "clib_sys.h" @@ -100,7 +101,6 @@ static const char *bridge_flags[] = { }; static int term_width; -static FILE *pciids_f = NULL; #if defined(MSDOS) static union REGS regs; static struct SREGS seg_regs; @@ -112,45 +112,40 @@ static struct PACKED { # pragma pack(pop) #endif +static int pciids_cur_vendor; +static int pciids_cur_device; #pragma pack(push, 1) -static struct PACKED { - uint32_t device_db_offset, - subdevice_db_offset, - class_db_offset, - subclass_db_offset, - progif_db_offset, - string_db_offset; -} pciids_header; static struct PACKED { uint16_t vendor_id; - uint32_t devices_offset, - string_offset; -} pciids_vendor; + uint32_t devices_offset; + uint32_t string_offset; +} *pciids_vendor = NULL; static struct PACKED { uint16_t device_id; - uint32_t subdevices_offset, - string_offset; -} pciids_device; -static struct PACKED { - uint16_t subvendor_id, - subdevice_id; + uint32_t subdevices_offset; uint32_t string_offset; -} pciids_subdevice; +} *pciids_device = NULL; +static struct PACKED { + uint16_t subvendor_id; + uint16_t subdevice_id; + uint32_t string_offset; +} *pciids_subdevice = NULL; static struct PACKED { uint8_t class_id; uint32_t string_offset; -} pciids_class; +} *pciids_class = NULL; static struct PACKED { - uint8_t class_id, - subclass_id; + uint8_t class_id; + uint8_t subclass_id; uint32_t string_offset; -} pciids_subclass; +} *pciids_subclass = NULL; static struct PACKED { - uint8_t class_id, - subclass_id, - progif_id; + uint8_t class_id; + uint8_t subclass_id; + uint8_t progif_id; uint32_t string_offset; -} pciids_progif; +} *pciids_progif = NULL; +static char *pciids_string = NULL; #if defined(MSDOS) typedef struct { @@ -174,84 +169,118 @@ typedef struct { #pragma pack(pop) static int -pciids_open_database() +pciids_open_database(void **ptr, char id) { - /* No action is required if the file is already open. */ - if (pciids_f) + FILE *f; + size_t pos; + unsigned int header_size; + unsigned int original_size; + unsigned int packed_size; + uint8_t header[128]; + char *filename; + char target_filename[13]; + unsigned short crc; + uint8_t *buf; + + /* No action is required if the database is already loaded. */ + if (*ptr) return 0; - /* Open file, and stop if the open failed or the header couldn't be read. */ - pciids_f = fopen("PCIIDS.BIN", "r" FOPEN_BINARY); - if (pciids_f && (fread(&pciids_header, sizeof(pciids_header), 1, pciids_f) < 1)) { - fclose(pciids_f); - pciids_f = NULL; + /* Open archive, and stop if the open failed. */ + f = fopen("PCIIDS.LHA", "r" FOPEN_BINARY); + if (!f) { + f = NULL; + return 1; } - /* Return 0 if the file was opened successfully, 1 otherwise. */ - return !pciids_f; + /* Generate target filename. */ + strcpy(target_filename, "PCIIDS_@.BIN"); + target_filename[7] = id; + + /* Go through archive. */ + while (!feof(f)) { + /* Read LHA header. */ + pos = ftell(f); + if (!fread(header, sizeof(header), 1, f)) + break; + + /* Parse LHA header. */ + header_size = LH5HeaderParse(header, sizeof(header), &original_size, &packed_size, &filename, &crc); + if (!header_size) + break; /* invalid header */ + + /* Check filename. */ + crc = !strcmp(filename, target_filename); + free(filename); + if (crc) { + /* Allocate buffer for reading the compressed data. */ + buf = malloc(packed_size); + if (!buf) + goto fail; + + /* Allocate buffer for the decompressed data. */ + *ptr = malloc(original_size); + if (!*ptr) + goto fail; + + /* Read and decompress data. */ + fseek(f, pos + header_size, SEEK_SET); + if (!fread(buf, packed_size, 1, f)) + goto fail; + if (LH5Decode(buf, packed_size, *ptr, original_size) == -1) + goto fail; + + /* All done, close archive. */ + fclose(f); + return 0; + } + + /* Move on to the next header. */ + fseek(f, pos + header_size + packed_size, SEEK_SET); + } + +fail: + /* Entry not found or read/decompression failed. */ + printf("PCI ID database %c decompression failed\n", id); + fclose(f); + return 1; } static char * pciids_read_string(uint32_t offset) { - uint8_t length, *buf; - uint32_t sum; - int i; - /* Return nothing if the string offset is invalid. */ if (offset == 0xffffffff) return NULL; /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_string, 'T')) return NULL; - /* Seek to string offset. */ - fseek(pciids_f, pciids_header.string_db_offset + offset, SEEK_SET); - - /* Read string length, and return nothing if it's an empty string. */ - fread(&length, sizeof(length), 1, pciids_f); - if (length == 0) - return NULL; - - /* Read string into buffer. */ - buf = malloc(length + 1); - if (fread(buf, length, 1, pciids_f) < 1) { - /* Clean up and return nothing if the read failed. */ - free(buf); - return NULL; - } - buf[length] = '\0'; - - return buf; + return &pciids_string[offset]; } static int -pciids_find_vendor(uint16_t vendor_id) +find_vendor(uint16_t vendor_id) { /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_vendor, 'V')) return 0; - /* Seek to vendor database. */ - fseek(pciids_f, sizeof(pciids_header), SEEK_SET); - - /* Read vendor entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_vendor, sizeof(pciids_vendor), 1, pciids_f) < 1) - break; - } while (pciids_vendor.vendor_id < vendor_id); + /* Go through vendor entries until the ID is matched or overtaken. */ + for (pciids_cur_vendor = 0; pciids_vendor[pciids_cur_vendor].vendor_id < vendor_id; pciids_cur_vendor++) + ; /* Return 1 if the ID was matched, 0 otherwise. */ - return pciids_vendor.vendor_id == vendor_id; + return pciids_vendor[pciids_cur_vendor].vendor_id == vendor_id; } static char * pciids_get_vendor(uint16_t vendor_id) { /* Find vendor ID in the database, and return its name if found. */ - if (pciids_find_vendor(vendor_id)) - return pciids_read_string(pciids_vendor.string_offset); + if (find_vendor(vendor_id)) + return pciids_read_string(pciids_vendor[pciids_cur_vendor].string_offset); /* Return nothing if the vendor ID was not found. */ return NULL; @@ -263,21 +292,16 @@ pciids_get_device(uint16_t device_id) /* Must be preceded by a call to {find|get}_vendor to establish the vendor ID! */ /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_device, 'D')) return NULL; - /* Seek to device database entries for the established vendor. */ - fseek(pciids_f, pciids_header.device_db_offset + pciids_vendor.devices_offset, SEEK_SET); - - /* Read device entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_device, sizeof(pciids_device), 1, pciids_f) < 1) - break; - } while (pciids_device.device_id < device_id); + /* Go through device entries until the ID is matched or overtaken. */ + for (pciids_cur_device = pciids_vendor[pciids_cur_vendor].devices_offset; pciids_device[pciids_cur_device].device_id < device_id; pciids_cur_device++) + ; /* Return the device name if found. */ - if (pciids_device.device_id == device_id) - return pciids_read_string(pciids_device.string_offset); + if (pciids_device[pciids_cur_device].device_id == device_id) + return pciids_read_string(pciids_device[pciids_cur_device].string_offset); /* Return nothing if the device ID was not found. */ return NULL; @@ -287,23 +311,19 @@ static char * pciids_get_subdevice(uint16_t subvendor_id, uint16_t subdevice_id) { /* Must be preceded by calls to {find|get}_vendor and get_device to establish the vendor/device ID! */ + int i; /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_subdevice, 'S')) return NULL; - /* Seek to subdevice database entries for the established subvendor. */ - fseek(pciids_f, pciids_header.subdevice_db_offset + pciids_device.subdevices_offset, SEEK_SET); - - /* Read subdevice entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_subdevice, sizeof(pciids_subdevice), 1, pciids_f) < 1) - break; - } while ((pciids_subdevice.subvendor_id < subvendor_id) || (pciids_subdevice.subdevice_id < subdevice_id)); + /* Go through subdevice entries until the ID is matched or overtaken. */ + for (i = pciids_device[pciids_cur_device].subdevices_offset; (pciids_subdevice[i].subvendor_id < subvendor_id) || (pciids_subdevice[i].subdevice_id < subdevice_id); i++) + ; /* Return the subdevice name if found. */ - if ((pciids_subdevice.subvendor_id == subvendor_id) && (pciids_subdevice.subdevice_id == subdevice_id)) - return pciids_read_string(pciids_subdevice.string_offset); + if ((pciids_subdevice[i].subvendor_id == subvendor_id) && (pciids_subdevice[i].subdevice_id == subdevice_id)) + return pciids_read_string(pciids_subdevice[i].string_offset); /* Return nothing if the subdevice ID was not found. */ return NULL; @@ -312,22 +332,19 @@ pciids_get_subdevice(uint16_t subvendor_id, uint16_t subdevice_id) static char * pciids_get_class(uint8_t class_id) { + int i; + /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_class, 'C')) return NULL; - /* Seek to class database. */ - fseek(pciids_f, pciids_header.class_db_offset, SEEK_SET); - - /* Read class entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_class, sizeof(pciids_class), 1, pciids_f) < 1) - break; - } while (pciids_class.class_id < class_id); + /* Go through class entries until the ID is matched or overtaken. */ + for (i = 0; pciids_class[i].class_id < class_id; i++) + ; /* Return the class name if found. */ - if (pciids_class.class_id == class_id) - return pciids_read_string(pciids_class.string_offset); + if (pciids_class[i].class_id == class_id) + return pciids_read_string(pciids_class[i].string_offset); /* Return nothing if the class ID was not found. */ return NULL; @@ -336,22 +353,19 @@ pciids_get_class(uint8_t class_id) static char * pciids_get_subclass(uint8_t class_id, uint8_t subclass_id) { + int i; + /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_subclass, 'U')) return NULL; - /* Seek to subclass database. */ - fseek(pciids_f, pciids_header.subclass_db_offset, SEEK_SET); - - /* Read subclass entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_subclass, sizeof(pciids_subclass), 1, pciids_f) < 1) - break; - } while ((pciids_subclass.class_id < class_id) || (pciids_subclass.subclass_id < subclass_id)); + /* Go through subclass entries until the ID is matched or overtaken. */ + for (i = 0; (pciids_subclass[i].class_id < class_id) || (pciids_subclass[i].subclass_id < subclass_id); i++) + ; /* Return the subclass name if found. */ - if ((pciids_subclass.class_id == class_id) && (pciids_subclass.subclass_id == subclass_id)) - return pciids_read_string(pciids_subclass.string_offset); + if ((pciids_subclass[i].class_id == class_id) && (pciids_subclass[i].subclass_id == subclass_id)) + return pciids_read_string(pciids_subclass[i].string_offset); /* Return nothing if the subclass ID was not found. */ return NULL; @@ -360,22 +374,19 @@ pciids_get_subclass(uint8_t class_id, uint8_t subclass_id) static char * pciids_get_progif(uint8_t class_id, uint8_t subclass_id, uint8_t progif_id) { + int i; + /* Open database if required. */ - if (pciids_open_database()) + if (pciids_open_database((void **) &pciids_progif, 'P')) return NULL; - /* Seek to programming interface database. */ - fseek(pciids_f, pciids_header.progif_db_offset, SEEK_SET); - - /* Read programming interface entries until the ID is matched or overtaken. */ - do { - if (fread(&pciids_progif, sizeof(pciids_progif), 1, pciids_f) < 1) - break; - } while ((pciids_progif.class_id < class_id) || (pciids_progif.subclass_id < subclass_id) || (pciids_progif.progif_id < progif_id)); + /* Go through programming interface entries until the ID is matched or overtaken. */ + for (i = 0; (pciids_progif[i].class_id < class_id) || (pciids_progif[i].subclass_id < subclass_id) || (pciids_progif[i].progif_id < progif_id); i++) + ; /* Return the programming interface name if found. */ - if ((pciids_progif.class_id == class_id) && (pciids_progif.subclass_id == subclass_id) && (pciids_progif.progif_id == progif_id)) - return pciids_read_string(pciids_progif.string_offset); + if ((pciids_progif[i].class_id == class_id) && (pciids_progif[i].subclass_id == subclass_id) && (pciids_progif[i].progif_id == progif_id)) + return pciids_read_string(pciids_progif[i].string_offset); /* Return nothing if the programming interface ID was not found. */ return NULL; @@ -612,14 +623,12 @@ scan_bus(uint8_t bus, int nesting, char dump, char *buf) /* Add vendor name to buffer. */ strcat(buf, temp); strcat(buf, " "); - free(temp); /* Look up device name. */ temp = pciids_get_device(dev_id.u16[1]); if (temp) { /* Add device name to buffer. */ strcat(buf, temp); - free(temp); } else { /* Device name not found. */ goto unknown_device; @@ -633,7 +642,6 @@ unknown_device: /* Look up class ID. */ if (temp) { /* Add class name to buffer. */ sprintf(&buf[strlen(buf)], "[%s]", temp); - free(temp); } else { /* Class name not found. */ sprintf(&buf[strlen(buf)], "[Class %02X:%02X:%02X]", dev_rev_class.u8[3], dev_rev_class.u8[2], dev_rev_class.u8[1]); @@ -807,24 +815,15 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) /* Print vendor name if found. */ temp = pciids_get_vendor(reg_val.u16[0]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); /* Print device ID. */ printf("\nDevice: [%04X] ", reg_val.u16[1]); /* Print device name if found. */ temp = pciids_get_device(reg_val.u16[1]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + if (temp) + printf("%s", temp ? temp : "[Unknown]"); /* Read header type. We'll be using it a lot. */ header_type = pci_readb(bus, dev, func, 0x0e); @@ -864,24 +863,14 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) /* Print subvendor name if found. */ temp = pciids_get_vendor(reg_val.u16[0]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); /* Print subdevice ID. */ printf("\nSubdevice: [%04X] ", reg_val.u16[1]); /* Print subdevice ID if found. */ temp = pciids_get_subdevice(reg_val.u16[0], reg_val.u16[1]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); } } @@ -912,36 +901,21 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) /* Print class name if found. */ temp = pciids_get_class(reg_val.u8[3]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); /* Print subclass ID. */ printf("\n [%02X] ", reg_val.u8[2]); /* Print subclass name if found. */ temp = pciids_get_subclass(reg_val.u8[3], reg_val.u8[2]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); /* Print programming interface ID. */ printf("\n [%02X] ", reg_val.u8[1]); /* Print programming interface name if found. */ temp = pciids_get_progif(reg_val.u8[3], reg_val.u8[2], reg_val.u8[1]); - if (temp) { - printf("%s", temp); - free(temp); - } else { - printf("[Unknown]"); - } + printf("%s", temp ? temp : "[Unknown]"); /* Read latency, grant and interrupt line. */ reg_val.u32 = pci_readl(bus, dev, func, 0x3c); diff --git a/pcireg/pciutil.py b/pcireg/pciutil.py index d48ccb0..d0cbf34 100644 --- a/pcireg/pciutil.py +++ b/pcireg/pciutil.py @@ -43,7 +43,7 @@ clean_device_abbr = [ ('High Definition Audio', 'HDA'), ('Host Adapter', 'HBA'), ('Host Bus Adapter', 'HBA'), - ('Host Controller', 'HC'), + ('Host[- ]Controller', 'HC'), # dash = 1106:3104 ('Input/Output', 'I/O'), ('Integrated ([^\s]+) (?:Graphics|GPU)', '\\2 iGPU'), # VIA CLE266 ('Integrated (?:Graphics|GPU)', 'iGPU'), @@ -75,7 +75,7 @@ clean_device_abbr = [ clean_device_bit_pattern = re.compile('''( |^|\(|\[|\{|/)(?:([0-9]{1,4}) )?(?:(K)(?:ilo)?|(M)(?:ega)?|(G)(?:iga)?)bit( |$|\)|\]|\})''', re.I) clean_device_suffix_pattern = re.compile(''' (?:Adapter|Card|Device|(?:Host )?Controller)( (?: [0-9#]+)?|$|\)|\]|\})''', re.I) clean_vendor_abbr_pattern = re.compile(''' \[([^\]]+)\]''') -clean_vendor_suffix_pattern = re.compile('''[ ,.](?:Semiconductors?|(?:Micro)?electronics?|Interactive|Technolog(?:y|ies)|(?:Micro)?systems|Computer(?: works)?|Products|Group|and subsidiaries|of(?: America)?|Co(?:rp(?:oration)?|mpany)?|Inc|LLC|Ltd|GmbH(?: \& .+)?|AB|AG|SA|(?:\(|\[|\{).*)$''', re.I) +clean_vendor_suffix_pattern = re.compile('''[ ,.](?:Semiconductors?|(?:Micro)?electronics?|Interactive|Technolog(?:y|ies)|(?:Micro)?systems|Computer(?: works)?|Products|Group|and subsidiaries|of(?: America)?|Co(?:rp(?:oration)?|mpany)?|Inc|LLC|Ltd|GmbH(?: & .+)?|AB|AG|SA|(?:\(|\[|\{).*)$''', re.I) clean_vendor_force = { 'National Semiconductor Corporation': 'NSC', }