From: John Tsiombikas Date: Sun, 15 May 2022 03:18:53 +0000 (+0300) Subject: added PCI code in anticipation of porting the S3 driver X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=commitdiff_plain;h=f06babe97875e6023dad1843c1f0c56639967656 added PCI code in anticipation of porting the S3 driver --- diff --git a/Makefile b/Makefile index c1a8cad..c862ea9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ !ifdef __UNIX__ dosobj = src/dos/audos.obj src/dos/djdpmi.obj src/dos/gfx.obj src/dos/keyb.obj & src/dos/logger.obj src/dos/main.obj src/dos/sball.obj src/dos/timer.obj & - src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj src/dos/mouse.obj + src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj src/dos/mouse.obj & + src/dos/pci.obj 3dobj = src/3dgfx/3dgfx.obj src/3dgfx/mesh.obj src/3dgfx/meshload.obj & src/3dgfx/polyclip.obj src/3dgfx/polyfill.obj srcobj = src/bsptree.obj src/cfgopt.obj src/console.obj src/demo.obj & @@ -23,7 +24,8 @@ libpath = libpath libs/imago libpath libs/anim libpath libs/midas dosobj = src\dos\audos.obj src\dos\djdpmi.obj src\dos\gfx.obj src\dos\keyb.obj & src\dos\logger.obj src\dos\main.obj src\dos\sball.obj src\dos\timer.obj & - src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj src\dos\mouse.obj + src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj src\dos\mouse.obj & + src\dos\pci.obj 3dobj = src\3dgfx\3dgfx.obj src\3dgfx\mesh.obj src\3dgfx\meshload.obj & src\3dgfx\polyclip.obj src\3dgfx\polyfill.obj srcobj = src\bsptree.obj src\cfgopt.obj src\console.obj src\demo.obj & diff --git a/src/dos/cdpmi.h b/src/dos/cdpmi.h index 71138b6..e8a6950 100644 --- a/src/dos/cdpmi.h +++ b/src/dos/cdpmi.h @@ -29,6 +29,17 @@ struct dpmi_regs { } PACKED; #pragma pack (pop) +enum { + FLAGS_CF = 0x000001, + FLAGS_PF = 0x000004, + FLAGS_ZF = 0x000040, + FLAGS_SF = 0x000080, + FLAGS_IF = 0x000020, + FLAGS_DF = 0x000040, + FLAGS_VM = 0x020000, + FLAGS_ID = 0x200000, +}; + uint16_t dpmi_alloc(unsigned int par, uint16_t *sel); void dpmi_free(uint16_t sel); void dpmi_int(int inum, struct dpmi_regs *regs); diff --git a/src/dos/dosutil.h b/src/dos/dosutil.h index 9894251..71af365 100644 --- a/src/dos/dosutil.h +++ b/src/dos/dosutil.h @@ -9,9 +9,11 @@ #define outp(p, v) outportb(p, v) #define outpw(p, v) outportw(p, v) +#define outpd(p, v) outportd(p, v) #define inp(p) inportb(p) #define inpw(p) inportw(p) +#define inpd(p) inportd(p) #endif #endif /* DOSUTIL_H_ */ diff --git a/src/dos/main.c b/src/dos/main.c index ee28dc9..7f67e85 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -62,6 +62,10 @@ int main(int argc, char **argv) init_timer(100); kb_init(32); + if(init_pci() != -1) { + /* TODO detect and initialize S3 virge */ + } + if(init_video() == -1) { return 1; } diff --git a/src/dos/pci.c b/src/dos/pci.c new file mode 100644 index 0000000..d3a1e7d --- /dev/null +++ b/src/dos/pci.c @@ -0,0 +1,421 @@ +/* +S3 Virge driver hack +Copyright (C) 2021 John Tsiombikas + +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 3 of the License, 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. If not, see . +*/ +#include +#include +#include +#include +#include +#include "inttypes.h" +#include "pci.h" +#include "cdpmi.h" + +#define CONFIG_ADDR_PORT 0xcf8 +#define CONFIG_DATA_PORT 0xcfc + +#define ADDR_ENABLE 0x80000000 +#define ADDR_BUSID(x) (((uint32_t)(x) & 0xff) << 16) +#define ADDR_DEVID(x) (((uint32_t)(x) & 0x1f) << 11) +#define ADDR_FUNC(x) (((uint32_t)(x) & 3) << 8) + +/* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */ +#define PCI_SIG 0x20494350 + +#define TYPE_MULTIFUNC 0x80 + + +static struct pci_device *pcidev; +static int num_pcidevs, max_pcidevs; + + +static int enum_bus(int busid); +static int enum_dev(int busid, int dev); +static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func); +static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func); + +static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg); +static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg); +static const char *class_str(int cc); +static const char *subclass_str(int cc, int sub); + +static uint32_t (*cfg_read32)(int, int, int, int); + +static void clear_devices(void); +static void add_device(struct pci_device *dev); + +int init_pci(void) +{ + int i, count = 0; + struct dpmi_regs regs = {0}; + + clear_devices(); + + regs.eax = 0xb101; + dpmi_int(0x1a, ®s); + + /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */ + if((regs.flags & FLAGS_CF) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) { + fprintf(stderr, "No PCI BIOS present\n"); + return -1; + } + + printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff); + if(regs.eax & 1) { + cfg_read32 = cfg_read32_m1; + } else { + if(!(regs.eax & 2)) { + fprintf(stderr, "Failed to find supported PCI mess mechanism\n"); + return -1; + } + printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n"); + cfg_read32 = cfg_read32_m2; + } + + for(i=0; i<256; i++) { + count += enum_bus(i); + } + printf("found %d PCI devices\n\n", count); + return 0; +} + +static int enum_bus(int busid) +{ + int i, count = 0; + + for(i=0; i<32; i++) { + count += enum_dev(busid, i); + } + + return count; +} + +static int enum_dev(int busid, int devid) +{ + int i, count; + struct pci_device dev; + + dev.bus = busid; + dev.dev = devid; + dev.func = 0; + + /* vendor id ffff is invalid */ + if((cfg_read32(busid, devid, 0, 0) & 0xffff) == 0xffff) { + return 0; + } + if(read_dev_info(&dev.cfg, busid, devid, 0) == -1) { + return 0; + } + print_dev_info(&dev.cfg, busid, devid, 0); + add_device(&dev); + + count = 1; + + if(dev.cfg.hdr_type & TYPE_MULTIFUNC) { + for(i=1; i<8; i++) { + if(read_dev_info(&dev.cfg, busid, devid, i) == -1) { + continue; + } + print_dev_info(&dev.cfg, busid, devid, i); + dev.func = i; + add_device(&dev); + count++; + } + } + return count; +} + +static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func) +{ + int i; + uint32_t *ptr = (uint32_t*)res; + + *ptr++ = cfg_read32(bus, dev, func, 0); + if(res->vendor == 0xffff) { + return -1; + } + + for(i=1; i<16; i++) { + *ptr++ = cfg_read32(bus, dev, func, i * 4); + } + return 0; +} + +static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func) +{ + printf("- (%d:%d,%d) Device %04x:%04x: ", bus, dev, func, info->vendor, info->device); + printf("\"%s\" (%d) - %s-func\n", class_str(info->class), info->class, + info->hdr_type & TYPE_MULTIFUNC ? "multi" : "single"); + printf(" subclass: \"%s\" (%d), iface: %d\n", subclass_str(info->class, info->subclass), + info->subclass, info->iface); +} + +static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg) +{ + uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) | + ADDR_FUNC(func) | reg; + + outpd(CONFIG_ADDR_PORT, addr); + return inpd(CONFIG_DATA_PORT); +} + +static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg) +{ + fprintf(stderr, "BUG: PCI mess mechanism #2 not implemented yet!"); + demo_abort(); + return 0; +} + +static const char *class_names[] = { + "unknown", + "mass storage controller", + "network controller", + "display controller", + "multimedia device", + "memory controller", + "bridge device", + "simple communication controller", + "base system peripheral", + "input device", + "docking station", + "processor", + "serial bus controller", + "wireless controller", + "intelligent I/O controller", + "satellite communication controller", + "encryption/decryption controller", + "data acquisition & signal processing controller" +}; + +static const char *class_mass_names[] = { + "SCSI bus controller", + "IDE controller", + "floppy disk controller", + "IPI bus controller", + "RAID controller" +}; + +static const char *class_net_names[] = { + "ethernet controller", + "token ring controller", + "FDDI controller", + "ATM controller", + "ISDN controller" +}; + +static const char *class_disp_names[] = { + "VGA-compatible controller", + "XGA controller", + "3D controller" +}; + +static const char *class_mm_names[] = { + "video device", + "audio device", + "telephony device" +}; + +static const char *class_bridge_names[] = { + "host bridge", + "ISA bridge", + "EISA bridge", + "MCA bridge", + "PCI-to-PCI bridge", + "Subtractive decode PCI-to-PCI bridge", + "PCMCIA bridge", + "NuBus bridge", + "CardBus bridge", + "RACEway bridge" +}; + +static const char *class_comm_names[] = { + "serial controller", + "parallel/IEEE1284", + "multiport serial controller", + "modem" +}; + +static const char *class_base_names[] = { + "interrupt controller", + "DMA controller", + "timer", + "RTC", + "PCI hot-plug controller" +}; + +static const char *class_input_names[] = { + "keyboard controller", + "digitizer", + "mouse controller", + "scanner controller", + "gameport controller" +}; + +static const char *class_ser_names[] = { + "firewire", + "ACCESS.bus", + "SSA", + "USB", + "Fibre Channel", + "SMBus" +}; + +static const char *class_sat_names[] = { + "TV", + "audio", + "voice", + "data" +}; + + +static const char *class_str(int cc) +{ + if(cc == 0xff) { + return "other"; + } + if(cc >= 0x12) { + return "unknown"; + } + return class_names[cc]; +} + +static const char *subclass_str(int cc, int sub) +{ + if(sub == 0x80) return "other"; + + switch(cc) { + case 0: + if(sub == 1) return "VGA-compatible device"; + return "unknown"; + + case 1: + if(sub > 4) return "unknown"; + return class_mass_names[sub]; + + case 2: + if(sub > 4) return "unknown"; + return class_net_names[sub]; + + case 3: + if(sub > 2) return "unknown"; + return class_disp_names[sub]; + + case 4: + if(sub > 2) return "unknown"; + return class_mm_names[sub]; + + case 5: + if(sub == 0) return "RAM"; + if(sub == 1) return "flash"; + return "unknown"; + + case 6: + if(sub > 8) return "unknown"; + return class_bridge_names[sub]; + + case 7: + if(sub > 3) return "unknown"; + return class_comm_names[sub]; + + case 8: + if(sub > 4) return "unknown"; + return class_base_names[sub]; + + case 9: + if(sub > 4) return "unknown"; + return class_input_names[sub]; + + case 10: + if(sub == 0) return "generic docking station"; + return "unknown"; + + case 11: + switch(sub) { + case 0: return "386"; + case 1: return "486"; + case 2: return "pentium"; + case 0x10: return "alpha"; + case 0x20: return "powerpc"; + case 0x30: return "mips"; + case 0x40: return "co-processor"; + default: + break; + } + return "unknown"; + + case 12: + if(sub > 5) return "unknown"; + return class_ser_names[sub]; + + case 13: + if(sub == 0) return "irda controller"; + if(sub == 1) return "IR controller"; + if(sub == 0x10) return "RF controller"; + return "unknonw"; + + case 15: + if(sub > 4) return "unknown"; + return class_sat_names[sub]; + + case 16: + if(sub == 0) return "network & computing crypto"; + if(sub == 1) return "entertainment crypto"; + return "unknown"; + + case 17: + if(sub == 0) return "DPIO module"; + return "unknown"; + + default: + break; + } + return "unknown"; +} + +static void clear_devices(void) +{ + free(pcidev); + pcidev = 0; + num_pcidevs = max_pcidevs = 0; +} + +static void add_device(struct pci_device *dev) +{ + if(num_pcidevs >= max_pcidevs) { + void *newarr; + int newsz = max_pcidevs ? max_pcidevs << 1 : 8; + + if(!(newarr = realloc(pcidev, newsz * sizeof *pcidev))) { + fprintf(stderr, "failed to resize PCI device array (%d)\n", newsz); + return; + } + pcidev = newarr; + max_pcidevs = newsz; + } + + pcidev[num_pcidevs++] = *dev; +} + +struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid) +{ + int i; + for(i=0; i + +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 3 of the License, 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. If not, see . +*/ +#ifndef PCI_H_ +#define PCI_H_ + +#include "inttypes.h" +#include "util.h" + +#pragma pack (push, 1) +struct pci_config_data { + uint16_t vendor, device; + uint16_t cmd, status; + uint8_t rev, iface, subclass, class; + uint8_t cacheline_size; + uint8_t latency_timer; + uint8_t hdr_type; + uint8_t bist; + uint32_t base_addr[6]; + uint32_t cardbus_cis; + uint16_t subsys_vendor; + uint16_t subsys; + uint32_t rom_addr; + uint32_t reserved1, reserved2; + uint8_t intr_line, intr_pin; + uint8_t min_grant, max_latency; +} PACKED; +#pragma pop (push) + +struct pci_device { + int bus, dev, func; + struct pci_config_data cfg; +}; + +int init_pci(void); + +struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid); + +#endif /* PCI_H_ */