00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00085 #include "StdAfx.h"
00086 #include "PCIDevice.h"
00087 #include "System.h"
00088
00089 CPCIDevice::CPCIDevice(CConfigurator* cfg, CSystem* c, int pcibus, int pcidev) : CSystemComponent(cfg, c)
00090 {
00091 int i;
00092
00093 int j;
00094
00095 for(i = 0; i < 8; i++)
00096 {
00097 device_at[i] = false;
00098 for(j = 0; j < 8; j++)
00099 pci_range_is_io[i][j] = false;
00100 }
00101
00102 for(i = 0; i < MAX_DEV_RANGES; i++)
00103 dev_range_is_io[i] = false;
00104
00105 myPCIBus = pcibus;
00106 myPCIDev = pcidev;
00107 }
00108
00109 CPCIDevice::~CPCIDevice(void)
00110 { }
00111
00112 void CPCIDevice::add_function(int func, u32 data[64], u32 mask[64])
00113 {
00114 memcpy(std_config_data[func], data, 64 * sizeof(u32));
00115 memcpy(std_config_mask[func], mask, 64 * sizeof(u32));
00116 #if defined(ES40_BIG_ENDIAN)
00117 int i;
00118 for(i = 0; i < 64; i++)
00119 {
00120 std_config_data[func][i] = endian_32(std_config_data[func][i]);
00121 std_config_mask[func][i] = endian_32(std_config_mask[func][i]);
00122 }
00123 #endif
00124 device_at[func] = true;
00125 }
00126
00127 void CPCIDevice::add_legacy_io(int id, u32 base, u32 length)
00128 {
00129 dev_range_is_io[id] = true;
00130 cSystem->RegisterMemory(this, id,
00131 U64(0x00000801fc000000) + (U64(0x0000000200000000) * myPCIBus) + base,
00132 length);
00133 }
00134
00135 void CPCIDevice::add_legacy_mem(int id, u32 base, u32 length)
00136 {
00137 dev_range_is_io[id] = false;
00138 cSystem->RegisterMemory(this, id,
00139 U64(0x0000080000000000) + (U64(0x0000000200000000) * myPCIBus) + base,
00140 length);
00141 }
00142
00143 u32 CPCIDevice::config_read(int func, u32 address, int dsize)
00144 {
00145 u8* x;
00146
00147 u32 data = 0;
00148
00149 x = (u8*) pci_state.config_data[func];
00150 x += address;
00151
00152 switch(dsize)
00153 {
00154 case 8: data = endian_8(*x); break;
00155 case 16: data = endian_16(*((u16*) x)); break;
00156 case 32: data = endian_32(*((u32*) x)); break;
00157 }
00158
00159 data = config_read_custom(func, address, dsize, data);
00160
00161
00162 return data;
00163 }
00164
00165 void CPCIDevice::config_write(int func, u32 address, int dsize, u32 data)
00166 {
00167
00168
00169 u8* x;
00170 u8* y;
00171
00172 u32 mask = 0;
00173 u32 old_data = 0;
00174 u32 new_data = 0;
00175
00176 x = (u8*) pci_state.config_data[func];
00177 x += address;
00178 y = (u8*) pci_state.config_mask[func];
00179 y += address;
00180
00181 #if defined(DEBUG_PCI)
00182 if(address == 0x3c && (data & 0xff) != 0xff)
00183 printf("%s.%d PCI Interrupt set to %02x.\n", devid_string, func, data & 0xff);
00184 #endif
00185 switch(dsize)
00186 {
00187 case 8:
00188 data = endian_8(data);
00189 old_data = (*x) & 0xff;
00190 mask = (*y) & 0xff;
00191 new_data = (old_data &~mask) | data & mask;
00192 *x = (u8) new_data;
00193 break;
00194
00195 case 16:
00196 data = endian_16(data);
00197 old_data = (*((u16*) x)) & 0xffff;
00198 mask = (*((u16*) y)) & 0xffff;
00199 new_data = (old_data &~mask) | data & mask;
00200 *((u16*) x) = (u16) new_data;
00201 break;
00202
00203 case 32:
00204 data = endian_32(data);
00205 old_data = (*((u32*) x));
00206 mask = (*((u32*) y));
00207 new_data = (old_data &~mask) | data & mask;
00208 *((u32*) x) = new_data;
00209 break;
00210 }
00211
00212 if(dsize == 32 && ((data & mask) != mask) && ((data & mask) != 0))
00213 {
00214 switch(address)
00215 {
00216 case 0x10:
00217 case 0x14:
00218 case 0x18:
00219 case 0x1c:
00220 case 0x20:
00221 case 0x24:
00222 register_bar(func, (address - 0x10) / 4, endian_32(new_data),
00223 endian_32(mask));
00224 break;
00225
00226 case 0x30:
00227 register_bar(func, 6, endian_32(new_data), endian_32(mask));
00228 break;
00229 }
00230 }
00231
00232 config_write_custom(func, address, dsize, old_data, new_data, data);
00233 }
00234
00235 void CPCIDevice::register_bar(int func, int bar, u32 data, u32 mask)
00236 {
00237 int id = PCI_RANGE_BASE + (func * 8) + bar;
00238 u32 length = ((~mask) | 1) + 1;
00239 u64 t;
00240
00241 if((data & 1) && bar != 6)
00242 {
00243
00244
00245 pci_range_is_io[func][bar] = true;
00246
00247 cSystem->RegisterMemory(this, PCI_RANGE_BASE + (func * 8) + bar,
00248 t = U64(0x00000801fc000000) + (U64(0x0000000200000000) * myPCIBus) +
00249 (data &~0x3), length);
00250 #if defined(DEBUG_PCI)
00251 printf("%s(%s).%d PCI BAR %d set to IO % "LL "x, len %x.\n",
00252 myCfg->get_myName(), myCfg->get_myValue(), func, bar, t, length);
00253 #endif
00254 }
00255 else if((data & 1) || bar != 6)
00256 {
00257
00258
00259 pci_range_is_io[func][bar] = true;
00260
00261 cSystem->RegisterMemory(this, PCI_RANGE_BASE + (func * 8) + bar,
00262 t = U64(0x0000080000000000) + (U64(0x0000000200000000) * myPCIBus) +
00263 (data &~0xf), length);
00264 #if defined(DEBUG_PCI)
00265 printf("%s(%s).%d PCI BAR %d set to MEM % "LL "x, len %x.\n",
00266 myCfg->get_myName(), myCfg->get_myValue(), func, bar, t, length);
00267 #endif
00268 }
00269 else
00270 {
00271
00272
00273 #if defined(DEBUG_PCI)
00274 printf("%s(%s).%d PCI BAR %d should be disabled...\n", myCfg->get_myName(),
00275 myCfg->get_myValue(), func, bar);
00276 #endif
00277 }
00278 }
00279
00280 void CPCIDevice::ResetPCI()
00281 {
00282 int i;
00283
00284 for(i = 0; i < 8; i++)
00285 {
00286 if(device_at[i])
00287 {
00288 cSystem->RegisterMemory(this, PCI_RANGE_BASE + (i * 8) + 7,
00289 U64(0x00000801fe000000) + (U64(0x0000000200000000) * myPCIBus) +
00290 (U64(0x0000000000000800) * myPCIDev) +
00291 (U64(0x0000000000000100) * i), 0x100);
00292 memcpy(pci_state.config_data[i], std_config_data[i], 64 * sizeof(u32));
00293 memcpy(pci_state.config_mask[i], std_config_mask[i], 64 * sizeof(u32));
00294
00295 config_write(i, 0x10, 32, endian_32(pci_state.config_data[i][4]));
00296 config_write(i, 0x14, 32, endian_32(pci_state.config_data[i][5]));
00297 config_write(i, 0x18, 32, endian_32(pci_state.config_data[i][6]));
00298 config_write(i, 0x1c, 32, endian_32(pci_state.config_data[i][7]));
00299 config_write(i, 0x20, 32, endian_32(pci_state.config_data[i][8]));
00300 config_write(i, 0x24, 32, endian_32(pci_state.config_data[i][9]));
00301 config_write(i, 0x30, 32, endian_32(pci_state.config_data[i][12]));
00302 }
00303 }
00304 }
00305
00306 u64 CPCIDevice::ReadMem(int index, u64 address, int dsize)
00307 {
00308 int func;
00309 int bar;
00310
00311 if(dsize == 64)
00312 return ReadMem(index, address, 32) | (((u64) ReadMem(index, address + 4, 32)) << 32);
00313
00314 if(dsize != 8 && dsize != 16 && dsize != 32)
00315 {
00316 FAILURE_5(InvalidArgument,
00317 "ReadMem: %s(%s) Unsupported dsize %d. (%d, %"LL "x)\n",
00318 myCfg->get_myName(), myCfg->get_myValue(), dsize, index, address);
00319 }
00320
00321 if(index < PCI_RANGE_BASE)
00322 {
00323 if(dev_range_is_io[index] && !(pci_state.config_data[0][1] & endian_32(1)))
00324 {
00325 printf("%s(%s) Legacy IO access with IO disabled from PCI config.\n",
00326 myCfg->get_myName(), myCfg->get_myValue());
00327 return 0;
00328 }
00329
00330 if(!dev_range_is_io[index] && !(pci_state.config_data[0][1] & endian_32(2)))
00331 {
00332 printf("%s(%s) Legacy memory access with memory disabled from PCI config.\n",
00333 myCfg->get_myName(), myCfg->get_myValue());
00334 return 0;
00335 }
00336
00337
00338 return ReadMem_Legacy(index, (u32) address, dsize);
00339 }
00340
00341 index -= PCI_RANGE_BASE;
00342
00343 bar = index & 7;
00344 func = (index / 8) & 7;
00345
00346 if(bar == 7)
00347 return config_read(func, (u32) address, dsize);
00348
00349 if(pci_range_is_io[func][bar] && !(pci_state.config_data[func][1] & endian_32(1)))
00350 {
00351 printf("%s(%s).%d PCI IO access with IO disabled from PCI config.\n",
00352 myCfg->get_myName(), myCfg->get_myValue(), func);
00353 return 0;
00354 }
00355
00356 if(!pci_range_is_io[func][bar]
00357 && !(pci_state.config_data[func][1] & endian_32(2)))
00358 {
00359 printf("%s(%s).%d PCI memory access with memory disabled from PCI config.\n",
00360 myCfg->get_myName(), myCfg->get_myValue(), func);
00361 return 0;
00362 }
00363
00364
00365 return ReadMem_Bar(func, bar, (u32) address, dsize);
00366 }
00367
00368 void CPCIDevice::WriteMem(int index, u64 address, int dsize, u64 data)
00369 {
00370 int func;
00371 int bar;
00372
00373 if(dsize == 64)
00374 {
00375 WriteMem(index, address, 32, data & U64(0xffffffff));
00376 WriteMem(index, address + 4, 32, (data >> 32) & U64(0xffffffff));
00377 return;
00378 }
00379
00380 if(dsize != 8 && dsize != 16 && dsize != 32)
00381 {
00382 FAILURE_6(InvalidArgument,
00383 "WriteMem: %s(%s) Unsupported dsize %d. (%d,%"LL "x,%"LL "x)\n",
00384 myCfg->get_myName(), myCfg->get_myValue(), dsize, index, address,
00385 data);
00386 }
00387
00388 if(index < PCI_RANGE_BASE)
00389 {
00390 if(dev_range_is_io[index] && !(pci_state.config_data[0][1] & endian_32(1)))
00391 {
00392 printf("%s(%s) Legacy IO access with IO disabled from PCI config.\n",
00393 myCfg->get_myName(), myCfg->get_myValue());
00394 return;
00395 }
00396
00397 if(!dev_range_is_io[index] && !(pci_state.config_data[0][1] & endian_32(2)))
00398 {
00399 printf("%s(%s) Legacy memory access with memory disabled from PCI config.\n",
00400 myCfg->get_myName(), myCfg->get_myValue());
00401 return;
00402 }
00403
00404 WriteMem_Legacy(index, (u32) address, dsize, (u32) data);
00405 return;
00406 }
00407
00408 index -= PCI_RANGE_BASE;
00409
00410 bar = index & 7;
00411 func = (index / 8) & 7;
00412
00413 if(bar == 7)
00414 {
00415 config_write(func, (u32) address, dsize, (u32) data);
00416 return;
00417 }
00418
00419 if(pci_range_is_io[func][bar] && !(pci_state.config_data[func][1] & endian_32(1)))
00420 {
00421 printf("%s(%s).%d PCI IO access with IO disabled from PCI config.\n",
00422 myCfg->get_myName(), myCfg->get_myValue(), func);
00423 return;
00424 }
00425
00426 if(!pci_range_is_io[func][bar]
00427 && !(pci_state.config_data[func][1] & endian_32(2)))
00428 {
00429 printf("%s(%s).%d PCI memory access with memory disabled from PCI config.\n",
00430 myCfg->get_myName(), myCfg->get_myValue(), func);
00431 return;
00432 }
00433
00434 WriteMem_Bar(func, bar, (u32) address, dsize, (u32) data);
00435 }
00436
00437 bool CPCIDevice::do_pci_interrupt(int func, bool asserted)
00438 {
00439 if((endian_32(pci_state.config_data[func][0x0f]) & 0xff) != 0xff)
00440 {
00441 cSystem->interrupt(endian_32(pci_state.config_data[func][0x0f]) & 0xff,
00442 asserted);
00443 return true;
00444 }
00445 else
00446 return false;
00447 }
00448
00449 static u32 pci_magic1 = 0xC1095A78;
00450 static u32 pci_magic2 = 0x87A5901C;
00451
00455 int CPCIDevice::SaveState(FILE* f)
00456 {
00457 long ss = sizeof(pci_state);
00458
00459 fwrite(&pci_magic1, sizeof(u32), 1, f);
00460 fwrite(&ss, sizeof(long), 1, f);
00461 fwrite(&pci_state, sizeof(pci_state), 1, f);
00462 fwrite(&pci_magic2, sizeof(u32), 1, f);
00463 printf("%s: %d PCI bytes saved.\n", devid_string, (int) ss);
00464 return 0;
00465 }
00466
00470 int CPCIDevice::RestoreState(FILE* f)
00471 {
00472 long ss;
00473 u32 m1;
00474 u32 m2;
00475 size_t r;
00476
00477 r = fread(&m1, sizeof(u32), 1, f);
00478 if(r != 1)
00479 {
00480 printf("%s: unexpected end of file!\n", devid_string);
00481 return -1;
00482 }
00483
00484 if(m1 != pci_magic1)
00485 {
00486 printf("%s: PCI MAGIC 1 does not match!\n", devid_string);
00487 return -1;
00488 }
00489
00490 fread(&ss, sizeof(long), 1, f);
00491 if(r != 1)
00492 {
00493 printf("%s: unexpected end of file!\n", devid_string);
00494 return -1;
00495 }
00496
00497 if(ss != sizeof(pci_state))
00498 {
00499 printf("%s: PCI STRUCT SIZE does not match!\n", devid_string);
00500 return -1;
00501 }
00502
00503 fread(&pci_state, sizeof(pci_state), 1, f);
00504 if(r != 1)
00505 {
00506 printf("%s: unexpected end of file!\n", devid_string);
00507 return -1;
00508 }
00509
00510 r = fread(&m2, sizeof(u32), 1, f);
00511 if(r != 1)
00512 {
00513 printf("%s: unexpected end of file!\n", devid_string);
00514 return -1;
00515 }
00516
00517 if(m2 != pci_magic2)
00518 {
00519 printf("%s: PCI MAGIC 1 does not match!\n", devid_string);
00520 return -1;
00521 }
00522
00523 printf("%s: %d PCI bytes restored.\n", devid_string, (int) ss);
00524 return 0;
00525 }
00526
00527 u32 CPCIDevice::ReadMem_Legacy(int index, u32 address, int dsize)
00528 {
00529 FAILURE_2(NotImplemented, "%s(%s) No Legacy read handler installed",
00530 myCfg->get_myName(), myCfg->get_myValue());
00531 }
00532
00533 void CPCIDevice::WriteMem_Legacy(int index, u32 address, int dsize, u32 data)
00534 {
00535 FAILURE_2(NotImplemented, "%s(%s) No Legacy write handler installed",
00536 myCfg->get_myName(), myCfg->get_myValue());
00537 }
00538
00539 u32 CPCIDevice::ReadMem_Bar(int func, int bar, u32 address, int dsize)
00540 {
00541 FAILURE_3(NotImplemented, "%s(%s).%d No BAR read handler installed",
00542 myCfg->get_myName(), myCfg->get_myValue(), func);
00543 }
00544
00545 void CPCIDevice::WriteMem_Bar(int func, int bar, u32 address, int dsize, u32 data)
00546 {
00547 FAILURE_3(NotImplemented, "%s(%s).%d No BAR write handler installed",
00548 myCfg->get_myName(), myCfg->get_myValue(), func);
00549 }
00550
00558 void CPCIDevice::do_pci_read(u32 address, void* dest, size_t element_size,
00559 size_t element_count)
00560 {
00561 size_t el;
00562 char* dst = (char*) dest;
00563
00564 if(element_count == 0)
00565 return;
00566
00567
00568 u64 phys_addr = cSystem->PCI_Phys(myPCIBus, address);
00569
00570
00571 if(element_count == 1)
00572 {
00573 switch(element_size)
00574 {
00575 case 1:
00576 * (u8*) dest = (u8) cSystem->ReadMem(phys_addr, 8, this);
00577 break;
00578
00579 case 2:
00580 * (u16*) dest = (u16) cSystem->ReadMem(phys_addr, 16, this);
00581 break;
00582
00583 case 4:
00584 * (u32*) dest = (u32) cSystem->ReadMem(phys_addr, 32, this);
00585 break;
00586
00587 default:
00588 FAILURE(InvalidArgument, "Strange element size");
00589 }
00590
00591 return;
00592 }
00593
00594 #if defined(ES40_BIG_ENDIAN)
00595
00596
00597
00598 if(element_size == 1)
00599 {
00600 #endif
00601
00602
00603 char* memptr = cSystem->PtrToMem(phys_addr);
00604
00605
00606
00607 if(memptr)
00608 {
00609 memcpy(dest, memptr, element_size * element_count);
00610 return;
00611 }
00612
00613 #if defined(ES40_BIG_ENDIAN)
00614 }
00615 #endif
00616
00617
00618
00619 switch(element_size)
00620 {
00621 case 1:
00622 for(el = 0; el < element_count; el++)
00623 {
00624 *(u8*) dst = (u8) cSystem->ReadMem(phys_addr, 8, this);
00625 dst++;
00626 phys_addr++;
00627 }
00628 break;
00629
00630 case 2:
00631 {
00632 *(u16*) dst = endian_16((u16) cSystem->ReadMem(phys_addr, 16, this));
00633 dst += 2;
00634 phys_addr += 2;
00635 }
00636 break;
00637
00638 case 4:
00639 {
00640 *(u32*) dst = endian_32((u32) cSystem->ReadMem(phys_addr, 32, this));
00641 dst += 4;;
00642 phys_addr += 4;
00643 }
00644 break;
00645
00646 default:
00647 FAILURE(InvalidArgument, "Strange element size");
00648 }
00649 }
00650
00658 void CPCIDevice::do_pci_write(u32 address, void* source, size_t element_size,
00659 size_t element_count)
00660 {
00661 size_t el;
00662 char* src = (char*) source;
00663
00664 if(element_count == 0)
00665 return;
00666
00667
00668 u64 phys_addr = cSystem->PCI_Phys(myPCIBus, address);
00669
00670
00671 if(element_count == 1)
00672 {
00673 switch(element_size)
00674 {
00675 case 1: cSystem->WriteMem(phys_addr, 8, *(u8*) source, this); break;
00676 case 2: cSystem->WriteMem(phys_addr, 16, *(u16*) source, this); break;
00677 case 4: cSystem->WriteMem(phys_addr, 32, *(u32*) source, this); break;
00678 default: FAILURE(InvalidArgument, "Strange element size");
00679 }
00680
00681 return;
00682 }
00683
00684 #if defined(ES40_BIG_ENDIAN)
00685
00686
00687
00688 if(element_size == 1)
00689 {
00690 #endif
00691
00692
00693 char* memptr = cSystem->PtrToMem(phys_addr);
00694
00695
00696
00697 if(memptr)
00698 {
00699 memcpy(memptr, source, element_size * element_count);
00700 return;
00701 }
00702
00703 #if defined(ES40_BIG_ENDIAN)
00704 }
00705 #endif
00706
00707
00708
00709 switch(element_size)
00710 {
00711 case 1:
00712 for(el = 0; el < element_count; el++)
00713 {
00714 cSystem->WriteMem(phys_addr, 8, *(u8*) src, this);
00715 src++;
00716 phys_addr++;
00717 }
00718 break;
00719
00720 case 2:
00721 {
00722 cSystem->WriteMem(phys_addr, 16, endian_16(*(u16*) src), this);
00723 src += 2;
00724 phys_addr += 2;
00725 }
00726 break;
00727
00728 case 4:
00729 {
00730 cSystem->WriteMem(phys_addr, 32, endian_32(*(u32*) src), this);
00731 src += 4;;
00732 phys_addr += 4;
00733 }
00734 break;
00735
00736 default:
00737 FAILURE(InvalidArgument, "Strange element size");
00738 }
00739 }