@aptre/v86 0.5.0 → 0.6.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/dist/v86.browser.js +1016 -60
- package/dist/v86.browser.js.map +4 -4
- package/dist/v86.js +1015 -60
- 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 +11 -21
- package/src/const.ts +2 -0
- package/src/cpu.ts +48 -8
- 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.0",
|
|
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.
|
|
@@ -122,7 +112,7 @@ export class V86 {
|
|
|
122
112
|
initial: WASM_TABLE_SIZE + WASM_TABLE_OFFSET,
|
|
123
113
|
})
|
|
124
114
|
|
|
125
|
-
const wasm_shared_funcs = {
|
|
115
|
+
const wasm_shared_funcs: Record<string, any> = {
|
|
126
116
|
cpu_exception_hook: (n: number) => this.cpu_exception_hook(n),
|
|
127
117
|
|
|
128
118
|
run_hardware_timers: function (a: any, t: any) {
|
|
@@ -231,8 +221,6 @@ export class V86 {
|
|
|
231
221
|
|
|
232
222
|
if (!wasm_fn) {
|
|
233
223
|
wasm_fn = (env: any) => {
|
|
234
|
-
/* global __dirname */
|
|
235
|
-
|
|
236
224
|
return new Promise((resolve) => {
|
|
237
225
|
let v86_bin = DEBUG ? 'v86-debug.wasm' : 'v86.wasm'
|
|
238
226
|
let v86_bin_fallback = 'v86-fallback.wasm'
|
|
@@ -243,12 +231,11 @@ export class V86 {
|
|
|
243
231
|
'v86.wasm',
|
|
244
232
|
'v86-fallback.wasm',
|
|
245
233
|
)
|
|
246
|
-
} else if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
v86_bin_fallback = __dirname + '/' + v86_bin_fallback
|
|
234
|
+
} else if (typeof window === 'undefined') {
|
|
235
|
+
// Node/Bun: resolve WASM relative to project root build/
|
|
236
|
+
const root = new URL('../../', import.meta.url).pathname
|
|
237
|
+
v86_bin = root + 'build/' + v86_bin
|
|
238
|
+
v86_bin_fallback = root + 'build/' + v86_bin_fallback
|
|
252
239
|
} else {
|
|
253
240
|
v86_bin = 'build/' + v86_bin
|
|
254
241
|
v86_bin_fallback = 'build/' + v86_bin_fallback
|
|
@@ -299,6 +286,7 @@ export class V86 {
|
|
|
299
286
|
const emulator = (this.v86 = new v86(this.emulator_bus, {
|
|
300
287
|
exports,
|
|
301
288
|
wasm_table,
|
|
289
|
+
wasm_memory,
|
|
302
290
|
}))
|
|
303
291
|
cpu = emulator.cpu
|
|
304
292
|
|
|
@@ -356,7 +344,9 @@ export class V86 {
|
|
|
356
344
|
settings.mac_address_translation = options.mac_address_translation
|
|
357
345
|
settings.cpuid_level = options.cpuid_level
|
|
358
346
|
settings.virtio_balloon = options.virtio_balloon
|
|
347
|
+
settings.virtio_mem = options.virtio_mem
|
|
359
348
|
settings.virtio_console = !!options.virtio_console
|
|
349
|
+
settings.virtio_v86fs = !!options.virtio_v86fs
|
|
360
350
|
|
|
361
351
|
const relay_url =
|
|
362
352
|
options.network_relay_url ||
|
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 {
|
|
@@ -268,7 +274,6 @@ export class CPU {
|
|
|
268
274
|
get_eflags!: () => number
|
|
269
275
|
handle_irqs!: () => void
|
|
270
276
|
main_loop!: () => number
|
|
271
|
-
reboot_internal!: () => void
|
|
272
277
|
set_jit_config!: (a: number, b: number) => void
|
|
273
278
|
|
|
274
279
|
read8!: (addr: number) => number
|
|
@@ -338,12 +343,11 @@ export class CPU {
|
|
|
338
343
|
this.name = 'cpu'
|
|
339
344
|
this.stop_idling = stop_idling
|
|
340
345
|
this.wm = wm
|
|
346
|
+
this.wasm_memory = wm.wasm_memory
|
|
341
347
|
this.wasm_patch()
|
|
342
348
|
this.create_jit_imports()
|
|
343
349
|
|
|
344
|
-
const memory = this.
|
|
345
|
-
|
|
346
|
-
this.wasm_memory = memory
|
|
350
|
+
const memory = this.wasm_memory
|
|
347
351
|
|
|
348
352
|
this.memory_size = view(Uint32Array, memory, 812, 1)
|
|
349
353
|
|
|
@@ -576,7 +580,7 @@ export class CPU {
|
|
|
576
580
|
|
|
577
581
|
const jit_imports = Object.create(null)
|
|
578
582
|
|
|
579
|
-
jit_imports['m'] = this.
|
|
583
|
+
jit_imports['m'] = this.wasm_memory
|
|
580
584
|
|
|
581
585
|
for (const name of Object.keys(this.wm.exports)) {
|
|
582
586
|
if (
|
|
@@ -611,8 +615,6 @@ export class CPU {
|
|
|
611
615
|
|
|
612
616
|
this.main_loop = get_import('main_loop')
|
|
613
617
|
|
|
614
|
-
this.reboot_internal = get_import('reboot_internal')
|
|
615
|
-
|
|
616
618
|
this.set_jit_config = get_import('set_jit_config')
|
|
617
619
|
|
|
618
620
|
this.read8 = get_import('read8')
|
|
@@ -812,6 +814,8 @@ export class CPU {
|
|
|
812
814
|
state[86] = this.last_result
|
|
813
815
|
state[87] = this.fpu_status_word
|
|
814
816
|
state[88] = this.mxcsr
|
|
817
|
+
state[89] = this.devices.virtio_mem
|
|
818
|
+
state[90] = this.devices.virtio_v86fs
|
|
815
819
|
|
|
816
820
|
return state
|
|
817
821
|
}
|
|
@@ -882,6 +886,26 @@ export class CPU {
|
|
|
882
886
|
)
|
|
883
887
|
}
|
|
884
888
|
|
|
889
|
+
resize_memory(new_size: number): void {
|
|
890
|
+
const mem8_offset = this.mem8.byteOffset
|
|
891
|
+
const needed_total = mem8_offset + new_size
|
|
892
|
+
const current_buffer = this.wasm_memory.buffer.byteLength
|
|
893
|
+
if (needed_total > current_buffer) {
|
|
894
|
+
const grow_pages = Math.ceil(
|
|
895
|
+
(needed_total - current_buffer) / WASM_PAGE_SIZE,
|
|
896
|
+
)
|
|
897
|
+
this.wasm_memory.grow(grow_pages)
|
|
898
|
+
}
|
|
899
|
+
this.mem8 = view(Uint8Array, this.wasm_memory, mem8_offset, new_size)
|
|
900
|
+
this.mem32s = view(
|
|
901
|
+
Int32Array,
|
|
902
|
+
this.wasm_memory,
|
|
903
|
+
mem8_offset,
|
|
904
|
+
new_size >> 2,
|
|
905
|
+
)
|
|
906
|
+
this.memory_size[0] = new_size
|
|
907
|
+
}
|
|
908
|
+
|
|
885
909
|
set_state(state: any[]): void {
|
|
886
910
|
this.memory_size[0] = state[0]
|
|
887
911
|
|
|
@@ -1007,6 +1031,10 @@ export class CPU {
|
|
|
1007
1031
|
this.devices.virtio_net.set_state(state[83])
|
|
1008
1032
|
if (this.devices.virtio_balloon)
|
|
1009
1033
|
this.devices.virtio_balloon.set_state(state[84])
|
|
1034
|
+
if (this.devices.virtio_mem && state[89])
|
|
1035
|
+
this.devices.virtio_mem.set_state(state[89])
|
|
1036
|
+
if (this.devices.virtio_v86fs && state[90])
|
|
1037
|
+
this.devices.virtio_v86fs.set_state(state[90])
|
|
1010
1038
|
|
|
1011
1039
|
this.fw_value = state[62]
|
|
1012
1040
|
|
|
@@ -1521,6 +1549,19 @@ export class CPU {
|
|
|
1521
1549
|
device_bus,
|
|
1522
1550
|
)
|
|
1523
1551
|
}
|
|
1552
|
+
if (settings.virtio_mem) {
|
|
1553
|
+
const mem_cfg = settings.virtio_mem
|
|
1554
|
+
this.devices.virtio_mem = new VirtioMem(
|
|
1555
|
+
this,
|
|
1556
|
+
device_bus,
|
|
1557
|
+
mem_cfg.region_addr,
|
|
1558
|
+
mem_cfg.region_size,
|
|
1559
|
+
mem_cfg.block_size,
|
|
1560
|
+
)
|
|
1561
|
+
}
|
|
1562
|
+
if (settings.virtio_v86fs) {
|
|
1563
|
+
this.devices.virtio_v86fs = new VirtioV86FS(this, device_bus)
|
|
1564
|
+
}
|
|
1524
1565
|
|
|
1525
1566
|
this.devices.sb16 = new SB16(this, device_bus)
|
|
1526
1567
|
}
|
|
@@ -1858,7 +1899,6 @@ export class CPU {
|
|
|
1858
1899
|
cpu.write32(multiboot_data + 4, ramdisk_top) // mod_end
|
|
1859
1900
|
cpu.write32(multiboot_data + 8, 0) // string
|
|
1860
1901
|
cpu.write32(multiboot_data + 12, 0) // reserved
|
|
1861
|
-
multiboot_data += 16
|
|
1862
1902
|
|
|
1863
1903
|
dbg_assert(ramdisk_top < cpu.memory_size[0])
|
|
1864
1904
|
|
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(
|
package/src/virtio.ts
CHANGED
|
@@ -520,18 +520,6 @@ export class VirtIO {
|
|
|
520
520
|
)
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
-
if (
|
|
524
|
-
data &
|
|
525
|
-
~this.device_status &
|
|
526
|
-
VIRTIO_STATUS_DRIVER_OK &&
|
|
527
|
-
this.device_status &
|
|
528
|
-
VIRTIO_STATUS_DEVICE_NEEDS_RESET
|
|
529
|
-
) {
|
|
530
|
-
// We couldn't notify NEEDS_RESET earlier because DRIVER_OK was not set.
|
|
531
|
-
// Now it has been set, notify now.
|
|
532
|
-
this.notify_config_changes()
|
|
533
|
-
}
|
|
534
|
-
|
|
535
523
|
// Don't set FEATURES_OK if our device doesn't support requested features.
|
|
536
524
|
if (!this.features_ok) {
|
|
537
525
|
if (DEBUG && data & VIRTIO_STATUS_FEATURES_OK) {
|
|
@@ -540,13 +528,17 @@ export class VirtIO {
|
|
|
540
528
|
data &= ~VIRTIO_STATUS_FEATURES_OK
|
|
541
529
|
}
|
|
542
530
|
|
|
531
|
+
const prev_status = this.device_status
|
|
543
532
|
this.device_status = data
|
|
544
533
|
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
534
|
+
if (data & ~prev_status & VIRTIO_STATUS_DRIVER_OK) {
|
|
535
|
+
if (
|
|
536
|
+
prev_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET
|
|
537
|
+
) {
|
|
538
|
+
// We couldn't notify NEEDS_RESET earlier because DRIVER_OK was not set.
|
|
539
|
+
// Now it has been set, notify now.
|
|
540
|
+
this.notify_config_changes()
|
|
541
|
+
}
|
|
550
542
|
options.on_driver_ok()
|
|
551
543
|
}
|
|
552
544
|
},
|
|
@@ -837,7 +829,7 @@ export class VirtIO {
|
|
|
837
829
|
let cap_next = (this.pci_space[0x34] = 0x40)
|
|
838
830
|
|
|
839
831
|
// Current offset.
|
|
840
|
-
let cap_ptr
|
|
832
|
+
let cap_ptr
|
|
841
833
|
|
|
842
834
|
for (const cap of capabilities) {
|
|
843
835
|
const cap_len = VIRTIO_PCI_CAP_LENGTH + cap.extra.length
|