@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/state.ts
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
declare let DEBUG: boolean
|
|
2
|
+
|
|
3
|
+
import { h } from './lib.js'
|
|
4
|
+
import { dbg_assert, dbg_log } from './log.js'
|
|
5
|
+
|
|
6
|
+
const STATE_VERSION = 6
|
|
7
|
+
const STATE_MAGIC = 0x86768676 | 0
|
|
8
|
+
const STATE_INDEX_MAGIC = 0
|
|
9
|
+
const STATE_INDEX_VERSION = 1
|
|
10
|
+
const STATE_INDEX_TOTAL_LEN = 2
|
|
11
|
+
const STATE_INDEX_INFO_LEN = 3
|
|
12
|
+
const STATE_INFO_BLOCK_START = 16
|
|
13
|
+
|
|
14
|
+
const ZSTD_MAGIC = 0xfd2fb528
|
|
15
|
+
|
|
16
|
+
export class StateLoadError extends Error {
|
|
17
|
+
constructor(msg: string) {
|
|
18
|
+
super(msg)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Minimal interface for the CPU fields state needs
|
|
23
|
+
interface StateCpu {
|
|
24
|
+
get_state(): any[]
|
|
25
|
+
|
|
26
|
+
set_state(state: any[]): void
|
|
27
|
+
wasm_memory: WebAssembly.Memory
|
|
28
|
+
zstd_create_ctx(len: number): number
|
|
29
|
+
zstd_get_src_ptr(ctx: number): number
|
|
30
|
+
zstd_read(ctx: number, len: number): number
|
|
31
|
+
zstd_read_free(ptr: number, len: number): void
|
|
32
|
+
zstd_free_ctx(ctx: number): void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const CONSTRUCTOR_TABLE: Record<string, any> = {
|
|
36
|
+
Map: Map,
|
|
37
|
+
Uint8Array: Uint8Array,
|
|
38
|
+
Int8Array: Int8Array,
|
|
39
|
+
Uint16Array: Uint16Array,
|
|
40
|
+
Int16Array: Int16Array,
|
|
41
|
+
Uint32Array: Uint32Array,
|
|
42
|
+
Int32Array: Int32Array,
|
|
43
|
+
Float32Array: Float32Array,
|
|
44
|
+
Float64Array: Float64Array,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function save_object(obj: any, saved_buffers: Uint8Array[]): any {
|
|
48
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
49
|
+
dbg_assert(typeof obj !== 'function')
|
|
50
|
+
return obj
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(obj)) {
|
|
54
|
+
return obj.map((x) => save_object(x, saved_buffers))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (obj instanceof Map) {
|
|
58
|
+
return {
|
|
59
|
+
__state_type__: 'Map',
|
|
60
|
+
|
|
61
|
+
args: Array.from(obj.entries()).map(([k, v]: [any, any]) => [
|
|
62
|
+
save_object(k, saved_buffers),
|
|
63
|
+
save_object(v, saved_buffers),
|
|
64
|
+
]),
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (obj.constructor === Object) {
|
|
69
|
+
console.log(obj)
|
|
70
|
+
dbg_assert(obj.constructor !== Object, 'Expected non-object')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (obj.BYTES_PER_ELEMENT) {
|
|
74
|
+
// Uint8Array, etc.
|
|
75
|
+
const buffer = new Uint8Array(
|
|
76
|
+
obj.buffer,
|
|
77
|
+
obj.byteOffset,
|
|
78
|
+
obj.length * obj.BYTES_PER_ELEMENT,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
const constructor = obj.constructor.name.replace('bound ', '')
|
|
82
|
+
|
|
83
|
+
dbg_assert(CONSTRUCTOR_TABLE[constructor])
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
__state_type__: constructor,
|
|
87
|
+
buffer_id: saved_buffers.push(buffer) - 1,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (DEBUG && !obj.get_state) {
|
|
92
|
+
console.log('Object without get_state: ', obj)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const state = obj.get_state()
|
|
96
|
+
|
|
97
|
+
const result: any[] = []
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < state.length; i++) {
|
|
100
|
+
const value = state[i]
|
|
101
|
+
|
|
102
|
+
dbg_assert(typeof value !== 'function')
|
|
103
|
+
|
|
104
|
+
result[i] = save_object(value, saved_buffers)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return result
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function restore_buffers(obj: any, buffers: ArrayBuffer[]): any {
|
|
111
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
112
|
+
dbg_assert(typeof obj !== 'function')
|
|
113
|
+
return obj
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (Array.isArray(obj)) {
|
|
117
|
+
for (let i = 0; i < obj.length; i++) {
|
|
118
|
+
obj[i] = restore_buffers(obj[i], buffers)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return obj
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const type = obj['__state_type__']
|
|
125
|
+
dbg_assert(type !== undefined)
|
|
126
|
+
|
|
127
|
+
const constructor = CONSTRUCTOR_TABLE[type]
|
|
128
|
+
dbg_assert(constructor, 'Unkown type: ' + type)
|
|
129
|
+
|
|
130
|
+
if (obj['args'] !== undefined) {
|
|
131
|
+
return new constructor(obj['args'])
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const buffer = buffers[obj['buffer_id']]
|
|
135
|
+
return new constructor(buffer)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function save_state(cpu: StateCpu): ArrayBuffer {
|
|
139
|
+
const saved_buffers: Uint8Array[] = []
|
|
140
|
+
const state = save_object(cpu, saved_buffers)
|
|
141
|
+
|
|
142
|
+
const buffer_infos: { offset: number; length: number }[] = []
|
|
143
|
+
let total_buffer_size = 0
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < saved_buffers.length; i++) {
|
|
146
|
+
const len = saved_buffers[i].byteLength
|
|
147
|
+
|
|
148
|
+
buffer_infos[i] = {
|
|
149
|
+
offset: total_buffer_size,
|
|
150
|
+
length: len,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
total_buffer_size += len
|
|
154
|
+
|
|
155
|
+
// align
|
|
156
|
+
total_buffer_size = (total_buffer_size + 3) & ~3
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const info_object = JSON.stringify({
|
|
160
|
+
buffer_infos: buffer_infos,
|
|
161
|
+
state: state,
|
|
162
|
+
})
|
|
163
|
+
const info_block = new TextEncoder().encode(info_object)
|
|
164
|
+
|
|
165
|
+
let buffer_block_start = STATE_INFO_BLOCK_START + info_block.length
|
|
166
|
+
buffer_block_start = (buffer_block_start + 3) & ~3
|
|
167
|
+
const total_size = buffer_block_start + total_buffer_size
|
|
168
|
+
|
|
169
|
+
const result = new ArrayBuffer(total_size)
|
|
170
|
+
|
|
171
|
+
const header_block = new Int32Array(result, 0, STATE_INFO_BLOCK_START / 4)
|
|
172
|
+
new Uint8Array(result, STATE_INFO_BLOCK_START, info_block.length).set(
|
|
173
|
+
info_block,
|
|
174
|
+
)
|
|
175
|
+
const buffer_block = new Uint8Array(result, buffer_block_start)
|
|
176
|
+
|
|
177
|
+
header_block[STATE_INDEX_MAGIC] = STATE_MAGIC
|
|
178
|
+
header_block[STATE_INDEX_VERSION] = STATE_VERSION
|
|
179
|
+
header_block[STATE_INDEX_TOTAL_LEN] = total_size
|
|
180
|
+
header_block[STATE_INDEX_INFO_LEN] = info_block.length
|
|
181
|
+
|
|
182
|
+
for (let i = 0; i < saved_buffers.length; i++) {
|
|
183
|
+
const buf = saved_buffers[i]
|
|
184
|
+
dbg_assert(buf.constructor === Uint8Array)
|
|
185
|
+
buffer_block.set(buf, buffer_infos[i].offset)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
dbg_log('State: json size ' + (info_block.byteLength >> 10) + 'k')
|
|
189
|
+
dbg_log(
|
|
190
|
+
'State: Total buffers size ' + (buffer_block.byteLength >> 10) + 'k',
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return result
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function restore_state(cpu: StateCpu, state: ArrayBuffer): void {
|
|
197
|
+
const state_bytes = new Uint8Array(state)
|
|
198
|
+
|
|
199
|
+
function read_state_header(
|
|
200
|
+
data: Uint8Array,
|
|
201
|
+
check_length: boolean,
|
|
202
|
+
): number {
|
|
203
|
+
const len = data.length
|
|
204
|
+
|
|
205
|
+
if (len < STATE_INFO_BLOCK_START) {
|
|
206
|
+
throw new StateLoadError('Invalid length: ' + len)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const header_block = new Int32Array(data.buffer, data.byteOffset, 4)
|
|
210
|
+
|
|
211
|
+
if (header_block[STATE_INDEX_MAGIC] !== STATE_MAGIC) {
|
|
212
|
+
throw new StateLoadError(
|
|
213
|
+
'Invalid header: ' + h(header_block[STATE_INDEX_MAGIC] >>> 0),
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (header_block[STATE_INDEX_VERSION] !== STATE_VERSION) {
|
|
218
|
+
throw new StateLoadError(
|
|
219
|
+
'Version mismatch: dump=' +
|
|
220
|
+
header_block[STATE_INDEX_VERSION] +
|
|
221
|
+
' we=' +
|
|
222
|
+
STATE_VERSION,
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (check_length && header_block[STATE_INDEX_TOTAL_LEN] !== len) {
|
|
227
|
+
throw new StateLoadError(
|
|
228
|
+
"Length doesn't match header: " +
|
|
229
|
+
'real=' +
|
|
230
|
+
len +
|
|
231
|
+
' header=' +
|
|
232
|
+
header_block[STATE_INDEX_TOTAL_LEN],
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return header_block[STATE_INDEX_INFO_LEN]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function read_info_block(info_block_buffer: Uint8Array) {
|
|
240
|
+
const info_block = new TextDecoder().decode(info_block_buffer)
|
|
241
|
+
return JSON.parse(info_block)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (new Uint32Array(state_bytes.buffer, 0, 1)[0] === ZSTD_MAGIC) {
|
|
245
|
+
const ctx = cpu.zstd_create_ctx(state_bytes.length)
|
|
246
|
+
|
|
247
|
+
new Uint8Array(
|
|
248
|
+
cpu.wasm_memory.buffer,
|
|
249
|
+
cpu.zstd_get_src_ptr(ctx) >>> 0,
|
|
250
|
+
state_bytes.length,
|
|
251
|
+
).set(state_bytes)
|
|
252
|
+
|
|
253
|
+
let ptr = cpu.zstd_read(ctx, 16)
|
|
254
|
+
const header_block = new Uint8Array(
|
|
255
|
+
cpu.wasm_memory.buffer,
|
|
256
|
+
ptr >>> 0,
|
|
257
|
+
16,
|
|
258
|
+
)
|
|
259
|
+
const info_block_len = read_state_header(header_block, false)
|
|
260
|
+
cpu.zstd_read_free(ptr, 16)
|
|
261
|
+
|
|
262
|
+
ptr = cpu.zstd_read(ctx, info_block_len)
|
|
263
|
+
const info_block_buffer = new Uint8Array(
|
|
264
|
+
cpu.wasm_memory.buffer,
|
|
265
|
+
ptr >>> 0,
|
|
266
|
+
info_block_len,
|
|
267
|
+
)
|
|
268
|
+
const info_block_obj = read_info_block(info_block_buffer)
|
|
269
|
+
cpu.zstd_read_free(ptr, info_block_len)
|
|
270
|
+
|
|
271
|
+
let state_object = info_block_obj['state']
|
|
272
|
+
const buffer_infos = info_block_obj['buffer_infos']
|
|
273
|
+
const buffers: ArrayBuffer[] = []
|
|
274
|
+
|
|
275
|
+
let position = STATE_INFO_BLOCK_START + info_block_len
|
|
276
|
+
|
|
277
|
+
for (const buffer_info of buffer_infos) {
|
|
278
|
+
const front_padding = ((position + 3) & ~3) - position
|
|
279
|
+
const CHUNK_SIZE = 1 * 1024 * 1024
|
|
280
|
+
|
|
281
|
+
if (buffer_info.length > CHUNK_SIZE) {
|
|
282
|
+
const chunk_ptr = cpu.zstd_read(ctx, front_padding) >>> 0
|
|
283
|
+
cpu.zstd_read_free(chunk_ptr, front_padding)
|
|
284
|
+
|
|
285
|
+
const buffer = new Uint8Array(buffer_info.length)
|
|
286
|
+
buffers.push(buffer.buffer)
|
|
287
|
+
|
|
288
|
+
let have = 0
|
|
289
|
+
while (have < buffer_info.length) {
|
|
290
|
+
const remaining = buffer_info.length - have
|
|
291
|
+
dbg_assert(remaining >= 0)
|
|
292
|
+
const to_read = Math.min(remaining, CHUNK_SIZE)
|
|
293
|
+
|
|
294
|
+
const read_ptr = cpu.zstd_read(ctx, to_read)
|
|
295
|
+
buffer.set(
|
|
296
|
+
new Uint8Array(
|
|
297
|
+
cpu.wasm_memory.buffer,
|
|
298
|
+
read_ptr >>> 0,
|
|
299
|
+
to_read,
|
|
300
|
+
),
|
|
301
|
+
have,
|
|
302
|
+
)
|
|
303
|
+
cpu.zstd_read_free(read_ptr, to_read)
|
|
304
|
+
|
|
305
|
+
have += to_read
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
const chunk_ptr = cpu.zstd_read(
|
|
309
|
+
ctx,
|
|
310
|
+
front_padding + buffer_info.length,
|
|
311
|
+
)
|
|
312
|
+
const offset = (chunk_ptr >>> 0) + front_padding
|
|
313
|
+
buffers.push(
|
|
314
|
+
cpu.wasm_memory.buffer.slice(
|
|
315
|
+
offset,
|
|
316
|
+
offset + buffer_info.length,
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
cpu.zstd_read_free(
|
|
320
|
+
chunk_ptr,
|
|
321
|
+
front_padding + buffer_info.length,
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
position += front_padding + buffer_info.length
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
state_object = restore_buffers(state_object, buffers)
|
|
329
|
+
cpu.set_state(state_object)
|
|
330
|
+
|
|
331
|
+
cpu.zstd_free_ctx(ctx)
|
|
332
|
+
} else {
|
|
333
|
+
const info_block_len = read_state_header(state_bytes, true)
|
|
334
|
+
|
|
335
|
+
if (info_block_len < 0 || info_block_len + 12 >= state_bytes.length) {
|
|
336
|
+
throw new StateLoadError(
|
|
337
|
+
'Invalid info block length: ' + info_block_len,
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const info_block_buffer = state_bytes.subarray(
|
|
342
|
+
STATE_INFO_BLOCK_START,
|
|
343
|
+
STATE_INFO_BLOCK_START + info_block_len,
|
|
344
|
+
)
|
|
345
|
+
const info_block_obj = read_info_block(info_block_buffer)
|
|
346
|
+
let state_object = info_block_obj['state']
|
|
347
|
+
const buffer_infos = info_block_obj['buffer_infos']
|
|
348
|
+
let buffer_block_start = STATE_INFO_BLOCK_START + info_block_len
|
|
349
|
+
buffer_block_start = (buffer_block_start + 3) & ~3
|
|
350
|
+
|
|
351
|
+
const buffers = buffer_infos.map((buffer_info: any) => {
|
|
352
|
+
const offset = buffer_block_start + buffer_info.offset
|
|
353
|
+
return state_bytes.buffer.slice(offset, offset + buffer_info.length)
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
state_object = restore_buffers(state_object, buffers)
|
|
357
|
+
cpu.set_state(state_object)
|
|
358
|
+
}
|
|
359
|
+
}
|