@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
@@ -0,0 +1,332 @@
1
+ import { LOG_NET } from '../const.js'
2
+ import { dbg_log } from '../log.js'
3
+
4
+ import {
5
+ create_eth_encoder_buf,
6
+ handle_fake_networking,
7
+ TCPConnection,
8
+ } from './fake_network.js'
9
+
10
+ import type {
11
+ EthEncoderBuf,
12
+ NetworkAdapterLike,
13
+ PacketSpec,
14
+ } from './fake_network.js'
15
+
16
+ import { BusConnector } from '../bus.js'
17
+
18
+ interface WispNetworkConfig {
19
+ id?: number
20
+ router_mac?: string
21
+ router_ip?: string
22
+ vm_ip?: string
23
+ masquerade?: boolean
24
+ dns_method?: string
25
+ doh_server?: string
26
+ mtu?: number
27
+ }
28
+
29
+ interface WispConnection {
30
+ data_callback: (data: Uint8Array) => void
31
+ close_callback: (reason: number) => void
32
+ congestion: number
33
+ congested?: boolean
34
+ }
35
+
36
+ interface WispFrameConnect {
37
+ type: 'CONNECT'
38
+ stream_id: number
39
+ hostname: string
40
+ port: number
41
+ data_callback: (data: Uint8Array) => void
42
+ close_callback: (reason: number) => void
43
+ }
44
+
45
+ interface WispFrameData {
46
+ type: 'DATA'
47
+ stream_id: number
48
+ data: Uint8Array
49
+ }
50
+
51
+ interface WispFrameClose {
52
+ type: 'CLOSE'
53
+ stream_id: number
54
+ reason: number
55
+ }
56
+
57
+ type WispFrame = WispFrameConnect | WispFrameData | WispFrameClose
58
+
59
+ interface CongestedPacket {
60
+ data: Uint8Array
61
+ type: string
62
+ }
63
+
64
+ export class WispNetworkAdapter implements NetworkAdapterLike {
65
+ wispws: WebSocket | null
66
+ last_stream: number
67
+ connections: Record<number, WispConnection>
68
+ congested_buffer: CongestedPacket[]
69
+ bus: BusConnector
70
+ id: number
71
+ router_mac: Uint8Array
72
+ router_ip: Uint8Array
73
+ vm_ip: Uint8Array
74
+ masquerade: boolean
75
+ vm_mac: Uint8Array
76
+ dns_method: string
77
+ doh_server: string | undefined
78
+ tcp_conn: Record<string, TCPConnection>
79
+ mtu: number | undefined
80
+ eth_encoder_buf: EthEncoderBuf
81
+
82
+ constructor(
83
+ wisp_url: string,
84
+ bus: BusConnector,
85
+ config?: WispNetworkConfig,
86
+ ) {
87
+ this.wispws = null
88
+ this.register_ws(wisp_url)
89
+ this.last_stream = 1
90
+ this.connections = {
91
+ 0: {
92
+ congestion: 0,
93
+ data_callback: () => {},
94
+ close_callback: () => {},
95
+ },
96
+ }
97
+ this.congested_buffer = []
98
+
99
+ config = config || {}
100
+ this.bus = bus
101
+ this.id = config.id || 0
102
+ this.router_mac = new Uint8Array(
103
+ (config.router_mac || '52:54:0:1:2:3').split(':').map(function (x) {
104
+ return parseInt(x, 16)
105
+ }),
106
+ )
107
+ this.router_ip = new Uint8Array(
108
+ (config.router_ip || '192.168.86.1').split('.').map(function (x) {
109
+ return parseInt(x, 10)
110
+ }),
111
+ )
112
+ this.vm_ip = new Uint8Array(
113
+ (config.vm_ip || '192.168.86.100').split('.').map(function (x) {
114
+ return parseInt(x, 10)
115
+ }),
116
+ )
117
+ this.masquerade = config.masquerade === undefined || !!config.masquerade
118
+ this.vm_mac = new Uint8Array(6)
119
+ this.dns_method = config.dns_method || 'doh'
120
+ this.doh_server = config.doh_server
121
+ this.tcp_conn = {}
122
+ this.mtu = config.mtu
123
+ this.eth_encoder_buf = create_eth_encoder_buf(this.mtu)
124
+
125
+ this.bus.register(
126
+ 'net' + this.id + '-mac',
127
+ function (this: WispNetworkAdapter, mac: string) {
128
+ this.vm_mac = new Uint8Array(
129
+ mac.split(':').map(function (x) {
130
+ return parseInt(x, 16)
131
+ }),
132
+ )
133
+ },
134
+ this,
135
+ )
136
+ this.bus.register(
137
+ 'net' + this.id + '-send',
138
+ function (this: WispNetworkAdapter, data: Uint8Array) {
139
+ this.send(data)
140
+ },
141
+ this,
142
+ )
143
+ }
144
+
145
+ register_ws(wisp_url: string): void {
146
+ this.wispws = new WebSocket(
147
+ wisp_url.replace('wisp://', 'ws://').replace('wisps://', 'wss://'),
148
+ )
149
+ this.wispws.binaryType = 'arraybuffer'
150
+ this.wispws.onmessage = (event: MessageEvent) => {
151
+ this.process_incoming_wisp_frame(new Uint8Array(event.data))
152
+ }
153
+ this.wispws.onclose = () => {
154
+ setTimeout(() => {
155
+ this.register_ws(wisp_url)
156
+ }, 10000) // wait 10s before reconnecting
157
+ }
158
+ }
159
+
160
+ send_packet(data: Uint8Array, type: string, stream_id: number): void {
161
+ if (this.connections[stream_id]) {
162
+ if (this.connections[stream_id].congestion > 0) {
163
+ if (type === 'DATA') {
164
+ this.connections[stream_id].congestion--
165
+ }
166
+ this.wispws!.send(new Uint8Array(data))
167
+ } else {
168
+ this.connections[stream_id].congested = true
169
+ this.congested_buffer.push({ data: data, type: type })
170
+ }
171
+ }
172
+ }
173
+
174
+ process_incoming_wisp_frame(frame: Uint8Array): void {
175
+ const view = new DataView(frame.buffer)
176
+ const stream_id = view.getUint32(1, true)
177
+ switch (frame[0]) {
178
+ case 1: // CONNECT
179
+ // The server should never send this actually
180
+ dbg_log('Server sent client-only packet CONNECT', LOG_NET)
181
+ break
182
+ case 2: // DATA
183
+ if (this.connections[stream_id])
184
+ this.connections[stream_id].data_callback(frame.slice(5))
185
+ else
186
+ throw new Error(
187
+ 'Got a DATA packet but stream not registered. ID: ' +
188
+ stream_id,
189
+ )
190
+ break
191
+ case 3: // CONTINUE
192
+ if (this.connections[stream_id]) {
193
+ this.connections[stream_id].congestion = view.getUint32(
194
+ 5,
195
+ true,
196
+ )
197
+ }
198
+
199
+ if (this.connections[stream_id].congested) {
200
+ const buffer = this.congested_buffer.slice(0)
201
+ this.congested_buffer.length = 0
202
+ this.connections[stream_id].congested = false
203
+ for (const packet of buffer) {
204
+ this.send_packet(packet.data, packet.type, stream_id)
205
+ }
206
+ }
207
+ break
208
+ case 4: // CLOSE
209
+ if (this.connections[stream_id])
210
+ this.connections[stream_id].close_callback(view.getUint8(5))
211
+ delete this.connections[stream_id]
212
+ break
213
+ case 5: // PROTOEXT
214
+ dbg_log('got a wisp V2 upgrade request, ignoring', LOG_NET)
215
+ // Not responding, this is wisp v1 client not wisp v2;
216
+ break
217
+ default:
218
+ dbg_log(
219
+ 'Wisp server returned unknown packet: ' + frame[0],
220
+ LOG_NET,
221
+ )
222
+ }
223
+ }
224
+
225
+ send_wisp_frame(frame_obj: WispFrame): void {
226
+ let full_packet: Uint8Array
227
+ let view: DataView
228
+ switch (frame_obj.type) {
229
+ case 'CONNECT': {
230
+ const hostname_buffer = new TextEncoder().encode(
231
+ frame_obj.hostname,
232
+ )
233
+ full_packet = new Uint8Array(5 + 1 + 2 + hostname_buffer.length)
234
+ view = new DataView(full_packet.buffer)
235
+ view.setUint8(0, 0x01) // TYPE
236
+ view.setUint32(1, frame_obj.stream_id, true) // Stream ID
237
+ view.setUint8(5, 0x01) // TCP
238
+ view.setUint16(6, frame_obj.port, true) // PORT
239
+ full_packet.set(hostname_buffer, 8) // hostname
240
+
241
+ // Setting callbacks
242
+ this.connections[frame_obj.stream_id] = {
243
+ data_callback: frame_obj.data_callback,
244
+ close_callback: frame_obj.close_callback,
245
+ congestion: this.connections[0].congestion,
246
+ }
247
+ break
248
+ }
249
+ case 'DATA':
250
+ full_packet = new Uint8Array(5 + frame_obj.data.length)
251
+ view = new DataView(full_packet.buffer)
252
+ view.setUint8(0, 0x02) // TYPE
253
+ view.setUint32(1, frame_obj.stream_id, true) // Stream ID
254
+ full_packet.set(frame_obj.data, 5) // Actual data
255
+ break
256
+ case 'CLOSE':
257
+ full_packet = new Uint8Array(5 + 1)
258
+ view = new DataView(full_packet.buffer)
259
+ view.setUint8(0, 0x04) // TYPE
260
+ view.setUint32(1, frame_obj.stream_id, true) // Stream ID
261
+ view.setUint8(5, frame_obj.reason) // Packet size
262
+ break
263
+ default:
264
+ dbg_log(
265
+ 'Client tried to send unknown packet: ' +
266
+ (frame_obj as WispFrame).type,
267
+ LOG_NET,
268
+ )
269
+ return
270
+ }
271
+ this.send_packet(full_packet, frame_obj.type, frame_obj.stream_id)
272
+ }
273
+
274
+ destroy(): void {
275
+ if (this.wispws) {
276
+ this.wispws.onmessage = null
277
+ this.wispws.onclose = null
278
+ this.wispws.close()
279
+ this.wispws = null
280
+ }
281
+ }
282
+
283
+ on_tcp_connection(conn: TCPConnection, packet: PacketSpec): boolean {
284
+ conn.stream_id = this.last_stream++
285
+
286
+ conn.on('data', (data: Uint8Array) => {
287
+ if (data.length !== 0) {
288
+ this.send_wisp_frame({
289
+ type: 'DATA',
290
+ stream_id: conn.stream_id,
291
+ data: data,
292
+ })
293
+ }
294
+ })
295
+
296
+ conn.on_close = () => {
297
+ this.send_wisp_frame({
298
+ type: 'CLOSE',
299
+ stream_id: conn.stream_id,
300
+ reason: 0x02, // 0x02: Voluntary stream closure
301
+ })
302
+ }
303
+
304
+ // WISP doesn't implement shutdown, use close as workaround
305
+ conn.on_shutdown = conn.on_close
306
+
307
+ this.send_wisp_frame({
308
+ type: 'CONNECT',
309
+ stream_id: conn.stream_id,
310
+ hostname: packet.ipv4!.dest.join('.'),
311
+ port: conn.sport,
312
+ data_callback: (data: Uint8Array) => {
313
+ conn.write(data)
314
+ },
315
+ close_callback: (_data: number) => {
316
+ conn.close()
317
+ },
318
+ })
319
+
320
+ conn.accept()
321
+ return true
322
+ }
323
+
324
+ send(data: Uint8Array): void {
325
+ // TODO: forward UDP traffic to WISP server once this WISP client supports UDP
326
+ handle_fake_networking(data, this)
327
+ }
328
+
329
+ receive(data: Uint8Array): void {
330
+ this.bus.send('net' + this.id + '-receive', new Uint8Array(data))
331
+ }
332
+ }
@@ -0,0 +1,64 @@
1
+ import { dbg_assert } from '../log.js'
2
+
3
+ interface WorkerBusListener {
4
+ fn: (...args: any[]) => any
5
+ this_value: unknown
6
+ }
7
+
8
+ /**
9
+ * Connector bridges postMessage to BusConnector.
10
+ */
11
+ export class Connector {
12
+ listeners: Record<string, WorkerBusListener[]>
13
+ pair: Worker | MessagePort
14
+
15
+ constructor(pair: Worker | MessagePort) {
16
+ this.listeners = {}
17
+ this.pair = pair
18
+
19
+ pair.addEventListener(
20
+ 'message',
21
+ ((e: Event) => {
22
+ const data = (e as MessageEvent).data
23
+ const listeners = this.listeners[data[0]]
24
+
25
+ for (let i = 0; i < listeners.length; i++) {
26
+ const listener = listeners[i]
27
+ listener.fn.call(listener.this_value, data[1])
28
+ }
29
+ }) satisfies EventListener,
30
+ false,
31
+ )
32
+ }
33
+
34
+ register(
35
+ name: string,
36
+ fn: (...args: any[]) => any,
37
+ this_value: unknown,
38
+ ): void {
39
+ let listeners = this.listeners[name]
40
+
41
+ if (listeners === undefined) {
42
+ listeners = this.listeners[name] = []
43
+ }
44
+
45
+ listeners.push({
46
+ fn: fn,
47
+ this_value: this_value,
48
+ })
49
+ }
50
+
51
+ send(name: string, value?: unknown, transfer_list?: Transferable[]): void {
52
+ dbg_assert(arguments.length >= 1)
53
+
54
+ if (!this.pair) {
55
+ return
56
+ }
57
+
58
+ this.pair.postMessage([name, value], transfer_list || [])
59
+ }
60
+ }
61
+
62
+ export const init = function (worker: Worker | MessagePort): Connector {
63
+ return new Connector(worker)
64
+ }