6
PCI_CONFIG_ADDRESS = 0xCF8,
7
PCI_CONFIG_DATA = 0xCFC;
15
this.pci_addr = new Uint8Array(4);
16
this.pci_value = new Uint8Array(4);
17
this.pci_response = new Uint8Array(4);
18
this.pci_status = new Uint8Array(4);
20
this.pci_addr32 = new Int32Array(this.pci_addr.buffer);
21
this.pci_value32 = new Int32Array(this.pci_value.buffer);
22
this.pci_response32 = new Int32Array(this.pci_response.buffer);
23
this.pci_status32 = new Int32Array(this.pci_status.buffer);
25
this.device_spaces = [];
31
for(var i = 0; i < 256; i++)
33
this.device_spaces[i] = undefined;
34
this.devices[i] = undefined;
39
cpu.io.register_write(PCI_CONFIG_DATA, this,
42
this.pci_write8(this.pci_addr32[0], value);
46
this.pci_write16(this.pci_addr32[0], value);
50
this.pci_write32(this.pci_addr32[0], value);
53
cpu.io.register_write(PCI_CONFIG_DATA + 1, this,
56
this.pci_write8(this.pci_addr32[0] + 1 | 0, value);
59
cpu.io.register_write(PCI_CONFIG_DATA + 2, this,
62
this.pci_write8(this.pci_addr32[0] + 2 | 0, value);
66
this.pci_write16(this.pci_addr32[0] + 2 | 0, value);
69
cpu.io.register_write(PCI_CONFIG_DATA + 3, this,
72
this.pci_write8(this.pci_addr32[0] + 3 | 0, value);
75
cpu.io.register_read_consecutive(PCI_CONFIG_DATA, this,
78
return this.pci_response[0];
82
return this.pci_response[1];
86
return this.pci_response[2];
90
return this.pci_response[3];
94
cpu.io.register_read_consecutive(PCI_CONFIG_ADDRESS, this,
97
return this.pci_status[0];
101
return this.pci_status[1];
105
return this.pci_status[2];
109
return this.pci_status[3];
113
cpu.io.register_write_consecutive(PCI_CONFIG_ADDRESS, this,
116
this.pci_addr[0] = out_byte & 0xFC;
120
if((this.pci_addr[1] & 0x06) === 0x02 && (out_byte & 0x06) === 0x06)
122
dbg_log("CPU reboot via PCI");
123
cpu.reboot_internal();
127
this.pci_addr[1] = out_byte;
131
this.pci_addr[2] = out_byte;
135
this.pci_addr[3] = out_byte;
165
0x86, 0x80, 0x37, 0x12, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
166
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PAM0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175
this.register_device(host_bridge);
181
0x86, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x80, 0x00,
182
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187
name: "82371SB PIIX3 ISA",
189
this.isa_bridge_space = this.register_device(this.isa_bridge);
190
this.isa_bridge_space8 = new Uint8Array(this.isa_bridge_space.buffer);
201
PCI.prototype.get_state = function()
205
for(var i = 0; i < 256; i++)
207
state[i] = this.device_spaces[i];
210
state[256] = this.pci_addr;
211
state[257] = this.pci_value;
212
state[258] = this.pci_response;
213
state[259] = this.pci_status;
218
PCI.prototype.set_state = function(state)
220
for(var i = 0; i < 256; i++)
222
var device = this.devices[i];
223
var space = state[i];
225
if(!device || !space)
229
dbg_log("Warning: While restoring PCI device: Device exists in current " +
230
"configuration but not in snapshot (" + device.name + ")");
234
dbg_log("Warning: While restoring PCI device: Device doesn't exist in current " +
235
"configuration but does in snapshot (device " + h(i, 2) + ")");
240
for(var bar_nr = 0; bar_nr < device.pci_bars.length; bar_nr++)
242
var value = space[(0x10 >> 2) + bar_nr];
246
var bar = device.pci_bars[bar_nr];
247
var from = bar.original_bar & ~1 & 0xFFFF;
248
var to = value & ~1 & 0xFFFF;
249
this.set_io_bars(bar, from, to);
257
this.device_spaces[i].set(space);
260
this.pci_addr.set(state[256]);
261
this.pci_value.set(state[257]);
262
this.pci_response.set(state[258]);
263
this.pci_status.set(state[259]);
266
PCI.prototype.pci_query = function()
268
var dbg_line = "query";
273
var bdf = this.pci_addr[2] << 8 | this.pci_addr[1],
274
addr = this.pci_addr[0] & 0xFC,
277
dev = bdf >> 3 & 0x1F,
279
enabled = this.pci_addr[3] >> 7;
281
dbg_line += " enabled=" + enabled;
282
dbg_line += " bdf=" + h(bdf, 4);
283
dbg_line += " dev=" + h(dev, 2);
284
dbg_line += " addr=" + h(addr, 2);
286
var device = this.device_spaces[bdf];
288
if(device !== undefined)
290
this.pci_status32[0] = 0x80000000 | 0;
292
if(addr < device.byteLength)
294
this.pci_response32[0] = device[addr >> 2];
299
this.pci_response32[0] = 0;
302
dbg_line += " " + h(this.pci_addr32[0] >>> 0, 8) + " -> " + h(this.pci_response32[0] >>> 0, 8);
304
if(addr >= device.byteLength)
306
dbg_line += " (undef)";
309
dbg_line += " (" + this.devices[bdf].name + ")";
311
dbg_log(dbg_line, LOG_PCI);
315
this.pci_response32[0] = -1;
316
this.pci_status32[0] = 0;
320
PCI.prototype.pci_write8 = function(address, written)
322
var bdf = address >> 8 & 0xFFFF;
323
var addr = address & 0xFF;
325
var space = new Uint8Array(this.device_spaces[bdf].buffer);
326
var device = this.devices[bdf];
333
dbg_assert(!(addr >= 0x10 && addr < 0x2C || addr >= 0x30 && addr < 0x34),
334
"PCI: Expected 32-bit write, got 8-bit (addr: " + h(addr) + ")");
336
dbg_log("PCI write8 dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +
337
" value=" + h(written, 2), LOG_PCI);
339
space[addr] = written;
342
PCI.prototype.pci_write16 = function(address, written)
344
dbg_assert((address & 1) === 0);
346
var bdf = address >> 8 & 0xFFFF;
347
var addr = address & 0xFF;
349
var space = new Uint16Array(this.device_spaces[bdf].buffer);
350
var device = this.devices[bdf];
357
if(addr >= 0x10 && addr < 0x2C)
360
dbg_log("Warning: PCI: Expected 32-bit write, got 16-bit (addr: " + h(addr) + ")");
364
dbg_assert(!(addr >= 0x30 && addr < 0x34),
365
"PCI: Expected 32-bit write, got 16-bit (addr: " + h(addr) + ")");
367
dbg_log("PCI writ16 dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +
368
" value=" + h(written, 4), LOG_PCI);
370
space[addr >>> 1] = written;
373
PCI.prototype.pci_write32 = function(address, written)
375
dbg_assert((address & 3) === 0);
377
var bdf = address >> 8 & 0xFFFF;
378
var addr = address & 0xFF;
380
var space = this.device_spaces[bdf];
381
var device = this.devices[bdf];
388
if(addr >= 0x10 && addr < 0x28)
390
var bar_nr = addr - 0x10 >> 2;
391
var bar = device.pci_bars[bar_nr];
393
dbg_log("BAR" + bar_nr + " exists=" + (bar ? "y" : "n") + " changed to " +
394
h(written >>> 0) + " dev=" + h(bdf >> 3, 2) + " (" + device.name + ") ", LOG_PCI);
398
dbg_assert(!(bar.size & bar.size - 1), "bar size should be power of 2");
400
var space_addr = addr >> 2;
401
var type = space[space_addr] & 1;
403
if((written | 3 | bar.size - 1) === -1)
405
written = ~(bar.size - 1) | type;
409
space[space_addr] = written;
417
var original_bar = bar.original_bar;
419
if((written & ~0xF) !== (original_bar & ~0xF))
422
dbg_log("Warning: Changing memory bar not supported, ignored", LOG_PCI);
426
space[space_addr] = original_bar;
433
dbg_assert(type === 1);
435
var from = space[space_addr] & ~1 & 0xFFFF;
436
var to = written & ~1 & 0xFFFF;
437
dbg_log("io bar changed from " + h(from >>> 0, 8) +
438
" to " + h(to >>> 0, 8) + " size=" + bar.size, LOG_PCI);
439
this.set_io_bars(bar, from, to);
440
space[space_addr] = written | 1;
445
space[addr >> 2] = 0;
448
dbg_log("BAR effective value: " + h(space[addr >> 2] >>> 0), LOG_PCI);
450
else if(addr === 0x30)
452
dbg_log("PCI write rom address dev=" + h(bdf >> 3, 2) + " (" + device.name + ")" +
453
" value=" + h(written >>> 0, 8), LOG_PCI);
455
if(device.pci_rom_size)
457
if((written | 0x7FF) === (0xFFFFFFFF|0))
459
space[addr >> 2] = -device.pci_rom_size | 0;
463
space[addr >> 2] = device.pci_rom_address | 0;
468
space[addr >> 2] = 0;
471
else if(addr === 0x04)
473
dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +
474
" value=" + h(written >>> 0, 8), LOG_PCI);
478
dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) +
479
" value=" + h(written >>> 0, 8), LOG_PCI);
480
space[addr >>> 2] = written;
484
PCI.prototype.register_device = function(device)
486
dbg_assert(device.pci_id !== undefined);
487
dbg_assert(device.pci_space !== undefined);
488
dbg_assert(device.pci_bars !== undefined);
490
var device_id = device.pci_id;
492
dbg_log("PCI register bdf=" + h(device_id) + " (" + device.name + ")", LOG_PCI);
494
dbg_assert(!this.devices[device_id]);
495
dbg_assert(device.pci_space.length >= 64);
496
dbg_assert(device_id < this.devices.length);
499
var space = new Int32Array(64);
500
space.set(new Int32Array(new Uint8Array(device.pci_space).buffer));
501
this.device_spaces[device_id] = space;
502
this.devices[device_id] = device;
504
var bar_space = space.slice(4, 10);
506
for(var i = 0; i < device.pci_bars.length; i++)
508
var bar = device.pci_bars[i];
515
var bar_base = bar_space[i];
516
var type = bar_base & 1;
518
bar.original_bar = bar_base;
527
dbg_assert(type === 1);
528
var port = bar_base & ~1;
530
for(var j = 0; j < bar.size; j++)
532
bar.entries[j] = this.io.ports[port + j];
540
PCI.prototype.set_io_bars = function(bar, from, to)
542
var count = bar.size;
543
dbg_log("Move io bars: from=" + h(from) + " to=" + h(to) + " count=" + count, LOG_PCI);
545
var ports = this.io.ports;
547
for(var i = 0; i < count; i++)
549
var old_entry = ports[from + i];
550
ports[from + i] = this.io.create_empty_entry();
552
if(old_entry.read8 === this.io.empty_port_read8 &&
553
old_entry.read16 === this.io.empty_port_read16 &&
554
old_entry.read32 === this.io.empty_port_read32 &&
555
old_entry.write8 === this.io.empty_port_write &&
556
old_entry.write16 === this.io.empty_port_write &&
557
old_entry.write32 === this.io.empty_port_write)
559
dbg_log("Warning: Bad IO bar: Source not mapped, port=" + h(from + i, 4), LOG_PCI);
562
var entry = bar.entries[i];
563
var empty_entry = ports[to + i];
564
dbg_assert(entry && empty_entry);
566
ports[to + i] = entry;
568
if(empty_entry.read8 === this.io.empty_port_read8 ||
569
empty_entry.read16 === this.io.empty_port_read16 ||
570
empty_entry.read32 === this.io.empty_port_read32 ||
571
empty_entry.write8 === this.io.empty_port_write ||
572
empty_entry.write16 === this.io.empty_port_write ||
573
empty_entry.write32 === this.io.empty_port_write)
577
dbg_log("Warning: Bad IO bar: Target already mapped, port=" + h(to + i, 4), LOG_PCI);
582
PCI.prototype.raise_irq = function(pci_id)
584
var space = this.device_spaces[pci_id];
587
var pin = (space[0x3C >>> 2] >> 8 & 0xFF) - 1;
588
var device = (pci_id >> 3) - 1 & 0xFF;
589
var parent_pin = pin + device & 3;
590
var irq = this.isa_bridge_space8[0x60 + parent_pin];
594
this.cpu.device_raise_irq(irq);
597
PCI.prototype.lower_irq = function(pci_id)
599
var space = this.device_spaces[pci_id];
602
var pin = space[0x3C >>> 2] >> 8 & 0xFF;
603
var device = pci_id >> 3 & 0xFF;
604
var parent_pin = pin + device - 2 & 3;
605
var irq = this.isa_bridge_space8[0x60 + parent_pin];
609
this.cpu.device_lower_irq(irq);