@aptre/v86 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- package/src/virtio_net.ts +326 -0
package/src/pci.ts
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
import { LOG_PCI } from './const.js'
|
|
2
|
+
import { h } from './lib.js'
|
|
3
|
+
import { dbg_assert, dbg_log } from './log.js'
|
|
4
|
+
import { IO } from './io.js'
|
|
5
|
+
|
|
6
|
+
// http://wiki.osdev.org/PCI
|
|
7
|
+
|
|
8
|
+
export const PCI_CONFIG_ADDRESS = 0xcf8
|
|
9
|
+
export const PCI_CONFIG_DATA = 0xcfc
|
|
10
|
+
|
|
11
|
+
// Minimal interface for CPU fields PCI uses.
|
|
12
|
+
interface PCICpu {
|
|
13
|
+
io: IO
|
|
14
|
+
device_raise_irq(irq: number): void
|
|
15
|
+
device_lower_irq(irq: number): void
|
|
16
|
+
reboot_internal(): void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Mirrors IOPortEntry from io.ts (not exported there).
|
|
20
|
+
interface PCIPortEntry {
|
|
21
|
+
read8: (port: number) => number
|
|
22
|
+
read16: (port: number) => number
|
|
23
|
+
read32: (port: number) => number
|
|
24
|
+
write8: (port: number) => void
|
|
25
|
+
write16: (port: number) => void
|
|
26
|
+
write32: (port: number) => void
|
|
27
|
+
device: { name?: string } | undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// PCIBar starts as { size: number } from devices. register_device()
|
|
31
|
+
// populates original_bar and entries at registration time.
|
|
32
|
+
export interface PCIBar {
|
|
33
|
+
size: number
|
|
34
|
+
original_bar?: number
|
|
35
|
+
entries?: PCIPortEntry[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PCIDevice {
|
|
39
|
+
pci_id: number
|
|
40
|
+
pci_space: number[]
|
|
41
|
+
pci_bars: (PCIBar | undefined)[]
|
|
42
|
+
name: string
|
|
43
|
+
pci_rom_size?: number
|
|
44
|
+
pci_rom_address?: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class PCI {
|
|
48
|
+
name: string
|
|
49
|
+
pci_addr: Uint8Array
|
|
50
|
+
pci_value: Uint8Array
|
|
51
|
+
pci_response: Uint8Array
|
|
52
|
+
pci_status: Uint8Array
|
|
53
|
+
|
|
54
|
+
pci_addr32: Int32Array
|
|
55
|
+
pci_value32: Int32Array
|
|
56
|
+
pci_response32: Int32Array
|
|
57
|
+
pci_status32: Int32Array
|
|
58
|
+
|
|
59
|
+
device_spaces: (Int32Array | undefined)[]
|
|
60
|
+
devices: (PCIDevice | undefined)[]
|
|
61
|
+
|
|
62
|
+
cpu: PCICpu
|
|
63
|
+
io: IO
|
|
64
|
+
|
|
65
|
+
isa_bridge: PCIDevice
|
|
66
|
+
isa_bridge_space: Int32Array
|
|
67
|
+
isa_bridge_space8: Uint8Array
|
|
68
|
+
|
|
69
|
+
constructor(cpu: PCICpu) {
|
|
70
|
+
this.name = 'PCI'
|
|
71
|
+
this.pci_addr = new Uint8Array(4)
|
|
72
|
+
this.pci_value = new Uint8Array(4)
|
|
73
|
+
this.pci_response = new Uint8Array(4)
|
|
74
|
+
this.pci_status = new Uint8Array(4)
|
|
75
|
+
|
|
76
|
+
this.pci_addr32 = new Int32Array(this.pci_addr.buffer)
|
|
77
|
+
this.pci_value32 = new Int32Array(this.pci_value.buffer)
|
|
78
|
+
this.pci_response32 = new Int32Array(this.pci_response.buffer)
|
|
79
|
+
this.pci_status32 = new Int32Array(this.pci_status.buffer)
|
|
80
|
+
|
|
81
|
+
this.device_spaces = []
|
|
82
|
+
this.devices = []
|
|
83
|
+
|
|
84
|
+
this.cpu = cpu
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < 256; i++) {
|
|
87
|
+
this.device_spaces[i] = undefined
|
|
88
|
+
this.devices[i] = undefined
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.io = cpu.io
|
|
92
|
+
|
|
93
|
+
cpu.io.register_write(
|
|
94
|
+
PCI_CONFIG_DATA,
|
|
95
|
+
this,
|
|
96
|
+
(value: number): void => {
|
|
97
|
+
this.pci_write8(this.pci_addr32[0], value)
|
|
98
|
+
},
|
|
99
|
+
(value: number): void => {
|
|
100
|
+
this.pci_write16(this.pci_addr32[0], value)
|
|
101
|
+
},
|
|
102
|
+
(value: number): void => {
|
|
103
|
+
this.pci_write32(this.pci_addr32[0], value)
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
cpu.io.register_write(
|
|
108
|
+
PCI_CONFIG_DATA + 1,
|
|
109
|
+
this,
|
|
110
|
+
(value: number): void => {
|
|
111
|
+
this.pci_write8((this.pci_addr32[0] + 1) | 0, value)
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
cpu.io.register_write(
|
|
116
|
+
PCI_CONFIG_DATA + 2,
|
|
117
|
+
this,
|
|
118
|
+
(value: number): void => {
|
|
119
|
+
this.pci_write8((this.pci_addr32[0] + 2) | 0, value)
|
|
120
|
+
},
|
|
121
|
+
(value: number): void => {
|
|
122
|
+
this.pci_write16((this.pci_addr32[0] + 2) | 0, value)
|
|
123
|
+
},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
cpu.io.register_write(
|
|
127
|
+
PCI_CONFIG_DATA + 3,
|
|
128
|
+
this,
|
|
129
|
+
(value: number): void => {
|
|
130
|
+
this.pci_write8((this.pci_addr32[0] + 3) | 0, value)
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
cpu.io.register_read_consecutive(
|
|
135
|
+
PCI_CONFIG_DATA,
|
|
136
|
+
this,
|
|
137
|
+
(): number => {
|
|
138
|
+
return this.pci_response[0]
|
|
139
|
+
},
|
|
140
|
+
(): number => {
|
|
141
|
+
return this.pci_response[1]
|
|
142
|
+
},
|
|
143
|
+
(): number => {
|
|
144
|
+
return this.pci_response[2]
|
|
145
|
+
},
|
|
146
|
+
(): number => {
|
|
147
|
+
return this.pci_response[3]
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
cpu.io.register_read_consecutive(
|
|
152
|
+
PCI_CONFIG_ADDRESS,
|
|
153
|
+
this,
|
|
154
|
+
(): number => {
|
|
155
|
+
return this.pci_status[0]
|
|
156
|
+
},
|
|
157
|
+
(): number => {
|
|
158
|
+
return this.pci_status[1]
|
|
159
|
+
},
|
|
160
|
+
(): number => {
|
|
161
|
+
return this.pci_status[2]
|
|
162
|
+
},
|
|
163
|
+
(): number => {
|
|
164
|
+
return this.pci_status[3]
|
|
165
|
+
},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
cpu.io.register_write_consecutive(
|
|
169
|
+
PCI_CONFIG_ADDRESS,
|
|
170
|
+
this,
|
|
171
|
+
(out_byte: number): void => {
|
|
172
|
+
this.pci_addr[0] = out_byte & 0xfc
|
|
173
|
+
},
|
|
174
|
+
(out_byte: number): void => {
|
|
175
|
+
if (
|
|
176
|
+
(this.pci_addr[1] & 0x06) === 0x02 &&
|
|
177
|
+
(out_byte & 0x06) === 0x06
|
|
178
|
+
) {
|
|
179
|
+
dbg_log('CPU reboot via PCI')
|
|
180
|
+
cpu.reboot_internal()
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this.pci_addr[1] = out_byte
|
|
185
|
+
},
|
|
186
|
+
(out_byte: number): void => {
|
|
187
|
+
this.pci_addr[2] = out_byte
|
|
188
|
+
},
|
|
189
|
+
(out_byte: number): void => {
|
|
190
|
+
this.pci_addr[3] = out_byte
|
|
191
|
+
this.pci_query()
|
|
192
|
+
},
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Some experimental PCI devices taken from my PC:
|
|
196
|
+
|
|
197
|
+
// 00:00.0 Host bridge: Intel Corporation 4 Series Chipset DRAM Controller (rev 02)
|
|
198
|
+
//var host_bridge = {
|
|
199
|
+
// pci_id: 0,
|
|
200
|
+
// pci_space: [
|
|
201
|
+
// 0x86, 0x80, 0x20, 0x2e, 0x06, 0x00, 0x90, 0x20, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
|
|
202
|
+
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
203
|
+
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xd3, 0x82,
|
|
204
|
+
// 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
205
|
+
// ],
|
|
206
|
+
// pci_bars: [],
|
|
207
|
+
//};
|
|
208
|
+
|
|
209
|
+
// This needs to be set in order for seabios to not execute code outside of
|
|
210
|
+
// mapped memory. While we map the BIOS into high memory, we don't allow
|
|
211
|
+
// executing code there, which enables optimisations in read_imm8.
|
|
212
|
+
// See [make_bios_writable_intel] in src/fw/shadow.c in seabios for details
|
|
213
|
+
const PAM0 = 0x10
|
|
214
|
+
|
|
215
|
+
const host_bridge: PCIDevice = {
|
|
216
|
+
pci_id: 0,
|
|
217
|
+
pci_space: [
|
|
218
|
+
// 00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
|
|
219
|
+
0x86,
|
|
220
|
+
0x80,
|
|
221
|
+
0x37,
|
|
222
|
+
0x12,
|
|
223
|
+
0x00,
|
|
224
|
+
0x00,
|
|
225
|
+
0x00,
|
|
226
|
+
0x00,
|
|
227
|
+
0x02,
|
|
228
|
+
0x00,
|
|
229
|
+
0x00,
|
|
230
|
+
0x06,
|
|
231
|
+
0x00,
|
|
232
|
+
0x00,
|
|
233
|
+
0x00,
|
|
234
|
+
0x00,
|
|
235
|
+
0x00,
|
|
236
|
+
0x00,
|
|
237
|
+
0x00,
|
|
238
|
+
0x00,
|
|
239
|
+
0x00,
|
|
240
|
+
0x00,
|
|
241
|
+
0x00,
|
|
242
|
+
0x00,
|
|
243
|
+
0x00,
|
|
244
|
+
0x00,
|
|
245
|
+
0x00,
|
|
246
|
+
0x00,
|
|
247
|
+
0x00,
|
|
248
|
+
0x00,
|
|
249
|
+
0x00,
|
|
250
|
+
0x00,
|
|
251
|
+
0x00,
|
|
252
|
+
0x00,
|
|
253
|
+
0x00,
|
|
254
|
+
0x00,
|
|
255
|
+
0x00,
|
|
256
|
+
0x00,
|
|
257
|
+
0x00,
|
|
258
|
+
0x00,
|
|
259
|
+
0x00,
|
|
260
|
+
0x00,
|
|
261
|
+
0x00,
|
|
262
|
+
0x00,
|
|
263
|
+
0x00,
|
|
264
|
+
0x00,
|
|
265
|
+
0x00,
|
|
266
|
+
0x00,
|
|
267
|
+
0x00,
|
|
268
|
+
0x00,
|
|
269
|
+
0x00,
|
|
270
|
+
0x00,
|
|
271
|
+
0x00,
|
|
272
|
+
0x00,
|
|
273
|
+
0x00,
|
|
274
|
+
0x00,
|
|
275
|
+
0x00,
|
|
276
|
+
0x00,
|
|
277
|
+
0x00,
|
|
278
|
+
0x00,
|
|
279
|
+
0x00,
|
|
280
|
+
0x00,
|
|
281
|
+
0x00,
|
|
282
|
+
0x00,
|
|
283
|
+
0x00,
|
|
284
|
+
0x00,
|
|
285
|
+
0x00,
|
|
286
|
+
0x00,
|
|
287
|
+
0x00,
|
|
288
|
+
0x00,
|
|
289
|
+
0x00,
|
|
290
|
+
0x00,
|
|
291
|
+
0x00,
|
|
292
|
+
0x00,
|
|
293
|
+
0x00,
|
|
294
|
+
0x00,
|
|
295
|
+
0x00,
|
|
296
|
+
0x00,
|
|
297
|
+
0x00,
|
|
298
|
+
0x00,
|
|
299
|
+
0x00,
|
|
300
|
+
0x00,
|
|
301
|
+
0x00,
|
|
302
|
+
0x00,
|
|
303
|
+
0x00,
|
|
304
|
+
0x00,
|
|
305
|
+
0x00,
|
|
306
|
+
0x00,
|
|
307
|
+
PAM0,
|
|
308
|
+
0x00,
|
|
309
|
+
0x00,
|
|
310
|
+
0x00,
|
|
311
|
+
0x00,
|
|
312
|
+
0x00,
|
|
313
|
+
0x00,
|
|
314
|
+
],
|
|
315
|
+
pci_bars: [],
|
|
316
|
+
name: '82441FX PMC',
|
|
317
|
+
}
|
|
318
|
+
this.register_device(host_bridge)
|
|
319
|
+
|
|
320
|
+
this.isa_bridge = {
|
|
321
|
+
pci_id: 1 << 3,
|
|
322
|
+
pci_space: [
|
|
323
|
+
// 00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
|
|
324
|
+
0x86,
|
|
325
|
+
0x80, 0x00, 0x70, 0x07, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01,
|
|
326
|
+
0x06, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
327
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
328
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
329
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
330
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
331
|
+
0x00, 0x00, 0x00,
|
|
332
|
+
],
|
|
333
|
+
pci_bars: [],
|
|
334
|
+
name: '82371SB PIIX3 ISA',
|
|
335
|
+
}
|
|
336
|
+
this.isa_bridge_space = this.register_device(this.isa_bridge)
|
|
337
|
+
this.isa_bridge_space8 = new Uint8Array(this.isa_bridge_space.buffer)
|
|
338
|
+
|
|
339
|
+
// 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90)
|
|
340
|
+
//this.register_device([
|
|
341
|
+
// 0x86, 0x80, 0x4e, 0x24, 0x07, 0x01, 0x10, 0x00, 0x90, 0x01, 0x04, 0x06, 0x00, 0x00, 0x01, 0x00,
|
|
342
|
+
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x20, 0xe0, 0xe0, 0x80, 0x22,
|
|
343
|
+
// 0xb0, 0xfe, 0xb0, 0xfe, 0xf1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
344
|
+
// 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00,
|
|
345
|
+
//], 0x1e << 3);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
get_state(): (Int32Array | Uint8Array | undefined)[] {
|
|
349
|
+
const state: (Int32Array | Uint8Array | undefined)[] = []
|
|
350
|
+
|
|
351
|
+
for (let i = 0; i < 256; i++) {
|
|
352
|
+
state[i] = this.device_spaces[i]
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
state[256] = this.pci_addr
|
|
356
|
+
state[257] = this.pci_value
|
|
357
|
+
state[258] = this.pci_response
|
|
358
|
+
state[259] = this.pci_status
|
|
359
|
+
|
|
360
|
+
return state
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
set_state(state: (Int32Array | Uint8Array | undefined)[]): void {
|
|
364
|
+
for (let i = 0; i < 256; i++) {
|
|
365
|
+
const device = this.devices[i]
|
|
366
|
+
const space = state[i]
|
|
367
|
+
|
|
368
|
+
if (!device || !space) {
|
|
369
|
+
if (device) {
|
|
370
|
+
dbg_log(
|
|
371
|
+
'Warning: While restoring PCI device: Device exists in current ' +
|
|
372
|
+
'configuration but not in snapshot (' +
|
|
373
|
+
device.name +
|
|
374
|
+
')',
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
if (space) {
|
|
378
|
+
dbg_log(
|
|
379
|
+
"Warning: While restoring PCI device: Device doesn't exist in current " +
|
|
380
|
+
'configuration but does in snapshot (device ' +
|
|
381
|
+
h(i, 2) +
|
|
382
|
+
')',
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
continue
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const space32 = new Int32Array(space.buffer)
|
|
389
|
+
|
|
390
|
+
for (let bar_nr = 0; bar_nr < device.pci_bars.length; bar_nr++) {
|
|
391
|
+
const value = space32[(0x10 >> 2) + bar_nr]
|
|
392
|
+
|
|
393
|
+
if (value & 1) {
|
|
394
|
+
const bar = device.pci_bars[bar_nr]
|
|
395
|
+
if (bar) {
|
|
396
|
+
const from = bar.original_bar! & ~1 & 0xffff
|
|
397
|
+
const to = value & ~1 & 0xffff
|
|
398
|
+
this.set_io_bars(bar, from, to)
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
// memory, cannot be changed
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const device_space = this.device_spaces[i]
|
|
406
|
+
if (device_space) {
|
|
407
|
+
device_space.set(new Int32Array(space.buffer))
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.pci_addr.set(state[256]!)
|
|
412
|
+
this.pci_value.set(state[257]!)
|
|
413
|
+
this.pci_response.set(state[258]!)
|
|
414
|
+
this.pci_status.set(state[259]!)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
pci_query(): void {
|
|
418
|
+
let dbg_line = 'query'
|
|
419
|
+
|
|
420
|
+
// Bit | .31 .0
|
|
421
|
+
// Fmt | EBBBBBBBBDDDDDFFFRRRRRR00
|
|
422
|
+
|
|
423
|
+
const bdf = (this.pci_addr[2] << 8) | this.pci_addr[1],
|
|
424
|
+
addr = this.pci_addr[0] & 0xfc,
|
|
425
|
+
//devfn = bdf & 0xFF,
|
|
426
|
+
//bus = bdf >> 8,
|
|
427
|
+
dev = (bdf >> 3) & 0x1f,
|
|
428
|
+
//fn = bdf & 7,
|
|
429
|
+
enabled = this.pci_addr[3] >> 7
|
|
430
|
+
|
|
431
|
+
dbg_line += ' enabled=' + enabled
|
|
432
|
+
dbg_line += ' bdf=' + h(bdf, 4)
|
|
433
|
+
dbg_line += ' dev=' + h(dev, 2)
|
|
434
|
+
dbg_line += ' addr=' + h(addr, 2)
|
|
435
|
+
|
|
436
|
+
const device = this.device_spaces[bdf]
|
|
437
|
+
|
|
438
|
+
if (device !== undefined) {
|
|
439
|
+
this.pci_status32[0] = 0x80000000 | 0
|
|
440
|
+
|
|
441
|
+
if (addr < device.byteLength) {
|
|
442
|
+
this.pci_response32[0] = device[addr >> 2]
|
|
443
|
+
} else {
|
|
444
|
+
// required by freebsd-9.1
|
|
445
|
+
this.pci_response32[0] = 0
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
dbg_line +=
|
|
449
|
+
' ' +
|
|
450
|
+
h(this.pci_addr32[0] >>> 0, 8) +
|
|
451
|
+
' -> ' +
|
|
452
|
+
h(this.pci_response32[0] >>> 0, 8)
|
|
453
|
+
|
|
454
|
+
if (addr >= device.byteLength) {
|
|
455
|
+
dbg_line += ' (undef)'
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
dbg_line += ' (' + this.devices[bdf]!.name + ')'
|
|
459
|
+
|
|
460
|
+
dbg_log(dbg_line, LOG_PCI)
|
|
461
|
+
} else {
|
|
462
|
+
this.pci_response32[0] = -1
|
|
463
|
+
this.pci_status32[0] = 0
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
pci_write8(address: number, written: number): void {
|
|
468
|
+
const bdf = (address >> 8) & 0xffff
|
|
469
|
+
const addr = address & 0xff
|
|
470
|
+
|
|
471
|
+
const device_space = this.device_spaces[bdf]
|
|
472
|
+
const device = this.devices[bdf]
|
|
473
|
+
|
|
474
|
+
if (!device_space) {
|
|
475
|
+
return
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const space = new Uint8Array(device_space.buffer)
|
|
479
|
+
|
|
480
|
+
dbg_assert(
|
|
481
|
+
!((addr >= 0x10 && addr < 0x2c) || (addr >= 0x30 && addr < 0x34)),
|
|
482
|
+
'PCI: Expected 32-bit write, got 8-bit (addr: ' + h(addr) + ')',
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
dbg_log(
|
|
486
|
+
'PCI write8 dev=' +
|
|
487
|
+
h(bdf >> 3, 2) +
|
|
488
|
+
' (' +
|
|
489
|
+
device!.name +
|
|
490
|
+
') addr=' +
|
|
491
|
+
h(addr, 4) +
|
|
492
|
+
' value=' +
|
|
493
|
+
h(written, 2),
|
|
494
|
+
LOG_PCI,
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
space[addr] = written
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
pci_write16(address: number, written: number): void {
|
|
501
|
+
dbg_assert((address & 1) === 0)
|
|
502
|
+
|
|
503
|
+
const bdf = (address >> 8) & 0xffff
|
|
504
|
+
const addr = address & 0xff
|
|
505
|
+
|
|
506
|
+
const device_space = this.device_spaces[bdf]
|
|
507
|
+
const device = this.devices[bdf]
|
|
508
|
+
|
|
509
|
+
if (!device_space) {
|
|
510
|
+
return
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const space = new Uint16Array(device_space.buffer)
|
|
514
|
+
|
|
515
|
+
if (addr >= 0x10 && addr < 0x2c) {
|
|
516
|
+
// Bochs bios
|
|
517
|
+
dbg_log(
|
|
518
|
+
'Warning: PCI: Expected 32-bit write, got 16-bit (addr: ' +
|
|
519
|
+
h(addr) +
|
|
520
|
+
')',
|
|
521
|
+
)
|
|
522
|
+
return
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
dbg_assert(
|
|
526
|
+
!(addr >= 0x30 && addr < 0x34),
|
|
527
|
+
'PCI: Expected 32-bit write, got 16-bit (addr: ' + h(addr) + ')',
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
dbg_log(
|
|
531
|
+
'PCI writ16 dev=' +
|
|
532
|
+
h(bdf >> 3, 2) +
|
|
533
|
+
' (' +
|
|
534
|
+
device!.name +
|
|
535
|
+
') addr=' +
|
|
536
|
+
h(addr, 4) +
|
|
537
|
+
' value=' +
|
|
538
|
+
h(written, 4),
|
|
539
|
+
LOG_PCI,
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
space[addr >>> 1] = written
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
pci_write32(address: number, written: number): void {
|
|
546
|
+
dbg_assert((address & 3) === 0)
|
|
547
|
+
|
|
548
|
+
const bdf = (address >> 8) & 0xffff
|
|
549
|
+
const addr = address & 0xff
|
|
550
|
+
|
|
551
|
+
const space = this.device_spaces[bdf]
|
|
552
|
+
const device = this.devices[bdf]
|
|
553
|
+
|
|
554
|
+
if (!space) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (addr >= 0x10 && addr < 0x28) {
|
|
559
|
+
const bar_nr = (addr - 0x10) >> 2
|
|
560
|
+
const bar = device!.pci_bars[bar_nr]
|
|
561
|
+
|
|
562
|
+
dbg_log(
|
|
563
|
+
'BAR' +
|
|
564
|
+
bar_nr +
|
|
565
|
+
' exists=' +
|
|
566
|
+
(bar ? 'y' : 'n') +
|
|
567
|
+
' changed from ' +
|
|
568
|
+
h(space[addr >> 2]) +
|
|
569
|
+
' to ' +
|
|
570
|
+
h(written >>> 0) +
|
|
571
|
+
' dev=' +
|
|
572
|
+
h(bdf >> 3, 2) +
|
|
573
|
+
' (' +
|
|
574
|
+
device!.name +
|
|
575
|
+
') ',
|
|
576
|
+
LOG_PCI,
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
if (bar) {
|
|
580
|
+
dbg_assert(
|
|
581
|
+
!(bar.size & (bar.size - 1)),
|
|
582
|
+
'bar size should be power of 2',
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
const space_addr = addr >> 2
|
|
586
|
+
const type = space[space_addr] & 1
|
|
587
|
+
|
|
588
|
+
if ((written | 3 | (bar.size - 1)) === -1) // size check
|
|
589
|
+
{
|
|
590
|
+
written = ~(bar.size - 1) | type
|
|
591
|
+
|
|
592
|
+
if (type === 0) {
|
|
593
|
+
space[space_addr] = written
|
|
594
|
+
}
|
|
595
|
+
} else {
|
|
596
|
+
if (type === 0) {
|
|
597
|
+
// memory
|
|
598
|
+
const original_bar = bar.original_bar!
|
|
599
|
+
|
|
600
|
+
if ((written & ~0xf) !== (original_bar & ~0xf)) {
|
|
601
|
+
// seabios
|
|
602
|
+
dbg_log(
|
|
603
|
+
'Warning: Changing memory bar not supported, ignored',
|
|
604
|
+
LOG_PCI,
|
|
605
|
+
)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// changing isn't supported yet, reset to default
|
|
609
|
+
space[space_addr] = original_bar
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (type === 1) {
|
|
614
|
+
// io
|
|
615
|
+
dbg_assert(type === 1)
|
|
616
|
+
|
|
617
|
+
const from = space[space_addr] & ~1 & 0xffff
|
|
618
|
+
const to = written & ~1 & 0xffff
|
|
619
|
+
dbg_log(
|
|
620
|
+
'io bar changed from ' +
|
|
621
|
+
h(from >>> 0, 8) +
|
|
622
|
+
' to ' +
|
|
623
|
+
h(to >>> 0, 8) +
|
|
624
|
+
' size=' +
|
|
625
|
+
bar.size,
|
|
626
|
+
LOG_PCI,
|
|
627
|
+
)
|
|
628
|
+
this.set_io_bars(bar, from, to)
|
|
629
|
+
space[space_addr] = written | 1
|
|
630
|
+
}
|
|
631
|
+
} else {
|
|
632
|
+
space[addr >> 2] = 0
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
dbg_log(
|
|
636
|
+
'BAR effective value: ' + h(space[addr >> 2] >>> 0),
|
|
637
|
+
LOG_PCI,
|
|
638
|
+
)
|
|
639
|
+
} else if (addr === 0x30) {
|
|
640
|
+
dbg_log(
|
|
641
|
+
'PCI write rom address dev=' +
|
|
642
|
+
h(bdf >> 3, 2) +
|
|
643
|
+
' (' +
|
|
644
|
+
device!.name +
|
|
645
|
+
')' +
|
|
646
|
+
' value=' +
|
|
647
|
+
h(written >>> 0, 8),
|
|
648
|
+
LOG_PCI,
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
if (device!.pci_rom_size) {
|
|
652
|
+
if ((written | 0x7ff) === (0xffffffff | 0)) {
|
|
653
|
+
space[addr >> 2] = -device!.pci_rom_size! | 0
|
|
654
|
+
} else {
|
|
655
|
+
space[addr >> 2] = device!.pci_rom_address! | 0
|
|
656
|
+
}
|
|
657
|
+
} else {
|
|
658
|
+
space[addr >> 2] = 0
|
|
659
|
+
}
|
|
660
|
+
} else if (addr === 0x04) {
|
|
661
|
+
dbg_log(
|
|
662
|
+
'PCI write dev=' +
|
|
663
|
+
h(bdf >> 3, 2) +
|
|
664
|
+
' (' +
|
|
665
|
+
device!.name +
|
|
666
|
+
') addr=' +
|
|
667
|
+
h(addr, 4) +
|
|
668
|
+
' value=' +
|
|
669
|
+
h(written >>> 0, 8),
|
|
670
|
+
LOG_PCI,
|
|
671
|
+
)
|
|
672
|
+
} else {
|
|
673
|
+
dbg_log(
|
|
674
|
+
'PCI write dev=' +
|
|
675
|
+
h(bdf >> 3, 2) +
|
|
676
|
+
' (' +
|
|
677
|
+
device!.name +
|
|
678
|
+
') addr=' +
|
|
679
|
+
h(addr, 4) +
|
|
680
|
+
' value=' +
|
|
681
|
+
h(written >>> 0, 8),
|
|
682
|
+
LOG_PCI,
|
|
683
|
+
)
|
|
684
|
+
space[addr >>> 2] = written
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
register_device(device: PCIDevice): Int32Array {
|
|
689
|
+
dbg_assert(device.pci_id !== undefined)
|
|
690
|
+
dbg_assert(device.pci_space !== undefined)
|
|
691
|
+
dbg_assert(device.pci_bars !== undefined)
|
|
692
|
+
|
|
693
|
+
const device_id = device.pci_id
|
|
694
|
+
|
|
695
|
+
dbg_log(
|
|
696
|
+
'PCI register bdf=' + h(device_id) + ' (' + device.name + ')',
|
|
697
|
+
LOG_PCI,
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
if (this.devices[device_id]) {
|
|
701
|
+
dbg_log(
|
|
702
|
+
'warning: overwriting device ' +
|
|
703
|
+
this.devices[device_id]!.name +
|
|
704
|
+
' with ' +
|
|
705
|
+
device.name,
|
|
706
|
+
LOG_PCI,
|
|
707
|
+
)
|
|
708
|
+
}
|
|
709
|
+
dbg_assert(device.pci_space.length >= 64)
|
|
710
|
+
dbg_assert(device_id < this.devices.length)
|
|
711
|
+
|
|
712
|
+
// convert bytewise notation from lspci to double words
|
|
713
|
+
const space = new Int32Array(64)
|
|
714
|
+
space.set(new Int32Array(new Uint8Array(device.pci_space).buffer))
|
|
715
|
+
this.device_spaces[device_id] = space
|
|
716
|
+
this.devices[device_id] = device
|
|
717
|
+
|
|
718
|
+
const bar_space = space.slice(4, 10)
|
|
719
|
+
|
|
720
|
+
for (let i = 0; i < device.pci_bars.length; i++) {
|
|
721
|
+
const bar = device.pci_bars[i]
|
|
722
|
+
|
|
723
|
+
if (!bar) {
|
|
724
|
+
continue
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const bar_base = bar_space[i]
|
|
728
|
+
const type = bar_base & 1
|
|
729
|
+
dbg_log(
|
|
730
|
+
'device ' +
|
|
731
|
+
device.name +
|
|
732
|
+
' register bar of size ' +
|
|
733
|
+
bar.size +
|
|
734
|
+
' at ' +
|
|
735
|
+
h(bar_base),
|
|
736
|
+
LOG_PCI,
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
bar.original_bar = bar_base
|
|
740
|
+
bar.entries = []
|
|
741
|
+
|
|
742
|
+
if (type === 0) {
|
|
743
|
+
// memory, not needed currently
|
|
744
|
+
} else {
|
|
745
|
+
dbg_assert(type === 1)
|
|
746
|
+
const port = bar_base & ~1
|
|
747
|
+
|
|
748
|
+
for (let j = 0; j < bar.size; j++) {
|
|
749
|
+
bar.entries[j] = this.io.ports[port + j]
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
return space
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
set_io_bars(bar: PCIBar, from: number, to: number): void {
|
|
758
|
+
const count = bar.size
|
|
759
|
+
dbg_log(
|
|
760
|
+
'Move io bars: from=' +
|
|
761
|
+
h(from) +
|
|
762
|
+
' to=' +
|
|
763
|
+
h(to) +
|
|
764
|
+
' count=' +
|
|
765
|
+
count,
|
|
766
|
+
LOG_PCI,
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
const ports = this.io.ports
|
|
770
|
+
|
|
771
|
+
for (let i = 0; i < count; i++) {
|
|
772
|
+
const _old_entry = ports[from + i]
|
|
773
|
+
|
|
774
|
+
if (from + i >= 0x1000) {
|
|
775
|
+
ports[from + i] = this.io.create_empty_entry()
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const entry = bar.entries![i]
|
|
779
|
+
const empty_entry = ports[to + i]
|
|
780
|
+
dbg_assert(!!entry && !!empty_entry)
|
|
781
|
+
|
|
782
|
+
if (to + i >= 0x1000) {
|
|
783
|
+
ports[to + i] = entry
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
raise_irq(pci_id: number): void {
|
|
789
|
+
const space = this.device_spaces[pci_id]
|
|
790
|
+
dbg_assert(!!space)
|
|
791
|
+
|
|
792
|
+
const pin = ((space![0x3c >>> 2] >> 8) & 0xff) - 1
|
|
793
|
+
const device = ((pci_id >> 3) - 1) & 0xff
|
|
794
|
+
const parent_pin = (pin + device) & 3
|
|
795
|
+
const irq = this.isa_bridge_space8[0x60 + parent_pin]
|
|
796
|
+
|
|
797
|
+
//dbg_log("PCI raise irq " + h(irq) + " dev=" + h(device, 2) +
|
|
798
|
+
// " (" + this.devices[pci_id].name + ")", LOG_PCI);
|
|
799
|
+
this.cpu.device_raise_irq(irq)
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
lower_irq(pci_id: number): void {
|
|
803
|
+
const space = this.device_spaces[pci_id]
|
|
804
|
+
dbg_assert(!!space)
|
|
805
|
+
|
|
806
|
+
const pin = (space![0x3c >>> 2] >> 8) & 0xff
|
|
807
|
+
const device = (pci_id >> 3) & 0xff
|
|
808
|
+
const parent_pin = (pin + device - 2) & 3
|
|
809
|
+
const irq = this.isa_bridge_space8[0x60 + parent_pin]
|
|
810
|
+
|
|
811
|
+
//dbg_log("PCI lower irq " + h(irq) + " dev=" + h(device, 2) +
|
|
812
|
+
// " (" + this.devices[pci_id].name + ")", LOG_PCI);
|
|
813
|
+
this.cpu.device_lower_irq(irq)
|
|
814
|
+
}
|
|
815
|
+
}
|