DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <string.h> 00021 #include "dosbox.h" 00022 #include "inout.h" 00023 #include "paging.h" 00024 #include "mem.h" 00025 #include "pci_bus.h" 00026 #include "setup.h" 00027 #include "debug.h" 00028 #include "callback.h" 00029 #include "regs.h" 00030 #include "../ints/int10.h" 00031 #include "voodoo.h" 00032 #include "control.h" 00033 00034 bool pcibus_enable = false; 00035 bool log_pci = false; 00036 00037 bool has_pcibus_enable(void) { 00038 return pcibus_enable; 00039 } 00040 00041 static Bit32u pci_caddress=0; // current PCI addressing 00042 00043 static PCI_Device* pci_devices[PCI_MAX_PCIBUSSES][PCI_MAX_PCIDEVICES]={{NULL}}; // registered PCI devices 00044 00045 // PCI address 00046 // 31 - set for a PCI access 00047 // 30-24 - 0 00048 // 23-16 - bus number (0x00ff0000) 00049 // 15-11 - device number (slot) (0x0000f800) 00050 // 10- 8 - subfunction number (0x00000700) 00051 // 7- 2 - config register # (0x000000fc) 00052 00053 static void write_pci_addr(Bitu port,Bitu val,Bitu iolen) { 00054 (void)iolen;//UNUSED 00055 (void)port;//UNUSED 00056 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)("Write PCI address :=%x",(int)val); 00057 pci_caddress=(Bit32u)val; 00058 } 00059 00060 static void write_pci(Bitu port,Bitu val,Bitu iolen) { 00061 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)("Write PCI data port %x :=%x (len %d)",(int)port,(int)val,(int)iolen); 00062 00063 if (pci_caddress & 0x80000000) { 00064 Bit8u busnum = (Bit8u)((pci_caddress >> 16) & 0xff); 00065 Bit8u devnum = (Bit8u)((pci_caddress >> 11) & 0x1f); 00066 Bit8u fctnum = (Bit8u)((pci_caddress >> 8) & 0x7); 00067 Bit8u regnum = (Bit8u)((pci_caddress & 0xfc) + (port & 0x03)); 00068 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)(" Write to device %x register %x (function %x) (:=%x)",(int)devnum,(int)regnum,(int)fctnum,(int)val); 00069 00070 if (busnum >= PCI_MAX_PCIBUSSES) return; 00071 if (devnum >= PCI_MAX_PCIDEVICES) return; 00072 00073 PCI_Device* dev=pci_devices[busnum][devnum]; 00074 if (dev == NULL) return; 00075 dev->config_write(regnum,iolen,(Bit32u)val); 00076 } 00077 } 00078 00079 00080 static Bitu read_pci_addr(Bitu port,Bitu iolen) { 00081 (void)port;//UNUSED 00082 (void)iolen;//UNUSED 00083 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)("Read PCI address -> %x",pci_caddress); 00084 return pci_caddress; 00085 } 00086 00087 static Bitu read_pci(Bitu port,Bitu iolen) { 00088 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)("Read PCI data -> %x",pci_caddress); 00089 00090 if (pci_caddress & 0x80000000UL) { 00091 Bit8u busnum = (Bit8u)((pci_caddress >> 16U) & 0xffU); 00092 Bit8u devnum = (Bit8u)((pci_caddress >> 11U) & 0x1fU); 00093 Bit8u fctnum = (Bit8u)((pci_caddress >> 8U) & 0x7U); 00094 Bit8u regnum = (Bit8u)((pci_caddress & 0xfcu) + (port & 0x03U)); 00095 if (log_pci) LOG(LOG_PCI,LOG_DEBUG)(" Read from device %x register %x (function %x)",(int)devnum,(int)regnum,(int)fctnum); 00096 00097 if (busnum >= PCI_MAX_PCIBUSSES) return ~0UL; 00098 if (devnum >= PCI_MAX_PCIDEVICES) return ~0UL; 00099 00100 PCI_Device* dev=pci_devices[busnum][devnum]; 00101 if (dev == NULL) return ~0UL; 00102 return dev->config_read(regnum,iolen); 00103 } 00104 00105 return ~0UL; 00106 } 00107 00108 00109 static Bitu PCI_PM_Handler() { 00110 LOG(LOG_PCI,LOG_WARN)("PCI PMode handler, unhandled function %x",reg_ax); 00111 return CBRET_NONE; 00112 } 00113 00114 PCI_Device::~PCI_Device() { 00115 } 00116 00117 PCI_Device::PCI_Device(Bit16u vendor, Bit16u device) { 00118 memset(config,0,256); /* zero config space */ 00119 memset(config_writemask,0,256); /* none of it is writeable */ 00120 setVendorID(vendor); 00121 setDeviceID(device); 00122 00123 /* default: allow setting/clearing some bits in the Command register */ 00124 host_writew(config_writemask+0x04,0x0403); /* allow changing mem/io enable and interrupt disable */ 00125 } 00126 00127 class PCI_VGADevice:public PCI_Device { 00128 private: 00129 static const Bit16u vendor=0x5333; // S3 00130 static const Bit16u device=0x8811; // trio64 00131 // static const Bit16u device=0x8810; // trio32 00132 public: 00133 PCI_VGADevice():PCI_Device(vendor,device) { 00134 // init (S3 graphics card) 00135 config[0x08] = 0x00; // revision ID 00136 config[0x09] = 0x00; // interface 00137 config[0x0a] = 0x00; // subclass type (vga compatible) 00138 config[0x0b] = 0x03; // class type (display controller) 00139 config[0x0c] = 0x00; // cache line size 00140 config[0x0d] = 0x00; // latency timer 00141 config[0x0e] = 0x00; // header type (other) 00142 00143 config[0x3c] = 0xff; // no irq 00144 00145 // reset 00146 config[0x04] = 0x23; // command register (vga palette snoop, ports enabled, memory space enabled) 00147 config[0x05] = 0x00; 00148 config[0x06] = 0x80; // status register (medium timing, fast back-to-back) 00149 config[0x07] = 0x02; 00150 00151 host_writew(config_writemask+0x04,0x0023); /* allow changing mem/io enable and VGA palette snoop */ 00152 00153 host_writed(config_writemask+0x10,0xFF000000); /* BAR0: memory resource 16MB aligned */ 00154 host_writed(config+0x10,(((Bit32u)S3_LFB_BASE)&0xfffffff0) | 0x8); 00155 00156 host_writed(config_writemask+0x14,0xFFFF0000); /* BAR1: memory resource 64KB aligned */ 00157 host_writed(config+0x14,(((Bit32u)(S3_LFB_BASE+0x1000000))&0xfffffff0)); 00158 } 00159 }; 00160 00161 00162 class PCI_SSTDevice:public PCI_Device { 00163 private: 00164 static const Bit16u vendor=0x121a; // 3dfx 00165 Bit16u oscillator_ctr; 00166 Bit16u pci_ctr; 00167 public: 00168 PCI_SSTDevice(Bitu type):PCI_Device(vendor,(type==2)?0x0002:0x0001) { 00169 oscillator_ctr=0; 00170 pci_ctr=0; 00171 00172 // init (3dfx voodoo) 00173 config[0x08] = 0x02; // revision 00174 config[0x09] = 0x00; // interface 00175 config[0x0a] = 0x00; // subclass code (video/graphics controller) 00176 config[0x0b] = 0x04; // class code (multimedia device) 00177 config[0x0e] = 0x00; // header type (other) 00178 00179 // reset 00180 config[0x04] = 0x02; // command register (memory space enabled) 00181 config[0x05] = 0x00; 00182 config[0x06] = 0x80; // status register (fast back-to-back) 00183 config[0x07] = 0x00; 00184 00185 config[0x3c] = 0xff; // no irq 00186 00187 host_writew(config_writemask+0x04,0x0123); /* allow changing mem/io enable, B2B enable, and VGA palette snoop */ 00188 00189 host_writed(config_writemask+0x10,0xFF000000); /* BAR0: memory resource 16MB aligned */ 00190 host_writed(config+0x10,(((Bit32u)VOODOO_INITIAL_LFB)&0xfffffff0) | 0x8); 00191 00192 if (getDeviceID() >= 2) { 00193 config[0x40] = 0x00; 00194 config[0x41] = 0x40; // voodoo2 revision ID (rev4) 00195 config[0x42] = 0x01; 00196 config[0x43] = 0x00; 00197 } 00198 } 00199 00200 virtual void config_write(Bit8u regnum,Bitu iolen,Bit32u value) { 00201 if (iolen == 1) { 00202 const unsigned char mask = config_writemask[regnum]; 00203 const unsigned char nmask = ~mask; 00204 00205 /* configuration write masks apply here as well */ 00206 config[regnum] = 00207 ((unsigned char)value & mask) + 00208 (config[regnum] & nmask); 00209 00210 switch (regnum) { /* FIXME: I hope I ported this right --J.C. */ 00211 case 0x10: 00212 case 0x11: 00213 case 0x12: 00214 case 0x13: 00215 VOODOO_PCI_SetLFB(host_readd(config+0x10)&0xfffffff0UL); /* need to act on the new (masked off) value */ 00216 break; 00217 case 0x40: 00218 VOODOO_PCI_InitEnable(value&7); 00219 break; 00220 case 0xc0: 00221 VOODOO_PCI_Enable(true); 00222 break; 00223 case 0xe0: 00224 VOODOO_PCI_Enable(false); 00225 break; 00226 default: 00227 break; 00228 } 00229 } 00230 else { 00231 PCI_Device::config_write(regnum,iolen,value); /* which will break down I/O into 8-bit */ 00232 } 00233 } 00234 virtual Bit32u config_read(Bit8u regnum,Bitu iolen) { 00235 if (iolen == 1) { 00236 switch (regnum) { 00237 case 0x4c: /* FIXME: I hope I ported this right --J.C. */ 00238 case 0x4d: 00239 case 0x4e: 00240 case 0x4f: 00241 LOG(LOG_PCI,LOG_DEBUG)("SST ParseReadRegister STATUS %x",regnum); 00242 break; 00243 00244 case 0x54: /* FIXME: I hope I ported this right --J.C. */ 00245 if (getDeviceID() >= 2) { 00246 oscillator_ctr++; 00247 pci_ctr--; 00248 return (oscillator_ctr | (((unsigned long)pci_ctr<<16ul) & 0x0fff0000ul)) & 0xffu; 00249 } 00250 break; 00251 case 0x55: 00252 if (getDeviceID() >= 2) 00253 return ((oscillator_ctr | (((unsigned long)pci_ctr<<16ul) & 0x0fff0000ul)) >> 8ul) & 0xffu; 00254 break; 00255 case 0x56: 00256 if (getDeviceID() >= 2) 00257 return ((oscillator_ctr | (((unsigned long)pci_ctr<<16ul) & 0x0fff0000ul)) >> 16ul) & 0xffu; 00258 break; 00259 case 0x57: 00260 if (getDeviceID() >= 2) 00261 return ((oscillator_ctr | (((unsigned long)pci_ctr<<16ul) & 0x0fff0000ul)) >> 24ul) & 0xffu; 00262 break; 00263 default: 00264 break; 00265 } 00266 00267 return config[regnum]; 00268 } 00269 else { 00270 return PCI_Device::config_read(regnum,iolen); /* which will break down I/O into 8-bit */ 00271 } 00272 } 00273 }; 00274 00275 static bool initialized = false; 00276 00277 static IO_WriteHandleObject PCI_WriteHandler[5]; 00278 static IO_ReadHandleObject PCI_ReadHandler[5]; 00279 00280 static CALLBACK_HandlerObject callback_pci; 00281 00282 static PhysPt GetPModeCallbackPointer(void) { 00283 return Real2Phys(callback_pci.Get_RealPointer()); 00284 } 00285 00286 static bool IsInitialized(void) { 00287 return initialized; 00288 } 00289 00290 // set up port handlers and configuration data 00291 static void InitializePCI(void) { 00292 // log 00293 LOG(LOG_MISC,LOG_DEBUG)("InitializePCI(): reinitializing PCI bus emulation"); 00294 00295 // install PCI-addressing ports 00296 PCI_WriteHandler[0].Install(0xcf8,write_pci_addr,IO_MD); 00297 PCI_ReadHandler[0].Install(0xcf8,read_pci_addr,IO_MD); 00298 // install PCI-register read/write handlers 00299 for (Bitu ct=0;ct<4;ct++) { 00300 PCI_WriteHandler[1+ct].Install(0xcfc+ct,write_pci,IO_MB); 00301 PCI_ReadHandler[1+ct].Install(0xcfc+ct,read_pci,IO_MB); 00302 } 00303 00304 callback_pci.Install(&PCI_PM_Handler,CB_IRETD,"PCI PM"); 00305 00306 initialized=true; 00307 } 00308 00309 bool UnregisterPCIDevice(PCI_Device* device) { 00310 unsigned int bus,dev; 00311 00312 for (bus=0;bus < PCI_MAX_PCIBUSSES;bus++) { 00313 for (dev=0;dev < PCI_MAX_PCIDEVICES;dev++) { 00314 if (pci_devices[bus][dev] == device) { 00315 pci_devices[bus][dev] = NULL; 00316 return true; 00317 } 00318 } 00319 } 00320 00321 return false; 00322 } 00323 00324 // register PCI device to bus and setup data 00325 Bits RegisterPCIDevice(PCI_Device* device, Bits bus=-1, Bits slot=-1) { 00326 if (device == NULL) return -1; 00327 if (bus >= PCI_MAX_PCIBUSSES) return -1; 00328 if (slot >= PCI_MAX_PCIDEVICES) return -1; 00329 00330 if (!initialized) InitializePCI(); 00331 00332 if (bus < 0 || slot < 0) { 00333 Bits try_bus,try_slot; 00334 00335 try_bus = (bus < 0) ? 0 : bus; 00336 try_slot = (slot < 0) ? 0 : slot; /* NTS: Most PCI implementations have a motherboard chipset or PCI bus device at slot 0 */ 00337 while (pci_devices[try_bus][try_slot] != NULL) { 00338 if (slot >= 0 || (try_slot+1) >= PCI_MAX_PCIDEVICES) { 00339 if (slot < 0) try_slot = 0; 00340 try_bus++; 00341 00342 if (bus >= 0 || try_bus >= PCI_MAX_PCIBUSSES) 00343 break; 00344 } 00345 else if (slot < 0) { 00346 try_slot++; 00347 } 00348 } 00349 00350 bus = try_bus; 00351 slot = try_slot; 00352 } 00353 00354 if (bus >= PCI_MAX_PCIBUSSES || slot >= PCI_MAX_PCIDEVICES) 00355 return -1; 00356 00357 if (pci_devices[bus][slot] != NULL) E_Exit("PCI interface error: attempted to fill slot already taken"); 00358 pci_devices[bus][slot]=device; 00359 return slot; 00360 } 00361 00362 static void Deinitialize(void) { 00363 initialized=false; 00364 pci_caddress=0; 00365 00366 // install PCI-addressing ports 00367 PCI_WriteHandler[0].Uninstall(); 00368 PCI_ReadHandler[0].Uninstall(); 00369 // install PCI-register read/write handlers 00370 for (Bitu ct=0;ct<4;ct++) { 00371 PCI_WriteHandler[1+ct].Uninstall(); 00372 PCI_ReadHandler[1+ct].Uninstall(); 00373 } 00374 00375 // remove callback 00376 callback_pci.Uninstall(); 00377 00378 // disconnect all PCI devices 00379 for (Bitu bus=0;bus<PCI_MAX_PCIBUSSES;bus++) { 00380 for (Bitu i=0;i < PCI_MAX_PCIDEVICES;i++) { 00381 if (pci_devices[bus][i] != NULL) { 00382 delete pci_devices[bus][i]; 00383 pci_devices[bus][i] = NULL; 00384 } 00385 } 00386 } 00387 } 00388 00389 static PCI_Device *S3_PCI=NULL; 00390 static PCI_Device *SST_PCI=NULL; 00391 00392 extern bool enable_pci_vga; 00393 00394 void PCI_AddSVGAS3_Device(void) { 00395 if (!pcibus_enable || !enable_pci_vga) return; 00396 00397 if (S3_PCI == NULL) { 00398 if ((S3_PCI=new PCI_VGADevice()) == NULL) 00399 return; 00400 00401 RegisterPCIDevice(S3_PCI); 00402 } 00403 } 00404 00405 void PCI_RemoveSVGAS3_Device(void) { 00406 if (S3_PCI != NULL) { 00407 UnregisterPCIDevice(S3_PCI); 00408 S3_PCI = NULL; 00409 } 00410 } 00411 00412 void PCI_AddSST_Device(Bitu type) { 00413 if (!pcibus_enable) return; 00414 00415 if (SST_PCI == NULL) { 00416 Bitu ctype = 1; 00417 00418 switch (type) { 00419 case 1: 00420 case 2: 00421 ctype = type; 00422 break; 00423 default: 00424 LOG(LOG_PCI,LOG_WARN)("PCI:SST: Invalid board type %x specified",(int)type); 00425 break; 00426 } 00427 00428 LOG(LOG_MISC,LOG_DEBUG)("Initializing Voodoo/3DFX PCI device"); 00429 if ((SST_PCI=new PCI_SSTDevice(ctype)) == NULL) 00430 return; 00431 00432 RegisterPCIDevice(SST_PCI); 00433 } 00434 } 00435 00436 void PCI_RemoveSST_Device(void) { 00437 if (SST_PCI != NULL) { 00438 UnregisterPCIDevice(SST_PCI); 00439 delete SST_PCI; 00440 SST_PCI = NULL; 00441 } 00442 } 00443 00444 PhysPt PCI_GetPModeInterface(void) { 00445 if (!pcibus_enable) return 0; 00446 return GetPModeCallbackPointer(); 00447 } 00448 00449 bool PCI_IsInitialized() { 00450 return IsInitialized(); 00451 } 00452 00453 void PCI_OnPowerOn(Section *sec) { 00454 (void)sec;//UNUSED 00455 Section_prop * secprop=static_cast<Section_prop *>(control->GetSection("dosbox")); 00456 assert(secprop != NULL); 00457 00458 Deinitialize(); 00459 00460 pcibus_enable = secprop->Get_bool("enable pci bus"); 00461 if (pcibus_enable) InitializePCI(); 00462 } 00463 00464 void PCI_ShutDown(Section* sec) { 00465 (void)sec;//UNUSED 00466 Deinitialize(); 00467 } 00468 00469 void PCIBUS_Init() { 00470 Section_prop * secprop=static_cast<Section_prop *>(control->GetSection("dosbox")); 00471 assert(secprop != NULL); 00472 00473 LOG(LOG_MISC,LOG_DEBUG)("Initializing PCI bus emulation"); 00474 00475 initialized=false; 00476 for (Bitu bus=0;bus<PCI_MAX_PCIBUSSES;bus++) 00477 for (Bitu devct=0;devct<PCI_MAX_PCIDEVICES;devct++) 00478 pci_devices[bus][devct]=NULL; 00479 00480 AddExitFunction(AddExitFunctionFuncPair(PCI_ShutDown),false); 00481 AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(PCI_OnPowerOn)); 00482 00483 /* NTS: PCI emulation does not have to change anything when entering into PC-98 mode. 00484 * I/O ports for PCI bus control are the SAME on both platforms (0xCF8-0xCFF). */ 00485 } 00486