@aptre/v86 0.6.0 → 0.6.2
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 +48 -19
- package/dist/v86.browser.js.map +2 -2
- package/dist/v86.js +48 -19
- package/dist/v86.js.map +2 -2
- package/package.json +1 -1
- package/src/browser/starter.ts +47 -3
- package/src/cpu.ts +16 -32
package/package.json
CHANGED
package/src/browser/starter.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
declare let DEBUG: boolean
|
|
2
2
|
|
|
3
3
|
import { v86 } from '../main.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
LOG_CPU,
|
|
6
|
+
WASM_PAGE_SIZE,
|
|
7
|
+
WASM_TABLE_OFFSET,
|
|
8
|
+
WASM_TABLE_SIZE,
|
|
9
|
+
} from '../const.js'
|
|
5
10
|
import { get_rand_int, load_file, read_sized_string_from_mem } from '../lib.js'
|
|
6
11
|
import { dbg_assert, dbg_trace, dbg_log, set_log_level } from '../log.js'
|
|
7
12
|
import * as print_stats from './print_stats.js'
|
|
@@ -105,7 +110,22 @@ export class V86 {
|
|
|
105
110
|
|
|
106
111
|
let cpu: any
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
// Reserve VA upfront so memory.grow() is fast (no realloc+copy).
|
|
114
|
+
// Without maximum, engines must reallocate on every grow which
|
|
115
|
+
// is expensive and can OOM for large guest memories.
|
|
116
|
+
const memory_size = options.memory_size || 64 * 1024 * 1024
|
|
117
|
+
const vga_memory_size = options.vga_memory_size || 8 * 1024 * 1024
|
|
118
|
+
const memory_max =
|
|
119
|
+
options.memory_max || (memory_size + vga_memory_size) * 4
|
|
120
|
+
const wasm_initial_pages = 256
|
|
121
|
+
const wasm_max_pages = Math.max(
|
|
122
|
+
wasm_initial_pages,
|
|
123
|
+
Math.min(Math.ceil(memory_max / WASM_PAGE_SIZE), 65536),
|
|
124
|
+
)
|
|
125
|
+
const wasm_memory = new WebAssembly.Memory({
|
|
126
|
+
initial: wasm_initial_pages,
|
|
127
|
+
maximum: wasm_max_pages,
|
|
128
|
+
})
|
|
109
129
|
|
|
110
130
|
const wasm_table = new WebAssembly.Table({
|
|
111
131
|
element: 'anyfunc',
|
|
@@ -113,6 +133,7 @@ export class V86 {
|
|
|
113
133
|
})
|
|
114
134
|
|
|
115
135
|
const wasm_shared_funcs: Record<string, any> = {
|
|
136
|
+
memory: wasm_memory,
|
|
116
137
|
cpu_exception_hook: (n: number) => this.cpu_exception_hook(n),
|
|
117
138
|
|
|
118
139
|
run_hardware_timers: function (a: any, t: any) {
|
|
@@ -280,7 +301,6 @@ export class V86 {
|
|
|
280
301
|
}
|
|
281
302
|
|
|
282
303
|
wasm_fn({ env: wasm_shared_funcs }).then((exports: WasmExports) => {
|
|
283
|
-
wasm_memory = exports.memory
|
|
284
304
|
exports['rust_init']()
|
|
285
305
|
|
|
286
306
|
const emulator = (this.v86 = new v86(this.emulator_bus, {
|
|
@@ -957,6 +977,30 @@ export class V86 {
|
|
|
957
977
|
this.v86.run()
|
|
958
978
|
}
|
|
959
979
|
|
|
980
|
+
/**
|
|
981
|
+
* Grow guest memory to the specified size in bytes. Stops the VM,
|
|
982
|
+
* grows WASM linear memory, updates memory_size, clears the TLB,
|
|
983
|
+
* and resumes execution.
|
|
984
|
+
*/
|
|
985
|
+
async growMemory(newSizeBytes: number): Promise<void> {
|
|
986
|
+
const cpu = this.v86.cpu
|
|
987
|
+
if (newSizeBytes <= cpu.memory_size[0]) {
|
|
988
|
+
return
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const wasRunning = this.cpu_is_running
|
|
992
|
+
if (wasRunning) {
|
|
993
|
+
await this.stop()
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
cpu.resize_memory(newSizeBytes)
|
|
997
|
+
cpu.full_clear_tlb()
|
|
998
|
+
|
|
999
|
+
if (wasRunning) {
|
|
1000
|
+
await this.run()
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
960
1004
|
/**
|
|
961
1005
|
* Stop emulation. Do nothing if emulator is not running. Can be asynchronous.
|
|
962
1006
|
*/
|
package/src/cpu.ts
CHANGED
|
@@ -359,32 +359,26 @@ export class CPU {
|
|
|
359
359
|
this.segment_limits = view(Uint32Array, memory, 768, 8)
|
|
360
360
|
this.segment_access_bytes = view(Uint8Array, memory, 512, 8)
|
|
361
361
|
|
|
362
|
-
// Whether or not in protected mode
|
|
363
362
|
this.protected_mode = view(Int32Array, memory, 800, 1)
|
|
364
363
|
|
|
365
364
|
this.idtr_size = view(Int32Array, memory, 564, 1)
|
|
366
365
|
this.idtr_offset = view(Int32Array, memory, 568, 1)
|
|
367
366
|
|
|
368
|
-
// global descriptor table register
|
|
369
367
|
this.gdtr_size = view(Int32Array, memory, 572, 1)
|
|
370
368
|
this.gdtr_offset = view(Int32Array, memory, 576, 1)
|
|
371
369
|
|
|
372
370
|
this.tss_size_32 = view(Int32Array, memory, 1128, 1)
|
|
373
371
|
|
|
374
|
-
// whether or not a page fault occured
|
|
375
372
|
this.page_fault = view(Uint32Array, memory, 540, 8)
|
|
376
373
|
|
|
377
374
|
this.cr = view(Int32Array, memory, 580, 8)
|
|
378
375
|
|
|
379
|
-
// current privilege level
|
|
380
376
|
this.cpl = view(Uint8Array, memory, 612, 1)
|
|
381
377
|
|
|
382
|
-
// current operand/address size
|
|
383
378
|
this.is_32 = view(Int32Array, memory, 804, 1)
|
|
384
379
|
|
|
385
380
|
this.stack_size_32 = view(Int32Array, memory, 808, 1)
|
|
386
381
|
|
|
387
|
-
// Was the last instruction a hlt?
|
|
388
382
|
this.in_hlt = view(Uint8Array, memory, 616, 1)
|
|
389
383
|
|
|
390
384
|
this.last_virt_eip = view(Int32Array, memory, 620, 1)
|
|
@@ -400,16 +394,13 @@ export class CPU {
|
|
|
400
394
|
|
|
401
395
|
this.flags = view(Int32Array, memory, 120, 1)
|
|
402
396
|
|
|
403
|
-
// bitmap of flags which are not updated in the flags variable
|
|
404
|
-
// changed by arithmetic instructions, so only relevant to arithmetic flags
|
|
405
397
|
this.flags_changed = view(Int32Array, memory, 100, 1)
|
|
406
398
|
|
|
407
|
-
// enough infos about the last arithmetic operation to compute eflags
|
|
408
399
|
this.last_op_size = view(Int32Array, memory, 96, 1)
|
|
409
400
|
this.last_op1 = view(Int32Array, memory, 104, 1)
|
|
410
401
|
this.last_result = view(Int32Array, memory, 112, 1)
|
|
411
402
|
|
|
412
|
-
this.current_tsc = view(Uint32Array, memory, 960, 2)
|
|
403
|
+
this.current_tsc = view(Uint32Array, memory, 960, 2)
|
|
413
404
|
|
|
414
405
|
// @ts-expect-error Devices are populated during init()
|
|
415
406
|
this.devices = {}
|
|
@@ -417,9 +408,7 @@ export class CPU {
|
|
|
417
408
|
this.instruction_pointer = view(Int32Array, memory, 556, 1)
|
|
418
409
|
this.previous_ip = view(Int32Array, memory, 560, 1)
|
|
419
410
|
|
|
420
|
-
// configured by guest
|
|
421
411
|
this.apic_enabled = view(Uint8Array, memory, 548, 1)
|
|
422
|
-
// configured when the emulator starts (changes bios initialisation)
|
|
423
412
|
this.acpi_enabled = view(Uint8Array, memory, 552, 1)
|
|
424
413
|
|
|
425
414
|
// managed in io.js
|
|
@@ -435,7 +424,6 @@ export class CPU {
|
|
|
435
424
|
|
|
436
425
|
this.instruction_counter = view(Uint32Array, memory, 664, 1)
|
|
437
426
|
|
|
438
|
-
// registers
|
|
439
427
|
this.reg32 = view(Int32Array, memory, 64, 8)
|
|
440
428
|
|
|
441
429
|
this.fpu_st = view(Int32Array, memory, 1152, 4 * 8)
|
|
@@ -464,10 +452,8 @@ export class CPU {
|
|
|
464
452
|
|
|
465
453
|
this.mxcsr = view(Int32Array, memory, 824, 1)
|
|
466
454
|
|
|
467
|
-
// segment registers, tr and ldtr
|
|
468
455
|
this.sreg = view(Uint16Array, memory, 668, 8)
|
|
469
456
|
|
|
470
|
-
// debug registers
|
|
471
457
|
this.dreg = view(Int32Array, memory, 684, 8)
|
|
472
458
|
|
|
473
459
|
this.reg_pdpte = view(Int32Array, memory, 968, 8)
|
|
@@ -887,27 +873,25 @@ export class CPU {
|
|
|
887
873
|
}
|
|
888
874
|
|
|
889
875
|
resize_memory(new_size: number): void {
|
|
890
|
-
const
|
|
891
|
-
const
|
|
892
|
-
const
|
|
893
|
-
if (
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
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
|
-
)
|
|
876
|
+
const offset = this.mem8.byteOffset
|
|
877
|
+
const needed = offset + new_size
|
|
878
|
+
const current = this.wasm_memory.buffer.byteLength
|
|
879
|
+
if (needed > current) {
|
|
880
|
+
const pages = Math.ceil((needed - current) / WASM_PAGE_SIZE)
|
|
881
|
+
this.wasm_memory.grow(pages)
|
|
882
|
+
}
|
|
883
|
+
this.mem8 = view(Uint8Array, this.wasm_memory, offset, new_size)
|
|
884
|
+
this.mem32s = view(Uint32Array, this.wasm_memory, offset, new_size >> 2)
|
|
906
885
|
this.memory_size[0] = new_size
|
|
907
886
|
}
|
|
908
887
|
|
|
909
888
|
set_state(state: any[]): void {
|
|
910
|
-
|
|
889
|
+
const saved_memory_size = state[0]
|
|
890
|
+
if (saved_memory_size > this.memory_size[0]) {
|
|
891
|
+
this.resize_memory(saved_memory_size)
|
|
892
|
+
} else {
|
|
893
|
+
this.memory_size[0] = saved_memory_size
|
|
894
|
+
}
|
|
911
895
|
|
|
912
896
|
if (this.mem8.length !== this.memory_size[0]) {
|
|
913
897
|
console.warn(
|