@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.
Files changed (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. 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
+ }