@aptre/v86 0.5.0 → 0.6.1
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/dist/v86.browser.js +1113 -93
- package/dist/v86.browser.js.map +4 -4
- package/dist/v86.js +1112 -93
- package/dist/v86.js.map +4 -4
- package/lib/9p.ts +4 -4
- package/lib/filesystem.ts +1 -1
- package/package.json +7 -7
- package/src/browser/starter.ts +53 -23
- package/src/const.ts +2 -0
- package/src/cpu.ts +128 -98
- package/src/pci.ts +8 -3
- package/src/ps2.ts +2 -2
- package/src/virtio.ts +10 -18
- package/src/virtio_mem.ts +349 -0
- package/src/virtio_v86fs.ts +873 -0
- package/src/rust/gen/analyzer.rs +0 -3807
- package/src/rust/gen/analyzer0f.rs +0 -3992
- package/src/rust/gen/interpreter.rs +0 -4447
- package/src/rust/gen/interpreter0f.rs +0 -5404
- package/src/rust/gen/jit.rs +0 -5080
- package/src/rust/gen/jit0f.rs +0 -5547
package/lib/9p.ts
CHANGED
|
@@ -311,7 +311,7 @@ export class Virtio9p {
|
|
|
311
311
|
|
|
312
312
|
const state = { offset: 0 }
|
|
313
313
|
const header = marshall.Unmarshall(['w', 'b', 'h'], buffer, state)
|
|
314
|
-
let size
|
|
314
|
+
let size
|
|
315
315
|
const id = header[1]
|
|
316
316
|
const tag = header[2]
|
|
317
317
|
|
|
@@ -382,7 +382,7 @@ export class Virtio9p {
|
|
|
382
382
|
)
|
|
383
383
|
|
|
384
384
|
if (ret < 0) {
|
|
385
|
-
let error_message
|
|
385
|
+
let error_message: string
|
|
386
386
|
if (ret === -EPERM)
|
|
387
387
|
error_message = 'Operation not permitted'
|
|
388
388
|
else {
|
|
@@ -984,7 +984,7 @@ export class Virtio9p {
|
|
|
984
984
|
newname,
|
|
985
985
|
)
|
|
986
986
|
if (ret < 0) {
|
|
987
|
-
let error_message
|
|
987
|
+
let error_message: string
|
|
988
988
|
if (ret === -ENOENT)
|
|
989
989
|
error_message = 'No such file or directory'
|
|
990
990
|
else if (ret === -EPERM)
|
|
@@ -1040,7 +1040,7 @@ export class Virtio9p {
|
|
|
1040
1040
|
}
|
|
1041
1041
|
const ret = this.fs.Unlink(this.fids[dirfd].inodeid, name)
|
|
1042
1042
|
if (ret < 0) {
|
|
1043
|
-
let error_message
|
|
1043
|
+
let error_message: string
|
|
1044
1044
|
if (ret === -ENOTEMPTY)
|
|
1045
1045
|
error_message = 'Directory not empty'
|
|
1046
1046
|
else if (ret === -EPERM)
|
package/lib/filesystem.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aptre/v86",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "BSD-2-Clause",
|
|
5
5
|
"description": "x86 PC emulator and x86-to-wasm JIT, running in the browser",
|
|
6
6
|
"homepage": "https://github.com/aperturerobotics/v86",
|
|
@@ -56,20 +56,20 @@
|
|
|
56
56
|
"./{src,lib,gen,tests}/**/*.{ts,js}": "prettier --config .prettierrc.yaml --write"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@eslint/js": "^
|
|
59
|
+
"@eslint/js": "^10.0.0",
|
|
60
60
|
"@types/node": "^25.5.0",
|
|
61
61
|
"@typescript/native-preview": "^7.0.0-dev.20250601",
|
|
62
|
-
"esbuild": "^0.
|
|
63
|
-
"eslint": "^
|
|
62
|
+
"esbuild": "^0.27.0",
|
|
63
|
+
"eslint": "^10.0.0",
|
|
64
64
|
"eslint-config-prettier": "^10.1.5",
|
|
65
65
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
66
|
-
"globals": "^
|
|
66
|
+
"globals": "^17.0.0",
|
|
67
67
|
"husky": "^9.1.7",
|
|
68
68
|
"lint-staged": "^16.0.0",
|
|
69
69
|
"prettier": "^3.5.3",
|
|
70
70
|
"rimraf": "^6.0.1",
|
|
71
|
-
"typescript": "^
|
|
71
|
+
"typescript": "^6.0.0",
|
|
72
72
|
"typescript-eslint": "^8.32.1",
|
|
73
|
-
"vitest": "^
|
|
73
|
+
"vitest": "^4.0.0"
|
|
74
74
|
}
|
|
75
75
|
}
|
package/src/browser/starter.ts
CHANGED
|
@@ -45,21 +45,11 @@ type FileDescriptor = any
|
|
|
45
45
|
|
|
46
46
|
type AutoStep = any
|
|
47
47
|
|
|
48
|
-
class
|
|
49
|
-
message: string
|
|
48
|
+
class FileNotFoundError extends Error {
|
|
50
49
|
constructor(message?: string) {
|
|
51
|
-
|
|
50
|
+
super(message || 'File not found')
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
|
-
FileExistsError.prototype = Error.prototype
|
|
55
|
-
|
|
56
|
-
class FileNotFoundError {
|
|
57
|
-
message: string
|
|
58
|
-
constructor(message?: string) {
|
|
59
|
-
this.message = message || 'File not found'
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
FileNotFoundError.prototype = Error.prototype
|
|
63
53
|
|
|
64
54
|
/**
|
|
65
55
|
* Constructor for emulator instances.
|
|
@@ -115,14 +105,31 @@ export class V86 {
|
|
|
115
105
|
|
|
116
106
|
let cpu: any
|
|
117
107
|
|
|
118
|
-
|
|
108
|
+
// Reserve VA upfront so memory.grow() is fast (no realloc+copy).
|
|
109
|
+
// Without maximum, engines must reallocate on every grow which
|
|
110
|
+
// is expensive and can OOM for large guest memories.
|
|
111
|
+
const memory_size = options.memory_size || 64 * 1024 * 1024
|
|
112
|
+
const vga_memory_size = options.vga_memory_size || 8 * 1024 * 1024
|
|
113
|
+
const memory_max =
|
|
114
|
+
options.memory_max || (memory_size + vga_memory_size) * 4
|
|
115
|
+
const WASM_PAGE_SIZE = 65536
|
|
116
|
+
const wasm_initial_pages = 256
|
|
117
|
+
const wasm_max_pages = Math.max(
|
|
118
|
+
wasm_initial_pages,
|
|
119
|
+
Math.min(Math.ceil(memory_max / WASM_PAGE_SIZE), 65536),
|
|
120
|
+
)
|
|
121
|
+
const wasm_memory = new WebAssembly.Memory({
|
|
122
|
+
initial: wasm_initial_pages,
|
|
123
|
+
maximum: wasm_max_pages,
|
|
124
|
+
})
|
|
119
125
|
|
|
120
126
|
const wasm_table = new WebAssembly.Table({
|
|
121
127
|
element: 'anyfunc',
|
|
122
128
|
initial: WASM_TABLE_SIZE + WASM_TABLE_OFFSET,
|
|
123
129
|
})
|
|
124
130
|
|
|
125
|
-
const wasm_shared_funcs = {
|
|
131
|
+
const wasm_shared_funcs: Record<string, any> = {
|
|
132
|
+
memory: wasm_memory,
|
|
126
133
|
cpu_exception_hook: (n: number) => this.cpu_exception_hook(n),
|
|
127
134
|
|
|
128
135
|
run_hardware_timers: function (a: any, t: any) {
|
|
@@ -231,8 +238,6 @@ export class V86 {
|
|
|
231
238
|
|
|
232
239
|
if (!wasm_fn) {
|
|
233
240
|
wasm_fn = (env: any) => {
|
|
234
|
-
/* global __dirname */
|
|
235
|
-
|
|
236
241
|
return new Promise((resolve) => {
|
|
237
242
|
let v86_bin = DEBUG ? 'v86-debug.wasm' : 'v86.wasm'
|
|
238
243
|
let v86_bin_fallback = 'v86-fallback.wasm'
|
|
@@ -243,12 +248,11 @@ export class V86 {
|
|
|
243
248
|
'v86.wasm',
|
|
244
249
|
'v86-fallback.wasm',
|
|
245
250
|
)
|
|
246
|
-
} else if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
v86_bin_fallback = __dirname + '/' + v86_bin_fallback
|
|
251
|
+
} else if (typeof window === 'undefined') {
|
|
252
|
+
// Node/Bun: resolve WASM relative to project root build/
|
|
253
|
+
const root = new URL('../../', import.meta.url).pathname
|
|
254
|
+
v86_bin = root + 'build/' + v86_bin
|
|
255
|
+
v86_bin_fallback = root + 'build/' + v86_bin_fallback
|
|
252
256
|
} else {
|
|
253
257
|
v86_bin = 'build/' + v86_bin
|
|
254
258
|
v86_bin_fallback = 'build/' + v86_bin_fallback
|
|
@@ -293,12 +297,12 @@ export class V86 {
|
|
|
293
297
|
}
|
|
294
298
|
|
|
295
299
|
wasm_fn({ env: wasm_shared_funcs }).then((exports: WasmExports) => {
|
|
296
|
-
wasm_memory = exports.memory
|
|
297
300
|
exports['rust_init']()
|
|
298
301
|
|
|
299
302
|
const emulator = (this.v86 = new v86(this.emulator_bus, {
|
|
300
303
|
exports,
|
|
301
304
|
wasm_table,
|
|
305
|
+
wasm_memory,
|
|
302
306
|
}))
|
|
303
307
|
cpu = emulator.cpu
|
|
304
308
|
|
|
@@ -356,7 +360,9 @@ export class V86 {
|
|
|
356
360
|
settings.mac_address_translation = options.mac_address_translation
|
|
357
361
|
settings.cpuid_level = options.cpuid_level
|
|
358
362
|
settings.virtio_balloon = options.virtio_balloon
|
|
363
|
+
settings.virtio_mem = options.virtio_mem
|
|
359
364
|
settings.virtio_console = !!options.virtio_console
|
|
365
|
+
settings.virtio_v86fs = !!options.virtio_v86fs
|
|
360
366
|
|
|
361
367
|
const relay_url =
|
|
362
368
|
options.network_relay_url ||
|
|
@@ -967,6 +973,30 @@ export class V86 {
|
|
|
967
973
|
this.v86.run()
|
|
968
974
|
}
|
|
969
975
|
|
|
976
|
+
/**
|
|
977
|
+
* Grow guest memory to the specified size in bytes. Stops the VM,
|
|
978
|
+
* grows WASM linear memory, updates memory_size, clears the TLB,
|
|
979
|
+
* and resumes execution.
|
|
980
|
+
*/
|
|
981
|
+
async growMemory(newSizeBytes: number): Promise<void> {
|
|
982
|
+
const cpu = this.v86.cpu
|
|
983
|
+
if (newSizeBytes <= cpu.memory_size[0]) {
|
|
984
|
+
return
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const wasRunning = this.cpu_is_running
|
|
988
|
+
if (wasRunning) {
|
|
989
|
+
await this.stop()
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
cpu.resize_memory(newSizeBytes)
|
|
993
|
+
cpu.full_clear_tlb()
|
|
994
|
+
|
|
995
|
+
if (wasRunning) {
|
|
996
|
+
await this.run()
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
970
1000
|
/**
|
|
971
1001
|
* Stop emulation. Do nothing if emulator is not running. Can be asynchronous.
|
|
972
1002
|
*/
|
package/src/const.ts
CHANGED
package/src/cpu.ts
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
FLAG_DIRECTION,
|
|
47
47
|
FLAG_OVERFLOW,
|
|
48
48
|
FLAG_PARITY,
|
|
49
|
+
WASM_PAGE_SIZE,
|
|
49
50
|
} from './const.js'
|
|
50
51
|
import { h, view, pads, Bitmap, dump_file } from './lib.js'
|
|
51
52
|
import { dbg_assert, dbg_log } from './log.js'
|
|
@@ -67,6 +68,8 @@ import { IDEController } from './ide.js'
|
|
|
67
68
|
import { VirtioNet } from './virtio_net.js'
|
|
68
69
|
import { VGAScreen } from './vga.js'
|
|
69
70
|
import { VirtioBalloon } from './virtio_balloon.js'
|
|
71
|
+
import { VirtioMem } from './virtio_mem.js'
|
|
72
|
+
import { VirtioV86FS } from './virtio_v86fs.js'
|
|
70
73
|
import { Virtio9p, Virtio9pHandler, Virtio9pProxy } from '../lib/9p.js'
|
|
71
74
|
|
|
72
75
|
import { load_kernel } from './kernel.js'
|
|
@@ -129,6 +132,8 @@ interface CPUDevices {
|
|
|
129
132
|
virtio_console: VirtioConsole
|
|
130
133
|
virtio_net: VirtioNet
|
|
131
134
|
virtio_balloon: VirtioBalloon
|
|
135
|
+
virtio_mem: VirtioMem
|
|
136
|
+
virtio_v86fs: VirtioV86FS
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
interface OptionRom {
|
|
@@ -139,6 +144,7 @@ interface OptionRom {
|
|
|
139
144
|
interface WasmModule {
|
|
140
145
|
exports: Record<string, any>
|
|
141
146
|
wasm_table: WebAssembly.Table
|
|
147
|
+
wasm_memory: WebAssembly.Memory
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
export class CPU {
|
|
@@ -149,6 +155,7 @@ export class CPU {
|
|
|
149
155
|
memory_size!: Int32Array
|
|
150
156
|
|
|
151
157
|
mem8: Uint8Array
|
|
158
|
+
mem8_offset: number = 0
|
|
152
159
|
mem32s: Int32Array
|
|
153
160
|
|
|
154
161
|
segment_is_null!: Uint8Array
|
|
@@ -268,7 +275,6 @@ export class CPU {
|
|
|
268
275
|
get_eflags!: () => number
|
|
269
276
|
handle_irqs!: () => void
|
|
270
277
|
main_loop!: () => number
|
|
271
|
-
reboot_internal!: () => void
|
|
272
278
|
set_jit_config!: (a: number, b: number) => void
|
|
273
279
|
|
|
274
280
|
read8!: (addr: number) => number
|
|
@@ -338,153 +344,115 @@ export class CPU {
|
|
|
338
344
|
this.name = 'cpu'
|
|
339
345
|
this.stop_idling = stop_idling
|
|
340
346
|
this.wm = wm
|
|
347
|
+
this.wasm_memory = wm.wasm_memory
|
|
341
348
|
this.wasm_patch()
|
|
342
349
|
this.create_jit_imports()
|
|
343
350
|
|
|
344
|
-
|
|
351
|
+
this.mem8 = new Uint8Array(0)
|
|
352
|
+
this.mem32s = new Int32Array(this.mem8.buffer)
|
|
345
353
|
|
|
346
|
-
this.
|
|
354
|
+
this.rebuild_wasm_views()
|
|
347
355
|
|
|
348
|
-
|
|
356
|
+
// @ts-expect-error Devices are populated during init()
|
|
357
|
+
this.devices = {}
|
|
349
358
|
|
|
350
|
-
|
|
351
|
-
this.
|
|
359
|
+
// managed in io.js
|
|
360
|
+
this.memory_map_read8 = []
|
|
361
|
+
this.memory_map_write8 = []
|
|
362
|
+
this.memory_map_read32 = []
|
|
363
|
+
this.memory_map_write32 = []
|
|
352
364
|
|
|
365
|
+
this.bios = {
|
|
366
|
+
main: null,
|
|
367
|
+
vga: null,
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
this.fpu_stack_empty[0] = 0xff
|
|
371
|
+
this.fpu_stack_ptr[0] = 0
|
|
372
|
+
|
|
373
|
+
this.fpu_control_word[0] = 0x37f
|
|
374
|
+
this.fpu_status_word[0] = 0
|
|
375
|
+
this.fpu_ip[0] = 0
|
|
376
|
+
this.fpu_ip_selector[0] = 0
|
|
377
|
+
this.fpu_opcode[0] = 0
|
|
378
|
+
this.fpu_dp[0] = 0
|
|
379
|
+
this.fpu_dp_selector[0] = 0
|
|
380
|
+
|
|
381
|
+
this.fw_value = []
|
|
382
|
+
this.fw_pointer = 0
|
|
383
|
+
this.option_roms = []
|
|
384
|
+
|
|
385
|
+
this.io = undefined!
|
|
386
|
+
|
|
387
|
+
this.bus = bus
|
|
388
|
+
|
|
389
|
+
this.set_tsc(0, 0)
|
|
390
|
+
|
|
391
|
+
if (DEBUG) {
|
|
392
|
+
this.seen_code = {}
|
|
393
|
+
this.seen_code_uncompiled = {}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Rebuild all TypedArray views into WASM linear memory.
|
|
399
|
+
* Must be called after any wasm_memory.grow() since growth
|
|
400
|
+
* detaches the old ArrayBuffer, invalidating all views.
|
|
401
|
+
*/
|
|
402
|
+
rebuild_wasm_views(): void {
|
|
403
|
+
const memory = this.wasm_memory
|
|
404
|
+
this.memory_size = view(Uint32Array, memory, 812, 1)
|
|
353
405
|
this.segment_is_null = view(Uint8Array, memory, 724, 8)
|
|
354
406
|
this.segment_offsets = view(Int32Array, memory, 736, 8)
|
|
355
407
|
this.segment_limits = view(Uint32Array, memory, 768, 8)
|
|
356
408
|
this.segment_access_bytes = view(Uint8Array, memory, 512, 8)
|
|
357
|
-
|
|
358
|
-
// Whether or not in protected mode
|
|
359
409
|
this.protected_mode = view(Int32Array, memory, 800, 1)
|
|
360
|
-
|
|
361
410
|
this.idtr_size = view(Int32Array, memory, 564, 1)
|
|
362
411
|
this.idtr_offset = view(Int32Array, memory, 568, 1)
|
|
363
|
-
|
|
364
|
-
// global descriptor table register
|
|
365
412
|
this.gdtr_size = view(Int32Array, memory, 572, 1)
|
|
366
413
|
this.gdtr_offset = view(Int32Array, memory, 576, 1)
|
|
367
|
-
|
|
368
414
|
this.tss_size_32 = view(Int32Array, memory, 1128, 1)
|
|
369
|
-
|
|
370
|
-
// whether or not a page fault occured
|
|
371
415
|
this.page_fault = view(Uint32Array, memory, 540, 8)
|
|
372
|
-
|
|
373
416
|
this.cr = view(Int32Array, memory, 580, 8)
|
|
374
|
-
|
|
375
|
-
// current privilege level
|
|
376
417
|
this.cpl = view(Uint8Array, memory, 612, 1)
|
|
377
|
-
|
|
378
|
-
// current operand/address size
|
|
379
418
|
this.is_32 = view(Int32Array, memory, 804, 1)
|
|
380
|
-
|
|
381
419
|
this.stack_size_32 = view(Int32Array, memory, 808, 1)
|
|
382
|
-
|
|
383
|
-
// Was the last instruction a hlt?
|
|
384
420
|
this.in_hlt = view(Uint8Array, memory, 616, 1)
|
|
385
|
-
|
|
386
421
|
this.last_virt_eip = view(Int32Array, memory, 620, 1)
|
|
387
422
|
this.eip_phys = view(Int32Array, memory, 624, 1)
|
|
388
|
-
|
|
389
423
|
this.sysenter_cs = view(Int32Array, memory, 636, 1)
|
|
390
|
-
|
|
391
424
|
this.sysenter_esp = view(Int32Array, memory, 640, 1)
|
|
392
|
-
|
|
393
425
|
this.sysenter_eip = view(Int32Array, memory, 644, 1)
|
|
394
|
-
|
|
395
426
|
this.prefixes = view(Int32Array, memory, 648, 1)
|
|
396
|
-
|
|
397
427
|
this.flags = view(Int32Array, memory, 120, 1)
|
|
398
|
-
|
|
399
|
-
// bitmap of flags which are not updated in the flags variable
|
|
400
|
-
// changed by arithmetic instructions, so only relevant to arithmetic flags
|
|
401
428
|
this.flags_changed = view(Int32Array, memory, 100, 1)
|
|
402
|
-
|
|
403
|
-
// enough infos about the last arithmetic operation to compute eflags
|
|
404
429
|
this.last_op_size = view(Int32Array, memory, 96, 1)
|
|
405
430
|
this.last_op1 = view(Int32Array, memory, 104, 1)
|
|
406
431
|
this.last_result = view(Int32Array, memory, 112, 1)
|
|
407
|
-
|
|
408
|
-
this.current_tsc = view(Uint32Array, memory, 960, 2) // 64 bit
|
|
409
|
-
|
|
410
|
-
// @ts-expect-error Devices are populated during init()
|
|
411
|
-
this.devices = {}
|
|
412
|
-
|
|
432
|
+
this.current_tsc = view(Uint32Array, memory, 960, 2)
|
|
413
433
|
this.instruction_pointer = view(Int32Array, memory, 556, 1)
|
|
414
434
|
this.previous_ip = view(Int32Array, memory, 560, 1)
|
|
415
|
-
|
|
416
|
-
// configured by guest
|
|
417
435
|
this.apic_enabled = view(Uint8Array, memory, 548, 1)
|
|
418
|
-
// configured when the emulator starts (changes bios initialisation)
|
|
419
436
|
this.acpi_enabled = view(Uint8Array, memory, 552, 1)
|
|
420
|
-
|
|
421
|
-
// managed in io.js
|
|
422
|
-
this.memory_map_read8 = []
|
|
423
|
-
this.memory_map_write8 = []
|
|
424
|
-
this.memory_map_read32 = []
|
|
425
|
-
this.memory_map_write32 = []
|
|
426
|
-
|
|
427
|
-
this.bios = {
|
|
428
|
-
main: null,
|
|
429
|
-
vga: null,
|
|
430
|
-
}
|
|
431
|
-
|
|
432
437
|
this.instruction_counter = view(Uint32Array, memory, 664, 1)
|
|
433
|
-
|
|
434
|
-
// registers
|
|
435
438
|
this.reg32 = view(Int32Array, memory, 64, 8)
|
|
436
|
-
|
|
437
439
|
this.fpu_st = view(Int32Array, memory, 1152, 4 * 8)
|
|
438
|
-
|
|
439
440
|
this.fpu_stack_empty = view(Uint8Array, memory, 816, 1)
|
|
440
|
-
this.fpu_stack_empty[0] = 0xff
|
|
441
441
|
this.fpu_stack_ptr = view(Uint8Array, memory, 1032, 1)
|
|
442
|
-
this.fpu_stack_ptr[0] = 0
|
|
443
|
-
|
|
444
442
|
this.fpu_control_word = view(Uint16Array, memory, 1036, 1)
|
|
445
|
-
this.fpu_control_word[0] = 0x37f
|
|
446
443
|
this.fpu_status_word = view(Uint16Array, memory, 1040, 1)
|
|
447
|
-
this.fpu_status_word[0] = 0
|
|
448
444
|
this.fpu_ip = view(Int32Array, memory, 1048, 1)
|
|
449
|
-
this.fpu_ip[0] = 0
|
|
450
445
|
this.fpu_ip_selector = view(Int32Array, memory, 1052, 1)
|
|
451
|
-
this.fpu_ip_selector[0] = 0
|
|
452
446
|
this.fpu_opcode = view(Int32Array, memory, 1044, 1)
|
|
453
|
-
this.fpu_opcode[0] = 0
|
|
454
447
|
this.fpu_dp = view(Int32Array, memory, 1056, 1)
|
|
455
|
-
this.fpu_dp[0] = 0
|
|
456
448
|
this.fpu_dp_selector = view(Int32Array, memory, 1060, 1)
|
|
457
|
-
this.fpu_dp_selector[0] = 0
|
|
458
|
-
|
|
459
449
|
this.reg_xmm32s = view(Int32Array, memory, 832, 8 * 4)
|
|
460
|
-
|
|
461
450
|
this.mxcsr = view(Int32Array, memory, 824, 1)
|
|
462
|
-
|
|
463
|
-
// segment registers, tr and ldtr
|
|
464
451
|
this.sreg = view(Uint16Array, memory, 668, 8)
|
|
465
|
-
|
|
466
|
-
// debug registers
|
|
467
452
|
this.dreg = view(Int32Array, memory, 684, 8)
|
|
468
|
-
|
|
469
453
|
this.reg_pdpte = view(Int32Array, memory, 968, 8)
|
|
470
|
-
|
|
471
454
|
this.svga_dirty_bitmap_min_offset = view(Uint32Array, memory, 716, 1)
|
|
472
455
|
this.svga_dirty_bitmap_max_offset = view(Uint32Array, memory, 720, 1)
|
|
473
|
-
|
|
474
|
-
this.fw_value = []
|
|
475
|
-
this.fw_pointer = 0
|
|
476
|
-
this.option_roms = []
|
|
477
|
-
|
|
478
|
-
this.io = undefined!
|
|
479
|
-
|
|
480
|
-
this.bus = bus
|
|
481
|
-
|
|
482
|
-
this.set_tsc(0, 0)
|
|
483
|
-
|
|
484
|
-
if (DEBUG) {
|
|
485
|
-
this.seen_code = {}
|
|
486
|
-
this.seen_code_uncompiled = {}
|
|
487
|
-
}
|
|
488
456
|
}
|
|
489
457
|
|
|
490
458
|
mmap_read8(addr: number): number {
|
|
@@ -576,7 +544,7 @@ export class CPU {
|
|
|
576
544
|
|
|
577
545
|
const jit_imports = Object.create(null)
|
|
578
546
|
|
|
579
|
-
jit_imports['m'] = this.
|
|
547
|
+
jit_imports['m'] = this.wasm_memory
|
|
580
548
|
|
|
581
549
|
for (const name of Object.keys(this.wm.exports)) {
|
|
582
550
|
if (
|
|
@@ -611,8 +579,6 @@ export class CPU {
|
|
|
611
579
|
|
|
612
580
|
this.main_loop = get_import('main_loop')
|
|
613
581
|
|
|
614
|
-
this.reboot_internal = get_import('reboot_internal')
|
|
615
|
-
|
|
616
582
|
this.set_jit_config = get_import('set_jit_config')
|
|
617
583
|
|
|
618
584
|
this.read8 = get_import('read8')
|
|
@@ -812,6 +778,8 @@ export class CPU {
|
|
|
812
778
|
state[86] = this.last_result
|
|
813
779
|
state[87] = this.fpu_status_word
|
|
814
780
|
state[88] = this.mxcsr
|
|
781
|
+
state[89] = this.devices.virtio_mem
|
|
782
|
+
state[90] = this.devices.virtio_v86fs
|
|
815
783
|
|
|
816
784
|
return state
|
|
817
785
|
}
|
|
@@ -882,8 +850,34 @@ export class CPU {
|
|
|
882
850
|
)
|
|
883
851
|
}
|
|
884
852
|
|
|
853
|
+
resize_memory(new_size: number): void {
|
|
854
|
+
const mem8_offset = this.mem8_offset
|
|
855
|
+
const needed_total = mem8_offset + new_size
|
|
856
|
+
const current_buffer = this.wasm_memory.buffer.byteLength
|
|
857
|
+
if (needed_total > current_buffer) {
|
|
858
|
+
const grow_pages = Math.ceil(
|
|
859
|
+
(needed_total - current_buffer) / WASM_PAGE_SIZE,
|
|
860
|
+
)
|
|
861
|
+
this.wasm_memory.grow(grow_pages)
|
|
862
|
+
this.rebuild_wasm_views()
|
|
863
|
+
}
|
|
864
|
+
this.mem8 = view(Uint8Array, this.wasm_memory, mem8_offset, new_size)
|
|
865
|
+
this.mem32s = view(
|
|
866
|
+
Int32Array,
|
|
867
|
+
this.wasm_memory,
|
|
868
|
+
mem8_offset,
|
|
869
|
+
new_size >> 2,
|
|
870
|
+
)
|
|
871
|
+
this.memory_size[0] = new_size
|
|
872
|
+
}
|
|
873
|
+
|
|
885
874
|
set_state(state: any[]): void {
|
|
886
|
-
|
|
875
|
+
const saved_memory_size = state[0]
|
|
876
|
+
if (saved_memory_size > this.memory_size[0]) {
|
|
877
|
+
this.resize_memory(saved_memory_size)
|
|
878
|
+
} else {
|
|
879
|
+
this.memory_size[0] = saved_memory_size
|
|
880
|
+
}
|
|
887
881
|
|
|
888
882
|
if (this.mem8.length !== this.memory_size[0]) {
|
|
889
883
|
console.warn(
|
|
@@ -1007,6 +1001,10 @@ export class CPU {
|
|
|
1007
1001
|
this.devices.virtio_net.set_state(state[83])
|
|
1008
1002
|
if (this.devices.virtio_balloon)
|
|
1009
1003
|
this.devices.virtio_balloon.set_state(state[84])
|
|
1004
|
+
if (this.devices.virtio_mem && state[89])
|
|
1005
|
+
this.devices.virtio_mem.set_state(state[89])
|
|
1006
|
+
if (this.devices.virtio_v86fs && state[90])
|
|
1007
|
+
this.devices.virtio_v86fs.set_state(state[90])
|
|
1010
1008
|
|
|
1011
1009
|
this.fw_value = state[62]
|
|
1012
1010
|
|
|
@@ -1247,9 +1245,10 @@ export class CPU {
|
|
|
1247
1245
|
'Expected uninitialised memory',
|
|
1248
1246
|
)
|
|
1249
1247
|
|
|
1250
|
-
this.memory_size[0] = size
|
|
1251
|
-
|
|
1252
1248
|
const memory_offset = this.allocate_memory(size)
|
|
1249
|
+
this.rebuild_wasm_views()
|
|
1250
|
+
this.memory_size[0] = size
|
|
1251
|
+
this.mem8_offset = memory_offset
|
|
1253
1252
|
|
|
1254
1253
|
this.mem8 = view(Uint8Array, this.wasm_memory, memory_offset, size)
|
|
1255
1254
|
this.mem32s = view(
|
|
@@ -1521,6 +1520,19 @@ export class CPU {
|
|
|
1521
1520
|
device_bus,
|
|
1522
1521
|
)
|
|
1523
1522
|
}
|
|
1523
|
+
if (settings.virtio_mem) {
|
|
1524
|
+
const mem_cfg = settings.virtio_mem
|
|
1525
|
+
this.devices.virtio_mem = new VirtioMem(
|
|
1526
|
+
this,
|
|
1527
|
+
device_bus,
|
|
1528
|
+
mem_cfg.region_addr,
|
|
1529
|
+
mem_cfg.region_size,
|
|
1530
|
+
mem_cfg.block_size,
|
|
1531
|
+
)
|
|
1532
|
+
}
|
|
1533
|
+
if (settings.virtio_v86fs) {
|
|
1534
|
+
this.devices.virtio_v86fs = new VirtioV86FS(this, device_bus)
|
|
1535
|
+
}
|
|
1524
1536
|
|
|
1525
1537
|
this.devices.sb16 = new SB16(this, device_bus)
|
|
1526
1538
|
}
|
|
@@ -1545,6 +1557,25 @@ export class CPU {
|
|
|
1545
1557
|
}
|
|
1546
1558
|
|
|
1547
1559
|
this.debug_init()
|
|
1560
|
+
|
|
1561
|
+
// Rebuild all WASM memory views. During init, allocate_memory
|
|
1562
|
+
// and svga_allocate_memory may trigger memory.grow (from Rust),
|
|
1563
|
+
// which detaches the old ArrayBuffer and invalidates all views.
|
|
1564
|
+
this.rebuild_wasm_views()
|
|
1565
|
+
if (this.mem8_offset > 0) {
|
|
1566
|
+
this.mem8 = view(
|
|
1567
|
+
Uint8Array,
|
|
1568
|
+
this.wasm_memory,
|
|
1569
|
+
this.mem8_offset,
|
|
1570
|
+
this.memory_size[0],
|
|
1571
|
+
)
|
|
1572
|
+
this.mem32s = view(
|
|
1573
|
+
Uint32Array,
|
|
1574
|
+
this.wasm_memory,
|
|
1575
|
+
this.mem8_offset,
|
|
1576
|
+
this.memory_size[0] >> 2,
|
|
1577
|
+
)
|
|
1578
|
+
}
|
|
1548
1579
|
}
|
|
1549
1580
|
|
|
1550
1581
|
load_multiboot(buffer: ArrayBuffer): void {
|
|
@@ -1858,7 +1889,6 @@ export class CPU {
|
|
|
1858
1889
|
cpu.write32(multiboot_data + 4, ramdisk_top) // mod_end
|
|
1859
1890
|
cpu.write32(multiboot_data + 8, 0) // string
|
|
1860
1891
|
cpu.write32(multiboot_data + 12, 0) // reserved
|
|
1861
|
-
multiboot_data += 16
|
|
1862
1892
|
|
|
1863
1893
|
dbg_assert(ramdisk_top < cpu.memory_size[0])
|
|
1864
1894
|
|
package/src/pci.ts
CHANGED
|
@@ -13,7 +13,7 @@ interface PCICpu {
|
|
|
13
13
|
io: IO
|
|
14
14
|
device_raise_irq(irq: number): void
|
|
15
15
|
device_lower_irq(irq: number): void
|
|
16
|
-
|
|
16
|
+
reboot(): void
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Mirrors IOPortEntry from io.ts (not exported there).
|
|
@@ -177,7 +177,7 @@ export class PCI {
|
|
|
177
177
|
(out_byte & 0x06) === 0x06
|
|
178
178
|
) {
|
|
179
179
|
dbg_log('CPU reboot via PCI')
|
|
180
|
-
cpu.
|
|
180
|
+
cpu.reboot()
|
|
181
181
|
return
|
|
182
182
|
}
|
|
183
183
|
|
|
@@ -304,6 +304,7 @@ export class PCI {
|
|
|
304
304
|
0x00,
|
|
305
305
|
0x00,
|
|
306
306
|
0x00,
|
|
307
|
+
0x00,
|
|
307
308
|
PAM0,
|
|
308
309
|
0x00,
|
|
309
310
|
0x00,
|
|
@@ -711,7 +712,11 @@ export class PCI {
|
|
|
711
712
|
|
|
712
713
|
// convert bytewise notation from lspci to double words
|
|
713
714
|
const space = new Int32Array(64)
|
|
714
|
-
|
|
715
|
+
const pci_bytes = new Uint8Array(device.pci_space)
|
|
716
|
+
const aligned_len = pci_bytes.length & ~3
|
|
717
|
+
if (aligned_len > 0) {
|
|
718
|
+
space.set(new Int32Array(pci_bytes.buffer, 0, aligned_len >> 2))
|
|
719
|
+
}
|
|
715
720
|
this.device_spaces[device_id] = space
|
|
716
721
|
this.devices[device_id] = device
|
|
717
722
|
|
package/src/ps2.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface PS2Cpu {
|
|
|
11
11
|
io: IO
|
|
12
12
|
device_raise_irq(irq: number): void
|
|
13
13
|
device_lower_irq(irq: number): void
|
|
14
|
-
|
|
14
|
+
reboot(): void
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
type PS2State = [
|
|
@@ -808,7 +808,7 @@ export class PS2 {
|
|
|
808
808
|
break
|
|
809
809
|
case 0xfe:
|
|
810
810
|
dbg_log('CPU reboot via PS2')
|
|
811
|
-
this.cpu.
|
|
811
|
+
this.cpu.reboot()
|
|
812
812
|
break
|
|
813
813
|
default:
|
|
814
814
|
dbg_log(
|