diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c78ba938..c83b8aad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,7 @@ jobs: run: (cd tests/kvm-unit-tests && ./configure && make x86/realmode.flat) - name: Run kvm-unit-test - run: tests/kvm-unit-tests/run.js tests/kvm-unit-tests/x86/realmode.flat + run: tests/kvm-unit-tests/run.mjs tests/kvm-unit-tests/x86/realmode.flat - name: Fetch namsmtests cache uses: actions/cache@v4 diff --git a/Makefile b/Makefile index 263da6d7..74d887f3 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ CARGO_FLAGS_SAFE=\ CARGO_FLAGS=$(CARGO_FLAGS_SAFE) -C target-feature=+bulk-memory -C target-feature=+multivalue -C target-feature=+simd128 -CORE_FILES=const.js config.js io.js main.js lib.js buffer.js ide.js pci.js floppy.js \ +CORE_FILES=cjs.js const.js config.js io.js main.js lib.js buffer.js ide.js pci.js floppy.js \ memory.js dma.js pit.js vga.js ps2.js rtc.js uart.js \ acpi.js apic.js ioapic.js \ state.js ne2k.js sb16.js virtio.js virtio_console.js virtio_net.js virtio_balloon.js \ @@ -151,7 +151,7 @@ build/libv86.mjs: $(CLOSURE) src/*.js lib/*.js src/browser/*.js $(CLOSURE_FLAGS)\ --compilation_level SIMPLE\ --jscomp_off=missingProperties\ - --output_wrapper ';let module = {exports:{}}; %output%; export default module.exports.V86;'\ + --output_wrapper ';let module = {exports:{}}; %output%; export default module.exports.V86; export let {V86, CPU} = module.exports;'\ --js $(CORE_FILES)\ --js $(BROWSER_FILES)\ --js $(LIB_FILES)\ @@ -257,6 +257,7 @@ clean: -rm build/libv86.js -rm build/libv86.mjs -rm build/libv86-debug.js + -rm build/libv86-debug.mjs -rm build/v86_all.js -rm build/v86.wasm -rm build/v86-debug.wasm @@ -299,45 +300,45 @@ tests: build/libv86-debug.js build/v86-debug.wasm build/integration-test-fs/fs.j tests-release: build/libv86.js build/v86.wasm build/integration-test-fs/fs.json TEST_RELEASE_BUILD=1 ./tests/full/run.js -nasmtests: build/libv86-debug.js build/v86-debug.wasm +nasmtests: build/libv86-debug.mjs build/v86-debug.wasm $(NASM_TEST_DIR)/create_tests.js $(NASM_TEST_DIR)/gen_fixtures.js $(NASM_TEST_DIR)/run.js -nasmtests-force-jit: build/libv86-debug.js build/v86-debug.wasm +nasmtests-force-jit: build/libv86-debug.mjs build/v86-debug.wasm $(NASM_TEST_DIR)/create_tests.js $(NASM_TEST_DIR)/gen_fixtures.js $(NASM_TEST_DIR)/run.js --force-jit -jitpagingtests: build/libv86-debug.js build/v86-debug.wasm +jitpagingtests: build/libv86-debug.mjs build/v86-debug.wasm $(MAKE) -C tests/jit-paging test-jit ./tests/jit-paging/run.js -qemutests: build/libv86-debug.js build/v86-debug.wasm +qemutests: build/libv86-debug.mjs build/v86-debug.wasm $(MAKE) -C tests/qemu test-i386 LOG_LEVEL=3 ./tests/qemu/run.js build/qemu-test-result ./tests/qemu/run-qemu.js > build/qemu-test-reference diff build/qemu-test-result build/qemu-test-reference -qemutests-release: build/libv86.js build/v86.wasm +qemutests-release: build/libv86.mjs build/v86.wasm $(MAKE) -C tests/qemu test-i386 TEST_RELEASE_BUILD=1 time ./tests/qemu/run.js build/qemu-test-result ./tests/qemu/run-qemu.js > build/qemu-test-reference diff build/qemu-test-result build/qemu-test-reference -kvm-unit-test: build/libv86-debug.js build/v86-debug.wasm +kvm-unit-test: build/libv86-debug.mjs build/v86-debug.wasm (cd tests/kvm-unit-tests && ./configure && make x86/realmode.flat) - tests/kvm-unit-tests/run.js tests/kvm-unit-tests/x86/realmode.flat + tests/kvm-unit-tests/run.mjs tests/kvm-unit-tests/x86/realmode.flat -kvm-unit-test-release: build/libv86.js build/v86.wasm +kvm-unit-test-release: build/libv86.mjs build/v86.wasm (cd tests/kvm-unit-tests && ./configure && make x86/realmode.flat) - TEST_RELEASE_BUILD=1 tests/kvm-unit-tests/run.js tests/kvm-unit-tests/x86/realmode.flat + TEST_RELEASE_BUILD=1 tests/kvm-unit-tests/run.mjs tests/kvm-unit-tests/x86/realmode.flat -expect-tests: build/libv86-debug.js build/v86-debug.wasm build/libwabt.js +expect-tests: build/libv86-debug.mjs build/v86-debug.wasm build/libwabt.cjs make -C tests/expect/tests ./tests/expect/run.js -devices-test: build/libv86-debug.js build/v86-debug.wasm +devices-test: build/libv86-debug.mjs build/v86-debug.wasm ./tests/devices/virtio_9p.js ./tests/devices/virtio_console.js ./tests/devices/fetch_network.js @@ -352,7 +353,7 @@ rust-test: $(RUST_FILES) rust-test-intensive: QUICKCHECK_TESTS=100000000 make rust-test -api-tests: build/libv86-debug.js build/v86-debug.wasm +api-tests: build/libv86-debug.mjs build/v86-debug.wasm ./tests/api/clean-shutdown.js ./tests/api/state.js ./tests/api/reset.js @@ -375,10 +376,11 @@ build/capstone-x86.min.js: mkdir -p build wget -nv -P build https://github.com/AlexAltea/capstone.js/releases/download/v3.0.5-rc1/capstone-x86.min.js -build/libwabt.js: +build/libwabt.cjs: mkdir -p build wget -nv -P build https://github.com/WebAssembly/wabt/archive/1.0.6.zip unzip -j -d build/ build/1.0.6.zip wabt-1.0.6/demo/libwabt.js + mv build/libwabt.js build/libwabt.cjs rm build/1.0.6.zip build/xterm.js: diff --git a/debug.html b/debug.html index 88105a4a..e752317e 100644 --- a/debug.html +++ b/debug.html @@ -4,58 +4,12 @@ v86 (debug) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + diff --git a/eslint.config.mjs b/eslint.config.mjs index 7f21000a..47f86752 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,5 +1,56 @@ + export default [ { + "languageOptions": { + "globals": { + "process": "readonly", + "window": "writable", + "navigator": "writable", + "location": "writable", + "document": "readonly", + "console": "readonly", + "crypto": "readonly", + "alert": "readonly", + "performance": "readonly", + "URL": "readonly", + "WebAssembly": "readonly", + + "setTimeout": "readonly", + "setInterval": "readonly", + "clearTimeout": "readonly", + "clearInterval": "readonly", + "requestAnimationFrame": "readonly", + "cancelAnimationFrame": "readonly", + + "Buffer": "readonly", + "FileReader": "readonly", + "TextEncoder": "readonly", + "TextDecoder": "readonly", + "fetch": "readonly", + "Headers": "readonly", + "Response": "readonly", + "WebSocket": "readonly", + "Blob": "readonly", + "Blob": "readonly", + "File": "readonly", + "XMLHttpRequest": "readonly", + "URLSearchParams": "readonly", + "ImageData": "readonly", + "Image": "readonly", + "OffscreenCanvas": "readonly", + "BroadcastChannel": "readonly", + + "AudioContext": "readonly", + "AudioWorkletProcessor": "readonly", + "webkitAudioContext": "readonly", + "AudioWorkletNode": "readonly", + "Worker": "readonly", + "postMessage": "readonly", + "importScripts": "readonly", + + "DEBUG": "writable" + } + }, rules: { "eol-last": "error", //"no-extra-parens": "error", @@ -69,7 +120,7 @@ export default [ "no-shadow-restricted-names": "error", "no-sparse-arrays": "error", "no-this-before-super": "error", - //"no-undef": "error", + "no-undef": "error", "no-unexpected-multiline": "error", //"no-unreachable": "error", "no-unsafe-finally": "error", diff --git a/examples/nodejs.js b/examples/nodejs.js index c2ec8246..98b4fd8b 100755 --- a/examples/nodejs.js +++ b/examples/nodejs.js @@ -1,8 +1,11 @@ #!/usr/bin/env node "use strict"; -var fs = require("fs"); -var V86 = require("../build/libv86.js").V86; +import fs from "node:fs"; +import url from "node:url"; +import { V86 } from "../build/libv86.js"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); function readfile(path) { diff --git a/examples/nodejs_state.js b/examples/nodejs_state.js index 229f2c14..63f5df25 100755 --- a/examples/nodejs_state.js +++ b/examples/nodejs_state.js @@ -1,8 +1,10 @@ #!/usr/bin/env node "use strict"; -var fs = require("fs"); -var V86 = require("../build/libv86.js").V86; +import fs from "node:fs"; +import url from "node:url"; +var V86 = await import("../build/libv86.js").V86; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); function readfile(path) { diff --git a/examples/worker.js b/examples/worker.js index 90760064..b438d49e 100644 --- a/examples/worker.js +++ b/examples/worker.js @@ -1,5 +1,7 @@ importScripts("../build/libv86.js"); +/* global V86 */ + var emulator = new V86({ wasm_path: "../build/v86.wasm", memory_size: 32 * 1024 * 1024, diff --git a/gen/generate_analyzer.js b/gen/generate_analyzer.js index de31a8c3..103e2a31 100755 --- a/gen/generate_analyzer.js +++ b/gen/generate_analyzer.js @@ -1,13 +1,16 @@ #!/usr/bin/env node "use strict"; -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); -const x86_table = require("./x86_table"); -const rust_ast = require("./rust_ast"); -const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util"); +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import x86_table from "./x86_table.js"; +const rust_ast = await import("./rust_ast.js"); +const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = await import("./util.js"); + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/"); mkdirpSync(OUT_DIR); diff --git a/gen/generate_interpreter.js b/gen/generate_interpreter.js index 8c09eddf..8015d0da 100755 --- a/gen/generate_interpreter.js +++ b/gen/generate_interpreter.js @@ -1,13 +1,16 @@ #!/usr/bin/env node "use strict"; -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); -const x86_table = require("./x86_table"); -const rust_ast = require("./rust_ast"); -const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util"); +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import x86_table from "./x86_table.js"; +const rust_ast = await import("./rust_ast.js"); +const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = await import("./util.js"); + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/"); mkdirpSync(OUT_DIR); diff --git a/gen/generate_jit.js b/gen/generate_jit.js index 104f0598..b237a368 100755 --- a/gen/generate_jit.js +++ b/gen/generate_jit.js @@ -1,15 +1,17 @@ #!/usr/bin/env node "use strict"; -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); -const x86_table = require("./x86_table"); -const rust_ast = require("./rust_ast"); -const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util"); +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import x86_table from "./x86_table.js"; +const rust_ast = await import("./rust_ast.js"); +const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = await import("./util.js"); + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/"); - mkdirpSync(OUT_DIR); const table_arg = get_switch_value("--table"); diff --git a/gen/rust_ast.js b/gen/rust_ast.js index fb4f2e98..7d50cd55 100644 --- a/gen/rust_ast.js +++ b/gen/rust_ast.js @@ -1,13 +1,13 @@ "use strict"; -const assert = require("assert").strict; +import assert from "node:assert/strict"; function indent(lines, how_much) { return lines.map(line => " ".repeat(how_much) + line); } -function print_syntax_tree(statements) +export function print_syntax_tree(statements) { let code = []; @@ -77,7 +77,3 @@ function print_syntax_tree(statements) return code; } - -module.exports = { - print_syntax_tree, -}; diff --git a/gen/util.js b/gen/util.js index 9325428c..a01a8eda 100644 --- a/gen/util.js +++ b/gen/util.js @@ -1,14 +1,13 @@ "use strict"; -const assert = require("assert"); -const fs = require("fs"); -const path = require("path"); -const process = require("process"); -const child_process = require("child_process"); +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + const CYAN_FMT = "\x1b[36m%s\x1b[0m"; -function hex(n, pad) +export function hex(n, pad) { pad = pad || 0; let s = n.toString(16).toUpperCase(); @@ -16,12 +15,12 @@ function hex(n, pad) return s; } -function mkdirpSync(dir) +export function mkdirpSync(dir) { fs.mkdirSync(dir, { recursive: true }); } -function get_switch_value(arg_switch) +export function get_switch_value(arg_switch) { const argv = process.argv; const switch_i = argv.indexOf(arg_switch); @@ -33,22 +32,14 @@ function get_switch_value(arg_switch) return null; } -function get_switch_exist(arg_switch) +export function get_switch_exist(arg_switch) { return process.argv.includes(arg_switch); } -function finalize_table_rust(out_dir, name, contents) +export function finalize_table_rust(out_dir, name, contents) { const file_path = path.join(out_dir, name); fs.writeFileSync(file_path, contents); console.log(CYAN_FMT, `[+] Wrote table ${name}.`); } - -module.exports = { - hex, - mkdirpSync, - get_switch_value, - get_switch_exist, - finalize_table_rust, -}; diff --git a/gen/x86_table.js b/gen/x86_table.js index e6663a0c..5325b4f6 100644 --- a/gen/x86_table.js +++ b/gen/x86_table.js @@ -1,6 +1,6 @@ "use strict"; -const { hex } = require("./util"); +const { hex } = await import("./util.js"); // http://ref.x86asm.net/coder32.html @@ -875,4 +875,5 @@ encodings.sort((e1, e2) => { return o1 - o2 || e1.fixed_g - e2.fixed_g; }); -module.exports = Object.freeze(encodings.map(entry => Object.freeze(entry))); +const result = Object.freeze(encodings.map(entry => Object.freeze(entry))); +export default result; diff --git a/lib/9p.js b/lib/9p.js index 27b39836..c988d43d 100644 --- a/lib/9p.js +++ b/lib/9p.js @@ -6,6 +6,21 @@ "use strict"; +import { TRACK_FILENAMES } from "../src/config.js"; +import { VirtIO, VIRTIO_F_VERSION_1, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC } from "../src/virtio.js"; +import { S_IFREG, S_IFDIR, STATUS_UNLINKED } from "./filesystem.js"; +import { hex8, message } from "./jor1k.js"; +import { marshall, texten } from "./marshall.js"; +import { range } from "../src/lib.js"; +import { dbg_assert } from "../src/log.js"; + + +// For Types Only +import { CPU } from "../src/cpu.js"; +import { BusConnector } from "../src/bus.js"; +import { FS } from "./filesystem.js"; + + // Feature bit (bit position) for mount tag. const VIRTIO_9P_F_MOUNT_TAG = 0; // Assumed max tag length in bytes. @@ -16,13 +31,13 @@ const MAX_REPLYBUFFER_SIZE = 16 * 1024 * 1024; // TODO // flush -var EPERM = 1; /* Operation not permitted */ -var ENOENT = 2; /* No such file or directory */ -var EEXIST = 17; /* File exists */ -var EINVAL = 22; /* Invalid argument */ -var EOPNOTSUPP = 95; /* Operation is not supported */ -var ENOTEMPTY = 39; /* Directory not empty */ -var EPROTO = 71; /* Protocol error */ +export const EPERM = 1; /* Operation not permitted */ +export const ENOENT = 2; /* No such file or directory */ +export const EEXIST = 17; /* File exists */ +export const EINVAL = 22; /* Invalid argument */ +export const EOPNOTSUPP = 95; /* Operation is not supported */ +export const ENOTEMPTY = 39; /* Directory not empty */ +export const EPROTO = 71; /* Protocol error */ var P9_SETATTR_MODE = 0x00000001; var P9_SETATTR_UID = 0x00000002; @@ -49,18 +64,18 @@ var P9_STAT_MODE_SETUID = 0x00080000; var P9_STAT_MODE_SETGID = 0x00040000; var P9_STAT_MODE_SETVTX = 0x00010000; -const P9_LOCK_TYPE_RDLCK = 0; -const P9_LOCK_TYPE_WRLCK = 1; -const P9_LOCK_TYPE_UNLCK = 2; +export const P9_LOCK_TYPE_RDLCK = 0; +export const P9_LOCK_TYPE_WRLCK = 1; +export const P9_LOCK_TYPE_UNLCK = 2; const P9_LOCK_TYPES = ["shared", "exclusive", "unlock"]; const P9_LOCK_FLAGS_BLOCK = 1; const P9_LOCK_FLAGS_RECLAIM = 2; -const P9_LOCK_SUCCESS = 0; -const P9_LOCK_BLOCKED = 1; -const P9_LOCK_ERROR = 2; -const P9_LOCK_GRACE = 3; +export const P9_LOCK_SUCCESS = 0; +export const P9_LOCK_BLOCKED = 1; +export const P9_LOCK_ERROR = 2; +export const P9_LOCK_GRACE = 3; var FID_NONE = -1; var FID_INODE = 1; @@ -72,7 +87,7 @@ var FID_XATTR = 2; * @param {FS} filesystem * @param {CPU} cpu */ -function Virtio9p(filesystem, cpu, bus) { +export function Virtio9p(filesystem, cpu, bus) { /** @type {FS} */ this.fs = filesystem; @@ -156,7 +171,7 @@ function Virtio9p(filesystem, cpu, bus) { read: () => this.configspace_taglen, write: data => { /* read only */ }, }, - ].concat(v86util.range(VIRTIO_9P_MAX_TAGLEN).map(index => + ].concat(range(VIRTIO_9P_MAX_TAGLEN).map(index => ({ bytes: 1, name: "mount tag name " + index, diff --git a/lib/filesystem.js b/lib/filesystem.js index 46856e01..486f53d6 100644 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -5,14 +5,25 @@ "use strict"; -var S_IRWXUGO = 0x1FF; -var S_IFMT = 0xF000; -var S_IFSOCK = 0xC000; -var S_IFLNK = 0xA000; -var S_IFREG = 0x8000; -var S_IFBLK = 0x6000; -var S_IFDIR = 0x4000; -var S_IFCHR = 0x2000; +import { LOG_9P } from "../src/const.js"; +import { h } from "../src/lib.js"; +import { dbg_assert, dbg_log } from "../src/log.js"; +import { marshall, texten } from "../lib/marshall.js"; +import { message } from "./jor1k.js"; +import { EEXIST, ENOTEMPTY, ENOENT, EPERM } from "./9p.js"; +import { P9_LOCK_SUCCESS, P9_LOCK_BLOCKED, P9_LOCK_TYPE_UNLCK, P9_LOCK_TYPE_WRLCK, P9_LOCK_TYPE_RDLCK } from "./9p.js"; + +// For Types Only +import { FileStorageInterface } from "../src/browser/filestorage.js"; + +export const S_IRWXUGO = 0x1FF; +export const S_IFMT = 0xF000; +export const S_IFSOCK = 0xC000; +export const S_IFLNK = 0xA000; +export const S_IFREG = 0x8000; +export const S_IFBLK = 0x6000; +export const S_IFDIR = 0x4000; +export const S_IFCHR = 0x2000; //var S_IFIFO 0010000 //var S_ISUID 0004000 @@ -24,11 +35,11 @@ var O_WRONLY = 0x0001; // open for writing only var O_RDWR = 0x0002; // open for reading and writing var O_ACCMODE = 0x0003; // mask for above modes -var STATUS_INVALID = -0x1; -var STATUS_OK = 0x0; -var STATUS_ON_STORAGE = 0x2; -var STATUS_UNLINKED = 0x4; -var STATUS_FORWARDING = 0x5; +export const STATUS_INVALID = -0x1; +export const STATUS_OK = 0x0; +export const STATUS_ON_STORAGE = 0x2; +export const STATUS_UNLINKED = 0x4; +export const STATUS_FORWARDING = 0x5; /** @const */ var JSONFS_VERSION = 3; @@ -49,7 +60,7 @@ var STATUS_FORWARDING = 0x5; * @param {!FileStorageInterface} storage * @param {{ last_qidnumber: number }=} qidcounter Another fs's qidcounter to synchronise with. */ -function FS(storage, qidcounter) { +export function FS(storage, qidcounter) { /** @type {Array.} */ this.inodes = []; this.events = []; diff --git a/lib/jor1k.js b/lib/jor1k.js index 1b27112b..6114e13a 100644 --- a/lib/jor1k.js +++ b/lib/jor1k.js @@ -1,5 +1,10 @@ "use strict"; +import { LOG_9P } from "../src/const.js"; +import { h } from "../src/lib.js"; +import { dbg_log } from "../src/log.js"; + + // jor1k compatibility var VIRTIO_MAGIC_REG = 0x0; @@ -29,12 +34,12 @@ var VRING_DESC_F_WRITE = 2; /* This marks a buffer as write-only (otherwise var VRING_DESC_F_INDIRECT = 4; /* This means the buffer contains a list of buffer descriptors. */ -function hex8(n) +export function hex8(n) { return h(n); } -var message = {}; +export var message = {}; /** @param {...string} log */ message.Debug = function(log) @@ -92,7 +97,7 @@ else LoadBinaryResource = function(url, OnSuccess, OnError) { //console.log(url); - require("fs")["readFile"](url, function(err, data) + import("node:" + "fs").then(fs => fs["readFile"](url, function(err, data) { if(err) { @@ -102,6 +107,6 @@ else { OnSuccess(data.buffer); } - }); + })); }; } diff --git a/lib/marshall.js b/lib/marshall.js index 17fc0c46..926ba5af 100644 --- a/lib/marshall.js +++ b/lib/marshall.js @@ -5,10 +5,12 @@ "use strict"; -var marshall = {}; +import { message } from "./jor1k.js"; -const textde = new TextDecoder(); -const texten = new TextEncoder(); +export var marshall = {}; + +export const textde = new TextDecoder(); +export const texten = new TextEncoder(); // Inserts data from an array to a byte aligned struct in memory marshall.Marshall = function(typelist, input, struct, offset) { diff --git a/nodejs-loader.mjs b/nodejs-loader.mjs index 1694d9d9..8e05d6e5 100644 --- a/nodejs-loader.mjs +++ b/nodejs-loader.mjs @@ -1,97 +1,5 @@ -import vm from "node:vm"; -import url from "node:url"; -import fs from "node:fs"; -import path from "node:path"; -import crypto from "node:crypto"; -import perf_hooks from "node:perf_hooks"; -const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); - -let files = [ - "src/const.js", - "src/config.js", - "src/log.js", - "src/cpu.js", - "src/debug.js", - "src/io.js", - "src/main.js", - "src/lib.js", - "src/buffer.js", - "src/ide.js", - "src/pci.js", - "src/floppy.js", - "src/memory.js", - "src/dma.js", - "src/pit.js", - "src/vga.js", - "src/ps2.js", - - "src/rtc.js", - "src/uart.js", - - "src/acpi.js", - "src/apic.js", - "src/ioapic.js", - - "src/state.js", - "src/ne2k.js", - "src/sb16.js", - "src/virtio.js", - "src/virtio_console.js", - "src/virtio_net.js", - "src/virtio_balloon.js", - "src/bus.js", - - "src/debug.js", - "src/elf.js", - "src/kernel.js", - - "lib/9p.js", - "lib/filesystem.js", - "lib/jor1k.js", - "lib/marshall.js", - - "src/browser/screen.js", - "src/browser/keyboard.js", - "src/browser/mouse.js", - "src/browser/speaker.js", - "src/browser/serial.js", - "src/browser/network.js", - "src/browser/fake_network.js", - "src/browser/fetch_network.js", - "src/browser/starter.js", - "src/browser/worker_bus.js", - "src/browser/dummy_screen.js", - "src/browser/print_stats.js", - "src/browser/filestorage.js" -]; - - -let globals = Object.create(globalThis); -let v86 = {}; - -let ctx = vm.createContext(globals); -globals.DEBUG = false; -globals.module = {exports:v86}; -Object.defineProperty(globals, "crypto", {value: crypto}); -globals.require = (what) => { - return ({ - perf_hooks, - fs - })[what]; -}; - -for( let f of files ) { - vm.runInContext(fs.readFileSync(path.join(__dirname, f), "utf8"), ctx, { - filename: f - }); -} - -export let { - FetchNetworkAdapter, - MemoryFileStorage, - ServerFileStorageWrapper, -} = globals; - -export default globals.V86; +globalThis.DEBUG = true; +var V86 = await import("./src/browser/starter.js"); +export default V86.V86; diff --git a/package.json b/package.json index 733a00f4..fc4415b5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build/*.mjs", "build/v86*.wasm" ], - "main": "build/libv86.js", - "repository": "github:copy/v86" + "main": "build/libv86.mjs", + "repository": "github:copy/v86", + "type": "module" } diff --git a/src/acpi.js b/src/acpi.js index daace1df..00106e48 100644 --- a/src/acpi.js +++ b/src/acpi.js @@ -2,14 +2,22 @@ // http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf +import { v86 } from "./main.js"; +import { LOG_ACPI } from "../src/const.js"; +import { h } from "./lib.js"; +import { dbg_log, dbg_assert } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; + /** @const */ -var PMTIMER_FREQ_SECONDS = 3579545; +export const PMTIMER_FREQ_SECONDS = 3579545; /** * @constructor * @param {CPU} cpu */ -function ACPI(cpu) +export function ACPI(cpu) { /** @type {CPU} */ this.cpu = cpu; diff --git a/src/apic.js b/src/apic.js index df2561ec..564face7 100644 --- a/src/apic.js +++ b/src/apic.js @@ -2,9 +2,18 @@ // See Intel's System Programming Guide +import { v86 } from "./main.js"; +import { LOG_APIC } from "../src/const.js"; +import { APIC_TIMER_FREQ } from "./config.js"; +import { h, int_log2 } from "./lib.js"; +import { dbg_assert, dbg_log, dbg_trace } from "./log.js"; +import { IOAPIC_CONFIG_MASKED, IOAPIC_DELIVERY_INIT, IOAPIC_DELIVERY_NMI, IOAPIC_DELIVERY_FIXED } from "./ioapic.js"; + +// For Types Only +import { CPU } from "./cpu.js"; /** @const */ -var APIC_LOG_VERBOSE = false; +export const APIC_LOG_VERBOSE = false; /** @const */ var APIC_ADDRESS = 0xFEE00000; @@ -23,7 +32,7 @@ var APIC_TIMER_MODE_TSC = 2 << 17; /** @const */ -var DELIVERY_MODES = [ +export const DELIVERY_MODES = [ "Fixed (0)", "Lowest Prio (1)", "SMI (2)", @@ -35,13 +44,14 @@ var DELIVERY_MODES = [ ]; /** @const */ -var DESTINATION_MODES = ["physical", "logical"]; +export const DESTINATION_MODES = ["physical", "logical"]; /** * @constructor * @param {CPU} cpu */ +export function APIC(cpu) { /** @type {CPU} */ @@ -640,7 +650,7 @@ APIC.prototype.register_get_highest_bit = function(v) if(word) { - return v86util.int_log2(word >>> 0) | i << 5; + return int_log2(word >>> 0) | i << 5; } } diff --git a/src/browser/dummy_screen.js b/src/browser/dummy_screen.js index 405dd818..6039d961 100644 --- a/src/browser/dummy_screen.js +++ b/src/browser/dummy_screen.js @@ -1,9 +1,11 @@ "use strict"; +import { dbg_assert } from "../log.js"; + /** * @constructor */ -function DummyScreenAdapter() +export function DummyScreenAdapter() { var graphic_image_data, diff --git a/src/browser/fake_network.js b/src/browser/fake_network.js index eee37e6c..8b1290e3 100644 --- a/src/browser/fake_network.js +++ b/src/browser/fake_network.js @@ -1,5 +1,9 @@ "use strict"; +import { LOG_FETCH } from "../const.js"; +import { h } from "../lib.js"; +import { dbg_assert, dbg_log } from "../log.js"; + // https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml const ETHERTYPE_IPV4 = 0x0800; const ETHERTYPE_ARP = 0x0806; @@ -23,17 +27,17 @@ const V86_ASCII = [118, 56, 54]; * * State TIME_WAIT is not needed, we can skip it and transition directly to CLOSED instead. */ -const TCP_STATE_CLOSED = "closed"; -const TCP_STATE_SYN_RECEIVED = "syn-received"; -const TCP_STATE_SYN_SENT = "syn-sent"; -const TCP_STATE_SYN_PROBE = "syn-probe"; +export const TCP_STATE_CLOSED = "closed"; +export const TCP_STATE_SYN_RECEIVED = "syn-received"; +export const TCP_STATE_SYN_SENT = "syn-sent"; +export const TCP_STATE_SYN_PROBE = "syn-probe"; //const TCP_STATE_LISTEN = "listen"; -const TCP_STATE_ESTABLISHED = "established"; -const TCP_STATE_FIN_WAIT_1 = "fin-wait-1"; -const TCP_STATE_CLOSE_WAIT = "close-wait"; -const TCP_STATE_FIN_WAIT_2 = "fin-wait-2"; -const TCP_STATE_LAST_ACK = "last-ack"; -const TCP_STATE_CLOSING = "closing"; +export const TCP_STATE_ESTABLISHED = "established"; +export const TCP_STATE_FIN_WAIT_1 = "fin-wait-1"; +export const TCP_STATE_CLOSE_WAIT = "close-wait"; +export const TCP_STATE_FIN_WAIT_2 = "fin-wait-2"; +export const TCP_STATE_LAST_ACK = "last-ack"; +export const TCP_STATE_CLOSING = "closing"; //const TCP_STATE_TIME_WAIT = "time-wait"; // source: RFC6335, 6. Port Number Ranges @@ -158,7 +162,7 @@ class GrowableRingbuffer } } -function create_eth_encoder_buf() +export function create_eth_encoder_buf() { const eth_frame = new Uint8Array(ETH_FRAME_SIZE); const buffer = eth_frame.buffer; @@ -445,7 +449,7 @@ function handle_fake_dhcp(packet, adapter) { adapter.receive(make_packet(adapter.eth_encoder_buf, reply)); } -function handle_fake_networking(data, adapter) { +export function handle_fake_networking(data, adapter) { let packet = {}; parse_eth(data, packet); @@ -974,7 +978,7 @@ function write_tcp(spec, out) { return total_length; } -function fake_tcp_connect(dport, adapter) +export function fake_tcp_connect(dport, adapter) { const vm_ip_str = adapter.vm_ip.join("."); const router_ip_str = adapter.router_ip.join("."); @@ -1003,7 +1007,7 @@ function fake_tcp_connect(dport, adapter) return conn; } -function fake_tcp_probe(dport, adapter) { +export function fake_tcp_probe(dport, adapter) { return new Promise((res, rej) => { let handle = fake_tcp_connect(dport, adapter); handle.state = TCP_STATE_SYN_PROBE; @@ -1014,7 +1018,7 @@ function fake_tcp_probe(dport, adapter) { /** * @constructor */ -function TCPConnection() +export function TCPConnection() { this.state = TCP_STATE_CLOSED; this.net = null; // The adapter is stored here diff --git a/src/browser/fetch_network.js b/src/browser/fetch_network.js index ecfdc92d..250d144b 100644 --- a/src/browser/fetch_network.js +++ b/src/browser/fetch_network.js @@ -1,5 +1,21 @@ "use strict"; +import { LOG_FETCH } from "../const.js"; +import { h } from "../lib.js"; +import { dbg_log } from "../log.js"; + +import { + create_eth_encoder_buf, + handle_fake_networking, + TCPConnection, + TCP_STATE_SYN_RECEIVED, + fake_tcp_connect, + fake_tcp_probe +} from "./fake_network.js"; + +// For Types Only +import { BusConnector } from "../bus.js"; + /** * @constructor * @@ -7,7 +23,7 @@ * @param {*=} config * @export */ -function FetchNetworkAdapter(bus, config) +export function FetchNetworkAdapter(bus, config) { config = config || {}; this.bus = bus; diff --git a/src/browser/filestorage.js b/src/browser/filestorage.js index 773cb69e..2cfd8fdd 100644 --- a/src/browser/filestorage.js +++ b/src/browser/filestorage.js @@ -1,7 +1,11 @@ "use strict"; + +import { dbg_assert } from "../log.js"; +import { load_file } from "../lib.js"; + /** @interface */ -function FileStorageInterface() {} +export function FileStorageInterface() {} /** * Read a portion of a file. @@ -31,7 +35,7 @@ FileStorageInterface.prototype.uncache = function(sha256sum) {}; * @constructor * @implements {FileStorageInterface} */ -function MemoryFileStorage() +export function MemoryFileStorage() { /** * From sha256sum to file data. @@ -83,7 +87,7 @@ MemoryFileStorage.prototype.uncache = function(sha256sum) * @param {FileStorageInterface} file_storage * @param {string} baseurl */ -function ServerFileStorageWrapper(file_storage, baseurl) +export function ServerFileStorageWrapper(file_storage, baseurl) { dbg_assert(baseurl, "ServerMemoryFileStorage: baseurl should not be empty"); @@ -104,7 +108,7 @@ ServerFileStorageWrapper.prototype.load_from_server = function(sha256sum) { return new Promise((resolve, reject) => { - v86util.load_file(this.baseurl + sha256sum, { done: async buffer => + load_file(this.baseurl + sha256sum, { done: async buffer => { const data = new Uint8Array(buffer); await this.cache(sha256sum, data); diff --git a/src/browser/inbrowser_network.js b/src/browser/inbrowser_network.js index 90541430..9144eef1 100644 --- a/src/browser/inbrowser_network.js +++ b/src/browser/inbrowser_network.js @@ -1,5 +1,9 @@ "use strict"; + +// For Types Only +import { BusConnector } from "../bus.js"; + /** * Network adapter "inbrowser" which connects the emulated NIC * to a shared in-browser BroadcastChannel. @@ -16,7 +20,7 @@ * @param {BusConnector} bus * @param {*=} config */ -function InBrowserNetworkAdapter(bus, config) +export function InBrowserNetworkAdapter(bus, config) { const id = config.id || 0; diff --git a/src/browser/keyboard.js b/src/browser/keyboard.js index 0ef6e073..1f47bf2e 100644 --- a/src/browser/keyboard.js +++ b/src/browser/keyboard.js @@ -1,5 +1,8 @@ "use strict"; +// For Types Only +import { BusConnector } from "../bus.js"; + /** @const */ var SHIFT_SCAN_CODE = 0x2A; @@ -14,7 +17,7 @@ const PLATFOM_WINDOWS = typeof window !== "undefined" && window.navigator.platfo * * @param {BusConnector} bus */ -function KeyboardAdapter(bus) +export function KeyboardAdapter(bus) { var /** diff --git a/src/browser/main.js b/src/browser/main.js index b1d5bbb3..0ac1db1a 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -1,7 +1,14 @@ "use strict"; -(function() -{ +import { V86 } from "./starter.js"; +import { LOG_NAMES } from "../const.js"; +import { LOG_LEVEL, setLogLevel } from "../config.js"; +import { print_stats } from "./print_stats.js"; +import { SyncFileBuffer } from "../buffer.js"; +import { pad0, pads, hex_dump, dump_file, download, round_up_to_next_power_of_2 } from "../lib.js"; +import { log_data } from "../log.js"; + + const ON_LOCALHOST = !location.hostname.endsWith("copy.sh"); const DEFAULT_NETWORKING_PROXIES = ["wss://relay.widgetry.org/", "ws://localhost:8080/"]; @@ -29,13 +36,13 @@ } else if(time < 3600) { - return (time / 60 | 0) + "m " + v86util.pad0(time % 60, 2) + "s"; + return (time / 60 | 0) + "m " + pad0(time % 60, 2) + "s"; } else { return (time / 3600 | 0) + "h " + - v86util.pad0((time / 60 | 0) % 60, 2) + "m " + - v86util.pad0(time % 60, 2) + "s"; + pad0((time / 60 | 0) % 60, 2) + "m " + + pad0(time % 60, 2) + "s"; } } @@ -1659,7 +1666,7 @@ } input.mask = mask; - label.append(input, v86util.pads(name, 4) + " "); + label.append(input, pads(name, 4) + " "); log_levels.appendChild(label); if(i === Math.floor(LOG_NAMES.length / 2)) @@ -1675,11 +1682,11 @@ if(target.checked) { - LOG_LEVEL |= mask; + setLogLevel(LOG_LEVEL | mask); } else { - LOG_LEVEL &= ~mask; + setLogLevel(LOG_LEVEL & ~mask); } target.blur(); @@ -1765,7 +1772,7 @@ if(chunk_size >= 0) { chunk_size = Math.min(4 * 1024 * 1024, Math.max(512, chunk_size)); - chunk_size = v86util.round_up_to_next_power_of_2(chunk_size); + chunk_size = round_up_to_next_power_of_2(chunk_size); } else { @@ -2384,6 +2391,9 @@ // $("memory_dump_dmp").blur(); //}; + /** + * @this HTMLElement + */ $("capture_network_traffic").onclick = function() { this.value = "0 packets"; @@ -2427,6 +2437,9 @@ $("load_state").blur(); }; + /** + * @this HTMLElement + */ $("load_state_input").onchange = async function() { var file = this.files[0]; @@ -2501,6 +2514,9 @@ $("alttab").blur(); }; + /** + * @this HTMLElement + */ $("scale").onchange = function() { var n = parseFloat(this.value); @@ -2627,11 +2643,14 @@ { $("filesystem_panel").style.display = "block"; + /** + * @this HTMLElement + */ $("filesystem_send_file").onchange = function() { Array.prototype.forEach.call(this.files, function(file) { - var loader = new v86util.SyncFileBuffer(file); + var loader = new SyncFileBuffer(file); loader.onload = function() { loader.get_buffer(async function(buffer) @@ -2646,6 +2665,9 @@ this.blur(); }; + /** + * @this HTMLElement + */ $("filesystem_get_file").onkeypress = async function(e) { if(e.which !== 13) @@ -2731,5 +2753,3 @@ window.history.pushState({ search }, "", search); } } - -})(); diff --git a/src/browser/mouse.js b/src/browser/mouse.js index d4f5c9cb..eb071ae2 100644 --- a/src/browser/mouse.js +++ b/src/browser/mouse.js @@ -1,11 +1,17 @@ "use strict"; + +import { dbg_log } from "../log.js"; + +// For Types Only +import { BusConnector } from "../bus.js"; + /** * @constructor * * @param {BusConnector} bus */ -function MouseAdapter(bus, screen_container) +export function MouseAdapter(bus, screen_container) { /** @const */ var SPEED_FACTOR = 0.15; diff --git a/src/browser/network.js b/src/browser/network.js index 22d58f26..4ee59d6d 100644 --- a/src/browser/network.js +++ b/src/browser/network.js @@ -1,5 +1,8 @@ "use strict"; +// For Types Only +import { BusConnector } from "../bus.js"; + /** * An ethernet-through-websocket adapter, to be used with * https://github.com/benjamincburns/websockproxy @@ -12,7 +15,7 @@ * @param {BusConnector} bus * @param {number} [id=0] id */ -function NetworkAdapter(url, bus, id) +export function NetworkAdapter(url, bus, id) { this.bus = bus; this.socket = undefined; diff --git a/src/browser/print_stats.js b/src/browser/print_stats.js index 4a5f3dc7..033cbe48 100644 --- a/src/browser/print_stats.js +++ b/src/browser/print_stats.js @@ -1,9 +1,11 @@ "use strict"; +import { pads } from "../lib.js"; + /** * @export */ -const print_stats = { +export const print_stats = { stats_to_string: function(cpu) { return print_stats.print_misc_stats(cpu) + @@ -251,7 +253,7 @@ const print_stats = { for(let i = 0; i < 0x100; i++) { - text += i.toString(16).padStart(2, "0") + ":" + v86util.pads(Math.round(per_opcode[i] / factor), pad_length); + text += i.toString(16).padStart(2, "0") + ":" + pads(Math.round(per_opcode[i] / factor), pad_length); if(i % 16 === 15) text += "\n"; @@ -264,7 +266,7 @@ const print_stats = { for(let i = 0; i < 0x100; i++) { - text += (i & 0xFF).toString(16).padStart(2, "0") + ":" + v86util.pads(Math.round(per_opcode0f[i] / factor), pad_length); + text += (i & 0xFF).toString(16).padStart(2, "0") + ":" + pads(Math.round(per_opcode0f[i] / factor), pad_length); if(i % 16 === 15) text += "\n"; diff --git a/src/browser/screen.js b/src/browser/screen.js index d207d443..3b963e67 100644 --- a/src/browser/screen.js +++ b/src/browser/screen.js @@ -1,11 +1,14 @@ "use strict"; +import { DEBUG_SCREEN_LAYERS } from "../config.js"; +import { dbg_assert } from "../log.js"; + /** * Adapter to use visual screen in browsers (in contrast to node) * @constructor * @param {Object} options */ -function ScreenAdapter(options, screen_fill_buffer) +export function ScreenAdapter(options, screen_fill_buffer) { const screen_container = options.container; this.screen_fill_buffer = screen_fill_buffer; diff --git a/src/browser/serial.js b/src/browser/serial.js index c5c59422..4d804195 100644 --- a/src/browser/serial.js +++ b/src/browser/serial.js @@ -1,11 +1,16 @@ "use strict"; +import { dbg_assert, dbg_log } from "../log.js"; + +// For Types Only +import { BusConnector } from "../bus.js"; + /** * @constructor * * @param {BusConnector} bus */ -function SerialAdapter(element, bus) +export function SerialAdapter(element, bus) { var serial = this; @@ -216,7 +221,7 @@ function SerialRecordingAdapter(bus) * @constructor * @param {BusConnector} bus */ -function SerialAdapterXtermJS(element, bus) +export function SerialAdapterXtermJS(element, bus) { this.element = element; diff --git a/src/browser/speaker.js b/src/browser/speaker.js index 44ab448c..2d29c10e 100644 --- a/src/browser/speaker.js +++ b/src/browser/speaker.js @@ -1,5 +1,18 @@ "use strict"; +import { + MIXER_CHANNEL_BOTH, MIXER_CHANNEL_LEFT, MIXER_CHANNEL_RIGHT, + MIXER_SRC_PCSPEAKER, MIXER_SRC_DAC, MIXER_SRC_MASTER, +} from "../const.js"; +import { dbg_assert, dbg_log } from "../log.js"; +import { OSCILLATOR_FREQ } from "../pit.js"; +import { dump_file } from "../lib.js"; + +// For Types Only +import { BusConnector } from "../bus.js"; + +/* global registerProcessor, sampleRate */ + /** @const */ var DAC_QUEUE_RESERVE = 0.2; @@ -10,7 +23,7 @@ var AUDIOBUFFER_MINIMUM_SAMPLING_RATE = 8000; * @constructor * @param {!BusConnector} bus */ -function SpeakerAdapter(bus) +export function SpeakerAdapter(bus) { if(typeof window === "undefined") { diff --git a/src/browser/starter.js b/src/browser/starter.js index 22591bd5..d7ad9a23 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -1,5 +1,36 @@ "use strict"; +import { v86 } from "../main.js"; +import { LOG_CPU, WASM_TABLE_OFFSET, WASM_TABLE_SIZE } from "../const.js"; +import { setLogLevel } from "../config.js"; +import { get_rand_int, load_file, read_sized_string_from_mem } from "../lib.js"; +import { dbg_assert, dbg_trace, dbg_log } from "../log.js"; +import { print_stats } from "./print_stats.js"; +import { Bus } from "../bus.js"; +import { BOOT_ORDER_FD_FIRST, BOOT_ORDER_HD_FIRST, BOOT_ORDER_CD_FIRST } from "../rtc.js"; + +import { SpeakerAdapter } from "./speaker.js"; +import { NetworkAdapter } from "./network.js"; +import { FetchNetworkAdapter } from "./fetch_network.js"; +import { WispNetworkAdapter } from "./wisp_network.js"; +import { KeyboardAdapter } from "./keyboard.js"; +import { MouseAdapter } from "./mouse.js"; +import { ScreenAdapter } from "./screen.js"; +import { DummyScreenAdapter } from "./dummy_screen.js"; +import { SerialAdapter, SerialAdapterXtermJS } from "./serial.js"; +import { InBrowserNetworkAdapter } from "./inbrowser_network.js"; + +import { MemoryFileStorage, ServerFileStorageWrapper } from "./filestorage.js"; +import { SyncBuffer, buffer_from_object } from "../buffer.js"; +import { FS } from "../../lib/filesystem.js"; +import { EEXIST, ENOENT } from "../../lib/9p.js"; + + +// Decorates CPU +import "../debug.js"; +import "../memory.js"; +import "../state.js"; + /** * Constructor for emulator instances. * @@ -107,12 +138,12 @@ * @constructor * @export */ -function V86(options) +export function V86(options) { if(typeof options.log_level === "number") { // XXX: Shared between all emulator instances - LOG_LEVEL = options.log_level; + setLogLevel(options.log_level); } //var worker = new Worker("src/browser/worker.js"); @@ -136,7 +167,7 @@ function V86(options) "cpu_event_halt": () => { this.emulator_bus.send("cpu-event-halt"); }, "abort": function() { dbg_assert(false); }, "microtick": v86.microtick, - "get_rand_int": function() { return v86util.get_rand_int(); }, + "get_rand_int": function() { return get_rand_int(); }, "apic_acknowledge_irq": function() { return cpu.devices.apic.acknowledge_irq(); }, "stop_idling": function() { return cpu.stop_idling(); }, @@ -159,11 +190,11 @@ function V86(options) }, "log_from_wasm": function(offset, len) { - const str = v86util.read_sized_string_from_mem(wasm_memory, offset, len); + const str = read_sized_string_from_mem(wasm_memory, offset, len); dbg_log(str, LOG_CPU); }, "console_log_from_wasm": function(offset, len) { - const str = v86util.read_sized_string_from_mem(wasm_memory, offset, len); + const str = read_sized_string_from_mem(wasm_memory, offset, len); console.error(str); }, "dbg_trace_from_wasm": function() { @@ -185,6 +216,8 @@ function V86(options) { wasm_fn = env => { + /* global __dirname */ + return new Promise(resolve => { let v86_bin = DEBUG ? "v86-debug.wasm" : "v86.wasm"; let v86_bin_fallback = "v86-fallback.wasm"; @@ -207,7 +240,7 @@ function V86(options) v86_bin_fallback = "build/" + v86_bin_fallback; } - v86util.load_file(v86_bin, { + load_file(v86_bin, { done: async bytes => { try @@ -218,7 +251,7 @@ function V86(options) } catch(err) { - v86util.load_file(v86_bin_fallback, { + load_file(v86_bin_fallback, { done: async bytes => { const { instance } = await WebAssembly.instantiate(bytes, env); this.wasm_source = bytes; @@ -471,7 +504,7 @@ V86.prototype.continue_init = async function(emulator, options) { files_to_load.push({ name, - loadable: v86util.buffer_from_object(file, this.zstd_decompress_worker.bind(this)), + loadable: buffer_from_object(file, this.zstd_decompress_worker.bind(this)), }); } }; @@ -552,7 +585,7 @@ V86.prototype.continue_init = async function(emulator, options) } else { - v86util.load_file(f.url, { + load_file(f.url, { done: function(result) { if(f.url.endsWith(".zst") && f.name !== "initial_state") @@ -561,7 +594,7 @@ V86.prototype.continue_init = async function(emulator, options) result = this.zstd_decompress(f.size, new Uint8Array(result)); } - put_on_settings.call(this, f.name, f.as_json ? result : new v86util.SyncBuffer(result)); + put_on_settings.call(this, f.name, f.as_json ? result : new SyncBuffer(result)); cont(index + 1); }.bind(this), progress: function progress(e) @@ -618,8 +651,8 @@ V86.prototype.continue_init = async function(emulator, options) settings.fs9p.read_file(initrd_path), settings.fs9p.read_file(bzimage_path), ]); - put_on_settings.call(this, "initrd", new v86util.SyncBuffer(initrd.buffer)); - put_on_settings.call(this, "bzimage", new v86util.SyncBuffer(bzimage.buffer)); + put_on_settings.call(this, "initrd", new SyncBuffer(initrd.buffer)); + put_on_settings.call(this, "bzimage", new SyncBuffer(bzimage.buffer)); } } else @@ -947,16 +980,16 @@ V86.prototype.set_fda = async function(file) { if(file.url && !file.async) { - v86util.load_file(file.url, { + load_file(file.url, { done: result => { - this.v86.cpu.devices.fdc.set_fda(new v86util.SyncBuffer(result)); + this.v86.cpu.devices.fdc.set_fda(new SyncBuffer(result)); }, }); } else { - const image = v86util.buffer_from_object(file, this.zstd_decompress_worker.bind(this)); + const image = buffer_from_object(file, this.zstd_decompress_worker.bind(this)); image.onload = () => { this.v86.cpu.devices.fdc.set_fda(image); @@ -1470,3 +1503,11 @@ function FileNotFoundError(message) this.message = message || "File not found"; } FileNotFoundError.prototype = Error.prototype; + +/* global module */ + +if(typeof module !== "undefined" && typeof module.exports !== "undefined") +{ + module.exports["V86"] = V86; + module.exports["print_stats"] = print_stats; +} diff --git a/src/browser/wisp_network.js b/src/browser/wisp_network.js index 2d07783f..99240b45 100644 --- a/src/browser/wisp_network.js +++ b/src/browser/wisp_network.js @@ -1,5 +1,18 @@ "use strict"; +import { LOG_NET } from "../const.js"; +import { dbg_log } from "../log.js"; + +import { + create_eth_encoder_buf, + handle_fake_networking, + TCPConnection, + TCP_STATE_SYN_RECEIVED, +} from "./fake_network.js"; + +// For Types Only +import { BusConnector } from "../bus.js"; + /** * @constructor * @@ -7,7 +20,7 @@ * @param {BusConnector} bus * @param {*=} config */ -function WispNetworkAdapter(wisp_url, bus, config) +export function WispNetworkAdapter(wisp_url, bus, config) { this.register_ws(wisp_url); this.last_stream = 1; diff --git a/src/browser/worker_bus.js b/src/browser/worker_bus.js index 23577231..3564d7c9 100644 --- a/src/browser/worker_bus.js +++ b/src/browser/worker_bus.js @@ -1,9 +1,9 @@ "use strict"; -var WorkerBus = {}; +import { dbg_assert } from "../log.js"; /** @constructor */ -WorkerBus.Connector = function(pair) +export var Connector = function(pair) { this.listeners = {}; this.pair = pair; @@ -22,7 +22,7 @@ WorkerBus.Connector = function(pair) }; -WorkerBus.Connector.prototype.register = function(name, fn, this_value) +Connector.prototype.register = function(name, fn, this_value) { var listeners = this.listeners[name]; @@ -44,7 +44,7 @@ WorkerBus.Connector.prototype.register = function(name, fn, this_value) * @param {*=} value * @param {*=} transfer_list */ -WorkerBus.Connector.prototype.send = function(name, value, transfer_list) +Connector.prototype.send = function(name, value, transfer_list) { dbg_assert(arguments.length >= 1); @@ -57,7 +57,7 @@ WorkerBus.Connector.prototype.send = function(name, value, transfer_list) }; -WorkerBus.init = function(worker) +export var init = function(worker) { - return new WorkerBus.Connector(worker); + return new Connector(worker); }; diff --git a/src/buffer.js b/src/buffer.js index 3d4382c2..403ad42a 100644 --- a/src/buffer.js +++ b/src/buffer.js @@ -1,14 +1,8 @@ "use strict"; -(function() -{ - v86util.SyncBuffer = SyncBuffer; - v86util.AsyncXHRBuffer = AsyncXHRBuffer; - v86util.AsyncXHRPartfileBuffer = AsyncXHRPartfileBuffer; - v86util.AsyncFileBuffer = AsyncFileBuffer; - v86util.SyncFileBuffer = SyncFileBuffer; - - v86util.buffer_from_object = buffer_from_object; +import { CPU } from "./cpu.js"; +import { load_file } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; // The smallest size the emulated hardware can emit const BLOCK_SIZE = 256; @@ -19,7 +13,7 @@ * Synchronous access to ArrayBuffer * @constructor */ - function SyncBuffer(buffer) + export function SyncBuffer(buffer) { dbg_assert(buffer instanceof ArrayBuffer); @@ -208,7 +202,7 @@ requested_length = Math.ceil((offset - requested_start + len) / this.fixed_chunk_size) * this.fixed_chunk_size; } - v86util.load_file(this.filename, { + load_file(this.filename, { done: function done(buffer) { var block = new Uint8Array(buffer); @@ -383,7 +377,7 @@ * @param {number|undefined} fixed_chunk_size * @param {boolean|undefined} partfile_alt_format */ - function AsyncXHRPartfileBuffer(filename, size, fixed_chunk_size, partfile_alt_format, zstd_decompress) + export function AsyncXHRPartfileBuffer(filename, size, fixed_chunk_size, partfile_alt_format, zstd_decompress) { const parts = filename.match(/\.[^\.]+(\.zst)?$/); @@ -484,7 +478,7 @@ } else { - v86util.load_file(part_filename, { + load_file(part_filename, { done: async function done(buffer) { let block = new Uint8Array(buffer); @@ -512,7 +506,7 @@ { const part_filename = this.basename + offset + "-" + (offset + len) + this.extension; - v86util.load_file(part_filename, { + load_file(part_filename, { done: function done(buffer) { dbg_assert(buffer.byteLength === len); @@ -537,7 +531,7 @@ * * @constructor */ - function SyncFileBuffer(file) + export function SyncFileBuffer(file) { this.file = file; this.byteLength = file.size; @@ -608,7 +602,7 @@ * * @constructor */ - function AsyncFileBuffer(file) + export function AsyncFileBuffer(file) { this.file = file; this.byteLength = file.size; @@ -703,11 +697,12 @@ return file; }; + var determine_size; if(typeof XMLHttpRequest === "undefined") { - var determine_size = function(path, cb) + determine_size = function(path, cb) { - require("fs")["stat"](path, (err, stats) => + import("node:" + "fs").then(fs => fs["stat"](path, (err, stats) => { if(err) { @@ -717,14 +712,14 @@ { cb(null, stats.size); } - }); + })); }; } else { - var determine_size = function(url, cb) + determine_size = function(url, cb) { - v86util.load_file(url, { + load_file(url, { done: (buffer, http) => { var header = http.getResponseHeader("Content-Range") || ""; @@ -748,13 +743,13 @@ }; } - function buffer_from_object(obj, zstd_decompress_worker) + export function buffer_from_object(obj, zstd_decompress_worker) { // TODO: accept Uint8Array, ArrayBuffer, File, url rather than { url } if(obj.buffer instanceof ArrayBuffer) { - return new v86util.SyncBuffer(obj.buffer); + return new SyncBuffer(obj.buffer); } else if(typeof File !== "undefined" && obj.buffer instanceof File) { @@ -776,11 +771,11 @@ if(is_async) { - return new v86util.AsyncFileBuffer(obj.buffer); + return new AsyncFileBuffer(obj.buffer); } else { - return new v86util.SyncFileBuffer(obj.buffer); + return new SyncFileBuffer(obj.buffer); } } else if(obj.url) @@ -789,11 +784,11 @@ if(obj.use_parts) { - return new v86util.AsyncXHRPartfileBuffer(obj.url, obj.size, obj.fixed_chunk_size, false, zstd_decompress_worker); + return new AsyncXHRPartfileBuffer(obj.url, obj.size, obj.fixed_chunk_size, false, zstd_decompress_worker); } else { - return new v86util.AsyncXHRBuffer(obj.url, obj.size, obj.fixed_chunk_size); + return new AsyncXHRBuffer(obj.url, obj.size, obj.fixed_chunk_size); } } else @@ -801,4 +796,3 @@ dbg_log("Ignored file: url=" + obj.url + " buffer=" + obj.buffer); } } -})(); diff --git a/src/bus.js b/src/bus.js index da718756..07ce172b 100644 --- a/src/bus.js +++ b/src/bus.js @@ -1,9 +1,11 @@ "use strict"; -var Bus = {}; +import { dbg_assert } from "./log.js"; + +export var Bus = {}; /** @constructor */ -function BusConnector() +export function BusConnector() { this.listeners = {}; this.pair = undefined; diff --git a/src/cjs.js b/src/cjs.js new file mode 100644 index 00000000..845072c4 --- /dev/null +++ b/src/cjs.js @@ -0,0 +1,27 @@ +"use strict"; + +/* global module, self */ + +var goog = goog || {}; +goog.exportSymbol = function(name, sym) { + if(typeof module !== "undefined" && typeof module.exports !== "undefined") + { + module.exports[name] = sym; + } + else if(typeof window !== "undefined") + { + window[name] = sym; + } + else if(typeof importScripts === "function") + { + // web worker + self[name] = sym; + } +}; +goog.exportProperty = function() {}; + +/** + * @define {boolean} + * Overridden for production by closure compiler + */ + var DEBUG = true; diff --git a/src/config.js b/src/config.js index 888a6fc5..a0ae8e12 100644 --- a/src/config.js +++ b/src/config.js @@ -3,51 +3,54 @@ * Compile time configuration, some only relevant for debug mode */ -/** - * @define {boolean} - * Overridden for production by closure compiler - */ -var DEBUG = true; +import { + LOG_ALL, LOG_PS2, LOG_PIT, LOG_9P, LOG_PIC, LOG_DMA, LOG_NET, LOG_FLOPPY, LOG_DISK, + LOG_SERIAL, LOG_VGA, LOG_SB16, LOG_VIRTIO +} from "./const.js"; /** @const */ -var LOG_TO_FILE = false; +export var LOG_TO_FILE = false; /** * @const * Enables logging all IO port reads and writes. Very verbose */ -var LOG_ALL_IO = false; +export var LOG_ALL_IO = false; /** * @const */ -var DUMP_GENERATED_WASM = false; +export var DUMP_GENERATED_WASM = false; /** * @const */ -var DUMP_UNCOMPILED_ASSEMBLY = false; +export var DUMP_UNCOMPILED_ASSEMBLY = false; /** * @const * More accurate filenames in 9p debug messages at the cost of performance. */ -var TRACK_FILENAMES = false; +export var TRACK_FILENAMES = false; -var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & +export var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; + +export function setLogLevel(level) { + LOG_LEVEL = level; +} /** * @const * Draws entire buffer and visualizes the layers that would be drawn */ -var DEBUG_SCREEN_LAYERS = DEBUG && false; +export var DEBUG_SCREEN_LAYERS = DEBUG && false; /** * @const * How many ticks the TSC does per millisecond */ -var TSC_RATE = 1 * 1000 * 1000; +export var TSC_RATE = 1 * 1000 * 1000; /** @const */ -var APIC_TIMER_FREQ = TSC_RATE; +export var APIC_TIMER_FREQ = TSC_RATE; diff --git a/src/const.js b/src/const.js index 775dada4..8d60ab33 100644 --- a/src/const.js +++ b/src/const.js @@ -1,6 +1,6 @@ "use strict"; -var +export const /** @const */ LOG_ALL = -1, /** @const */ LOG_NONE = 0, @@ -35,7 +35,7 @@ var * @const * @type {Array>} */ -var LOG_NAMES = [ +export const LOG_NAMES = [ [1, ""], [LOG_CPU, "CPU"], [LOG_DISK, "DISK"], @@ -62,7 +62,7 @@ var LOG_NAMES = [ [LOG_FETCH, "FETC"], ]; -var +export const // flags register bitflags /** @const */ FLAG_CARRY = 1, @@ -108,7 +108,7 @@ FLAGS_DEFAULT = 1 << 1, /** @const */ REG_LDTR = 7; // local descriptor table register -var +export const /** * The minimum number of bytes that can be memory-mapped * by one device. @@ -122,45 +122,45 @@ var MMAP_MAX = 0x100000000; /** @const */ -var CR0_PG = 1 << 31; +export const CR0_PG = 1 << 31; /** @const */ -var CR4_PAE = 1 << 5; +export const CR4_PAE = 1 << 5; // https://github.com/qemu/seabios/blob/14221cd86eadba82255fdc55ed174d401c7a0a04/src/fw/paravirt.c#L205-L219 -/** @const */ var FW_CFG_SIGNATURE = 0x00; -/** @const */ var FW_CFG_ID = 0x01; -/** @const */ var FW_CFG_RAM_SIZE = 0x03; -/** @const */ var FW_CFG_NB_CPUS = 0x05; -/** @const */ var FW_CFG_MAX_CPUS = 0x0F; -/** @const */ var FW_CFG_NUMA = 0x0D; -/** @const */ var FW_CFG_FILE_DIR = 0x19; +/** @const */ export const FW_CFG_SIGNATURE = 0x00; +/** @const */ export const FW_CFG_ID = 0x01; +/** @const */ export const FW_CFG_RAM_SIZE = 0x03; +/** @const */ export const FW_CFG_NB_CPUS = 0x05; +/** @const */ export const FW_CFG_MAX_CPUS = 0x0F; +/** @const */ export const FW_CFG_NUMA = 0x0D; +/** @const */ export const FW_CFG_FILE_DIR = 0x19; -/** @const */ var FW_CFG_CUSTOM_START = 0x8000; +/** @const */ export const FW_CFG_CUSTOM_START = 0x8000; // This value is specific to v86, choosen to hopefully not collide with other indexes -/** @const */ var FW_CFG_FILE_START = 0xC000; +/** @const */ export const FW_CFG_FILE_START = 0xC000; -/** @const */ var FW_CFG_SIGNATURE_QEMU = 0x554D4551; +/** @const */ export const FW_CFG_SIGNATURE_QEMU = 0x554D4551; // See same constant in jit.rs /** @const */ -var WASM_TABLE_SIZE = 900; +export const WASM_TABLE_SIZE = 900; /** @const */ -var WASM_TABLE_OFFSET = 1024; +export const WASM_TABLE_OFFSET = 1024; /** @const */ -var MIXER_CHANNEL_LEFT = 0; +export const MIXER_CHANNEL_LEFT = 0; /** @const */ -var MIXER_CHANNEL_RIGHT = 1; +export const MIXER_CHANNEL_RIGHT = 1; /** @const */ -var MIXER_CHANNEL_BOTH = 2; +export const MIXER_CHANNEL_BOTH = 2; /** @const */ -var MIXER_SRC_MASTER = 0; +export const MIXER_SRC_MASTER = 0; /** @const */ -var MIXER_SRC_PCSPEAKER = 1; +export const MIXER_SRC_PCSPEAKER = 1; /** @const */ -var MIXER_SRC_DAC = 2; +export const MIXER_SRC_DAC = 2; diff --git a/src/cpu.js b/src/cpu.js index 70e18cd1..29b6089f 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -1,5 +1,58 @@ "use strict"; +import { + LOG_CPU, REG_CS, + FW_CFG_SIGNATURE, FW_CFG_SIGNATURE_QEMU, + WASM_TABLE_SIZE, WASM_TABLE_OFFSET, FW_CFG_ID, + FW_CFG_RAM_SIZE, FW_CFG_NB_CPUS, FW_CFG_MAX_CPUS, + FW_CFG_NUMA, FW_CFG_FILE_DIR, FW_CFG_FILE_START, + FW_CFG_CUSTOM_START, REG_EAX, REG_EBX, FLAGS_DEFAULT, + MMAP_BLOCK_BITS, MMAP_BLOCK_SIZE, MMAP_MAX +} from "./const.js"; +import { DUMP_GENERATED_WASM, DUMP_UNCOMPILED_ASSEMBLY } from "./config.js"; +import { h, view, Bitmap } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + +import { SB16 } from "./sb16.js"; +import { IOAPIC } from "./ioapic.js"; +import { APIC, APIC_LOG_VERBOSE } from "./apic.js"; +import { ACPI } from "./acpi.js"; +import { PIT } from "./pit.js"; +import { DMA } from "./dma.js"; +import { UART } from "./uart.js"; +import { Ne2k } from "./ne2k.js"; +import { IO } from "./io.js"; +import { VirtioConsole } from "./virtio_console.js"; +import { PCI } from "./pci.js"; +import { PS2 } from "./ps2.js"; +import { read_elf } from "./elf.js"; + +import { FloppyController } from "./floppy.js"; +import { IDEDevice } from "./ide.js"; +import { VirtioNet } from "./virtio_net.js"; +import { VGAScreen } from "./vga.js"; +import { VirtioBalloon } from "./virtio_balloon.js"; +import { Virtio9p } from "../lib/9p.js"; + +import { load_kernel } from "./kernel.js"; + + +import { + RTC, + CMOS_EQUIPMENT_INFO, CMOS_BIOS_SMP_COUNT, + CMOS_MEM_HIGHMEM_HIGH, CMOS_MEM_HIGHMEM_MID, CMOS_MEM_HIGHMEM_LOW, + CMOS_DISK_DATA, CMOS_BIOS_DISKTRANSFLAG, CMOS_FLOPPY_DRIVE_TYPE, + BOOT_ORDER_CD_FIRST, CMOS_BIOS_BOOTFLAG1, CMOS_BIOS_BOOTFLAG2, + CMOS_MEM_BASE_LOW, CMOS_MEM_BASE_HIGH, + CMOS_MEM_OLD_EXT_LOW, CMOS_MEM_OLD_EXT_HIGH, CMOS_MEM_EXTMEM_LOW, + CMOS_MEM_EXTMEM_HIGH, CMOS_MEM_EXTMEM2_LOW, CMOS_MEM_EXTMEM2_HIGH +} from "./rtc.js"; + + +// For Types Only + +import { BusConnector } from "./bus.js"; + // Resources: // https://pdos.csail.mit.edu/6.828/2006/readings/i386/toc.htm // https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html @@ -7,7 +60,7 @@ /** @constructor */ -function CPU(bus, wm, stop_idling) +export function CPU(bus, wm, stop_idling) { this.stop_idling = stop_idling; this.wm = wm; @@ -18,91 +71,91 @@ function CPU(bus, wm, stop_idling) this.wasm_memory = memory; - this.memory_size = v86util.view(Uint32Array, memory, 812, 1); + this.memory_size = view(Uint32Array, memory, 812, 1); this.mem8 = new Uint8Array(0); this.mem32s = new Int32Array(this.mem8.buffer); - this.segment_is_null = v86util.view(Uint8Array, memory, 724, 8); - this.segment_offsets = v86util.view(Int32Array, memory, 736, 8); - this.segment_limits = v86util.view(Uint32Array, memory, 768, 8); - this.segment_access_bytes = v86util.view(Uint8Array, memory, 512, 8); + this.segment_is_null = view(Uint8Array, memory, 724, 8); + this.segment_offsets = view(Int32Array, memory, 736, 8); + this.segment_limits = view(Uint32Array, memory, 768, 8); + this.segment_access_bytes = view(Uint8Array, memory, 512, 8); /** * Wheter or not in protected mode */ - this.protected_mode = v86util.view(Int32Array, memory, 800, 1); + this.protected_mode = view(Int32Array, memory, 800, 1); - this.idtr_size = v86util.view(Int32Array, memory, 564, 1); - this.idtr_offset = v86util.view(Int32Array, memory, 568, 1); + this.idtr_size = view(Int32Array, memory, 564, 1); + this.idtr_offset = view(Int32Array, memory, 568, 1); /** * global descriptor table register */ - this.gdtr_size = v86util.view(Int32Array, memory, 572, 1); - this.gdtr_offset = v86util.view(Int32Array, memory, 576, 1); + this.gdtr_size = view(Int32Array, memory, 572, 1); + this.gdtr_offset = view(Int32Array, memory, 576, 1); - this.tss_size_32 = v86util.view(Int32Array, memory, 1128, 1); + this.tss_size_32 = view(Int32Array, memory, 1128, 1); /* * whether or not a page fault occured */ - this.page_fault = v86util.view(Uint32Array, memory, 540, 8); + this.page_fault = view(Uint32Array, memory, 540, 8); - this.cr = v86util.view(Int32Array, memory, 580, 8); + this.cr = view(Int32Array, memory, 580, 8); // current privilege level - this.cpl = v86util.view(Uint8Array, memory, 612, 1); + this.cpl = view(Uint8Array, memory, 612, 1); // current operand/address size - this.is_32 = v86util.view(Int32Array, memory, 804, 1); + this.is_32 = view(Int32Array, memory, 804, 1); - this.stack_size_32 = v86util.view(Int32Array, memory, 808, 1); + this.stack_size_32 = view(Int32Array, memory, 808, 1); /** * Was the last instruction a hlt? */ - this.in_hlt = v86util.view(Uint8Array, memory, 616, 1); + this.in_hlt = view(Uint8Array, memory, 616, 1); - this.last_virt_eip = v86util.view(Int32Array, memory, 620, 1); - this.eip_phys = v86util.view(Int32Array, memory, 624, 1); + this.last_virt_eip = view(Int32Array, memory, 620, 1); + this.eip_phys = view(Int32Array, memory, 624, 1); - this.sysenter_cs = v86util.view(Int32Array, memory, 636, 1); + this.sysenter_cs = view(Int32Array, memory, 636, 1); - this.sysenter_esp = v86util.view(Int32Array, memory, 640, 1); + this.sysenter_esp = view(Int32Array, memory, 640, 1); - this.sysenter_eip = v86util.view(Int32Array, memory, 644, 1); + this.sysenter_eip = view(Int32Array, memory, 644, 1); - this.prefixes = v86util.view(Int32Array, memory, 648, 1); + this.prefixes = view(Int32Array, memory, 648, 1); - this.flags = v86util.view(Int32Array, memory, 120, 1); + this.flags = view(Int32Array, memory, 120, 1); /** * bitmap of flags which are not updated in the flags variable * changed by arithmetic instructions, so only relevant to arithmetic flags */ - this.flags_changed = v86util.view(Int32Array, memory, 100, 1); + this.flags_changed = view(Int32Array, memory, 100, 1); /** * enough infos about the last arithmetic operation to compute eflags */ - this.last_op_size = v86util.view(Int32Array, memory, 96, 1); - this.last_op1 = v86util.view(Int32Array, memory, 104, 1); - this.last_result = v86util.view(Int32Array, memory, 112, 1); + this.last_op_size = view(Int32Array, memory, 96, 1); + this.last_op1 = view(Int32Array, memory, 104, 1); + this.last_result = view(Int32Array, memory, 112, 1); - this.current_tsc = v86util.view(Uint32Array, memory, 960, 2); // 64 bit + this.current_tsc = view(Uint32Array, memory, 960, 2); // 64 bit /** @type {!Object} */ this.devices = {}; - this.instruction_pointer = v86util.view(Int32Array, memory, 556, 1); - this.previous_ip = v86util.view(Int32Array, memory, 560, 1); + this.instruction_pointer = view(Int32Array, memory, 556, 1); + this.previous_ip = view(Int32Array, memory, 560, 1); // configured by guest - this.apic_enabled = v86util.view(Uint8Array, memory, 548, 1); + this.apic_enabled = view(Uint8Array, memory, 548, 1); // configured when the emulator starts (changes bios initialisation) - this.acpi_enabled = v86util.view(Uint8Array, memory, 552, 1); + this.acpi_enabled = view(Uint8Array, memory, 552, 1); // managed in io.js /** @const */ this.memory_map_read8 = []; @@ -119,47 +172,47 @@ function CPU(bus, wm, stop_idling) vga: null, }; - this.instruction_counter = v86util.view(Uint32Array, memory, 664, 1); + this.instruction_counter = view(Uint32Array, memory, 664, 1); // registers - this.reg32 = v86util.view(Int32Array, memory, 64, 8); + this.reg32 = view(Int32Array, memory, 64, 8); - this.fpu_st = v86util.view(Int32Array, memory, 1152, 4 * 8); + this.fpu_st = view(Int32Array, memory, 1152, 4 * 8); - this.fpu_stack_empty = v86util.view(Uint8Array, memory, 816, 1); + this.fpu_stack_empty = view(Uint8Array, memory, 816, 1); this.fpu_stack_empty[0] = 0xFF; - this.fpu_stack_ptr = v86util.view(Uint8Array, memory, 1032, 1); + this.fpu_stack_ptr = view(Uint8Array, memory, 1032, 1); this.fpu_stack_ptr[0] = 0; - this.fpu_control_word = v86util.view(Uint16Array, memory, 1036, 1); + this.fpu_control_word = view(Uint16Array, memory, 1036, 1); this.fpu_control_word[0] = 0x37F; - this.fpu_status_word = v86util.view(Uint16Array, memory, 1040, 1); + this.fpu_status_word = view(Uint16Array, memory, 1040, 1); this.fpu_status_word[0] = 0; - this.fpu_ip = v86util.view(Int32Array, memory, 1048, 1); + this.fpu_ip = view(Int32Array, memory, 1048, 1); this.fpu_ip[0] = 0; - this.fpu_ip_selector = v86util.view(Int32Array, memory, 1052, 1); + this.fpu_ip_selector = view(Int32Array, memory, 1052, 1); this.fpu_ip_selector[0] = 0; - this.fpu_opcode = v86util.view(Int32Array, memory, 1044, 1); + this.fpu_opcode = view(Int32Array, memory, 1044, 1); this.fpu_opcode[0] = 0; - this.fpu_dp = v86util.view(Int32Array, memory, 1056, 1); + this.fpu_dp = view(Int32Array, memory, 1056, 1); this.fpu_dp[0] = 0; - this.fpu_dp_selector = v86util.view(Int32Array, memory, 1060, 1); + this.fpu_dp_selector = view(Int32Array, memory, 1060, 1); this.fpu_dp_selector[0] = 0; - this.reg_xmm32s = v86util.view(Int32Array, memory, 832, 8 * 4); + this.reg_xmm32s = view(Int32Array, memory, 832, 8 * 4); - this.mxcsr = v86util.view(Int32Array, memory, 824, 1); + this.mxcsr = view(Int32Array, memory, 824, 1); // segment registers, tr and ldtr - this.sreg = v86util.view(Uint16Array, memory, 668, 8); + this.sreg = view(Uint16Array, memory, 668, 8); // debug registers - this.dreg = v86util.view(Int32Array, memory, 684, 8); + this.dreg = view(Int32Array, memory, 684, 8); - this.reg_pdpte = v86util.view(Int32Array, memory, 968, 8); + this.reg_pdpte = view(Int32Array, memory, 968, 8); - this.svga_dirty_bitmap_min_offset = v86util.view(Uint32Array, memory, 716, 1); - this.svga_dirty_bitmap_max_offset = v86util.view(Uint32Array, memory, 720, 1); + this.svga_dirty_bitmap_min_offset = view(Uint32Array, memory, 716, 1); + this.svga_dirty_bitmap_max_offset = view(Uint32Array, memory, 720, 1); this.fw_value = []; this.fw_pointer = 0; @@ -573,7 +626,7 @@ CPU.prototype.set_state = function(state) this.fpu_dp_selector[0] = state[74]; this.fpu_opcode[0] = state[75]; - const bitmap = new v86util.Bitmap(state[78].buffer); + const bitmap = new Bitmap(state[78].buffer); const packed_memory = state[77]; this.unpack_memory(bitmap, packed_memory); @@ -636,7 +689,7 @@ CPU.prototype.pack_memory = function() } } - const bitmap = new v86util.Bitmap(page_count); + const bitmap = new Bitmap(page_count); const packed_memory = new Uint8Array(nonzero_pages.length << 12); for(const [i, page] of nonzero_pages.entries()) @@ -720,8 +773,8 @@ CPU.prototype.create_memory = function(size, minimum_size) const memory_offset = this.allocate_memory(size); - this.mem8 = v86util.view(Uint8Array, this.wasm_memory, memory_offset, size); - this.mem32s = v86util.view(Uint32Array, this.wasm_memory, memory_offset, size >> 2); + this.mem8 = view(Uint8Array, this.wasm_memory, memory_offset, size); + this.mem32s = view(Uint32Array, this.wasm_memory, memory_offset, size >> 2); }; /** diff --git a/src/debug.js b/src/debug.js index a694d8ae..9292d661 100644 --- a/src/debug.js +++ b/src/debug.js @@ -1,5 +1,16 @@ "use strict"; +import { + LOG_BIOS, LOG_CPU, + REG_ESP, REG_EBP, REG_ESI, REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_EDI, + REG_CS, REG_DS, REG_ES, REG_FS, REG_GS, REG_SS, CR0_PG, CR4_PAE, REG_LDTR, + FLAG_VM, FLAG_INTERRUPT, FLAG_CARRY, FLAG_ADJUST, FLAG_ZERO, FLAG_SIGN, FLAG_TRAP, + FLAG_DIRECTION, FLAG_OVERFLOW, FLAG_PARITY +} from "./const.js"; +import { h, pads } from "./lib.js"; +import { dbg_log } from "./log.js"; +import { CPU } from "./cpu.js"; + CPU.prototype.debug_init = function() { var cpu = this; @@ -560,6 +571,7 @@ CPU.prototype.debug_init = function() { if(cs === undefined) { + /* global require */ if(typeof require === "function") { cs = require("./capstone-x86.min.js"); @@ -588,7 +600,7 @@ CPU.prototype.debug_init = function() instructions.forEach(function (instr) { dbg_log(h(instr.address >>> 0) + ": " + - v86util.pads(instr.bytes.map(x => h(x, 2).slice(-2)).join(" "), 20) + " " + + pads(instr.bytes.map(x => h(x, 2).slice(-2)).join(" "), 20) + " " + instr.mnemonic + " " + instr.op_str); }); dbg_log(""); @@ -616,11 +628,12 @@ CPU.prototype.debug_init = function() debug.dump_wasm = function(buffer) { + /* global require */ if(wabt === undefined) { if(typeof require === "function") { - wabt = require("./libwabt.js"); + wabt = require("./libwabt.cjs"); } else { diff --git a/src/dma.js b/src/dma.js index 4283bded..6ad6d710 100644 --- a/src/dma.js +++ b/src/dma.js @@ -1,10 +1,17 @@ "use strict"; +import { LOG_DMA } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; + /** * @constructor * @param {CPU} cpu */ -function DMA(cpu) +export function DMA(cpu) { /** @const @type {CPU} */ this.cpu = cpu; diff --git a/src/elf.js b/src/elf.js index b2d9b3d7..50d561aa 100644 --- a/src/elf.js +++ b/src/elf.js @@ -1,5 +1,8 @@ "use strict"; +import { LOG_LEVEL } from "./config.js"; +import { dbg_log } from "./log.js"; + // A minimal elf parser for loading 32 bit, x86, little endian, executable elf files const ELF_MAGIC = 0x464C457F; @@ -95,7 +98,7 @@ function create_struct(struct) } /** @param {ArrayBuffer} buffer */ -function read_elf(buffer) +export function read_elf(buffer) { const view = new DataView(buffer); diff --git a/src/floppy.js b/src/floppy.js index 3fdde453..302e29b5 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -3,6 +3,18 @@ // https://www.isdaman.com/alsos/hardware/fdc/floppy.htm // https://wiki.osdev.org/Floppy_Disk_Controller +import { LOG_FLOPPY } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; +import { CMOS_FLOPPY_DRIVE_TYPE } from "./rtc.js"; +import { SyncBuffer } from "./buffer.js"; + + +// For Types Only +import { CPU } from "./cpu.js"; +import { DMA } from "./dma.js"; +import { IO } from "./io.js"; + const DIR_DOOR = 0x80; const ST1_NID = 1 << 0; const ST1_NDAT = 1 << 2; @@ -12,7 +24,7 @@ const ST1_NDAT = 1 << 2; * * @param {CPU} cpu */ -function FloppyController(cpu, fda_image, fdb_image) +export function FloppyController(cpu, fda_image, fdb_image) { /** @const @type {IO|undefined} */ this.io = cpu.io; @@ -110,7 +122,7 @@ FloppyController.prototype.set_fda = function(fda_image) dbg_assert(fda_image.buffer && fda_image.buffer instanceof ArrayBuffer); const new_image = new Uint8Array(floppy_size); new_image.set(new Uint8Array(fda_image.buffer)); - fda_image = new v86util.SyncBuffer(new_image.buffer); + fda_image = new SyncBuffer(new_image.buffer); dbg_log("Warning: Unkown floppy size: " + fda_image.byteLength + ", assuming " + floppy_size); } diff --git a/src/ide.js b/src/ide.js index 24691156..ea4c97e7 100644 --- a/src/ide.js +++ b/src/ide.js @@ -1,5 +1,14 @@ "use strict"; +import { LOG_DISK } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; +import { CMOS_BIOS_DISKTRANSFLAG, CMOS_DISK_DATA, CMOS_DISK_DRIVE1_CYL } from "./rtc.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; + /** @const */ var CDROM_SECTOR_SIZE = 2048; /** @const */ @@ -12,7 +21,7 @@ var HD_SECTOR_SIZE = 512; * @param {number} nr * @param {BusConnector} bus * */ -function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) +export function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) { this.master = new IDEInterface(this, cpu, master_buffer, is_cd, nr, 0, bus); this.slave = new IDEInterface(this, cpu, slave_buffer, false, nr, 1, bus); diff --git a/src/io.js b/src/io.js index 1d0f1125..29ad137b 100644 --- a/src/io.js +++ b/src/io.js @@ -1,5 +1,14 @@ "use strict"; +import { LOG_IO, MMAP_BLOCK_BITS, MMAP_BLOCK_SIZE, MMAP_MAX } from "./const.js"; +import { LOG_ALL_IO } from "./config.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + + +// For Types Only +import { CPU } from "./cpu.js"; + /** * The ISA IO bus * Devices register their ports here @@ -7,7 +16,7 @@ * @constructor * @param {CPU} cpu */ -function IO(cpu) +export function IO(cpu) { /** @const */ this.ports = []; @@ -87,9 +96,9 @@ IO.prototype.empty_port_write = function(x) /** * @param {number} port_addr * @param {Object} device - * @param {function():number=} r8 - * @param {function():number=} r16 - * @param {function():number=} r32 + * @param {function(number):number=} r8 + * @param {function(number):number=} r16 + * @param {function(number):number=} r32 */ IO.prototype.register_read = function(port_addr, device, r8, r16, r32) { diff --git a/src/ioapic.js b/src/ioapic.js index 793ff853..ab51b675 100644 --- a/src/ioapic.js +++ b/src/ioapic.js @@ -2,55 +2,64 @@ // http://download.intel.com/design/chipsets/datashts/29056601.pdf -/** @const */ -var IOAPIC_ADDRESS = 0xFEC00000; +import { LOG_APIC, MMAP_BLOCK_SIZE } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; +import { DELIVERY_MODES, DESTINATION_MODES, APIC_LOG_VERBOSE } from "./apic.js"; -/** @const */ -var IOREGSEL = 0; - -/** @const */ -var IOWIN = 0x10; - -/** @const */ -var IOAPIC_IRQ_COUNT = 24; - -/** @const */ -var IOAPIC_ID = 0; // must match value in seabios +// For Types Only +import { CPU } from "./cpu.js"; /** @const */ -var IOAPIC_CONFIG_TRIGGER_MODE_LEVEL = 1 << 15; +export const IOAPIC_ADDRESS = 0xFEC00000; /** @const */ -var IOAPIC_CONFIG_MASKED = 1 << 16; +export const IOREGSEL = 0; /** @const */ -var IOAPIC_CONFIG_DELIVS = 1 << 12; +export const IOWIN = 0x10; /** @const */ -var IOAPIC_CONFIG_REMOTE_IRR = 1 << 14; +export const IOAPIC_IRQ_COUNT = 24; /** @const */ -var IOAPIC_CONFIG_READONLY_MASK = IOAPIC_CONFIG_REMOTE_IRR | IOAPIC_CONFIG_DELIVS | 0xFFFE0000; +export const IOAPIC_ID = 0; // must match value in seabios + /** @const */ -var IOAPIC_DELIVERY_FIXED = 0; +export const IOAPIC_CONFIG_TRIGGER_MODE_LEVEL = 1 << 15; /** @const */ -var IOAPIC_DELIVERY_LOWEST_PRIORITY = 1; +export const IOAPIC_CONFIG_MASKED = 1 << 16; /** @const */ -var IOAPIC_DELIVERY_NMI = 4; +export const IOAPIC_CONFIG_DELIVS = 1 << 12; /** @const */ -var IOAPIC_DELIVERY_INIT = 5; +export const IOAPIC_CONFIG_REMOTE_IRR = 1 << 14; + +/** @const */ +export const IOAPIC_CONFIG_READONLY_MASK = IOAPIC_CONFIG_REMOTE_IRR | IOAPIC_CONFIG_DELIVS | 0xFFFE0000; + +/** @const */ +export const IOAPIC_DELIVERY_FIXED = 0; + +/** @const */ +export const IOAPIC_DELIVERY_LOWEST_PRIORITY = 1; + +/** @const */ +export const IOAPIC_DELIVERY_NMI = 4; + +/** @const */ +export const IOAPIC_DELIVERY_INIT = 5; /** * @constructor * @param {CPU} cpu */ -function IOAPIC(cpu) +export function IOAPIC(cpu) { /** @type {CPU} */ this.cpu = cpu; diff --git a/src/kernel.js b/src/kernel.js index 16948540..0fdd0995 100644 --- a/src/kernel.js +++ b/src/kernel.js @@ -1,5 +1,9 @@ "use strict"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + + // https://www.kernel.org/doc/Documentation/x86/boot.txt const LINUX_BOOT_HDR_SETUP_SECTS = 0x1F1; @@ -37,7 +41,7 @@ const LINUX_BOOT_HDR_LOADFLAGS_KEEP_SEGMENTS = 1 << 6; const LINUX_BOOT_HDR_LOADFLAGS_CAN_USE_HEAPS = 1 << 7; -function load_kernel(mem8, bzimage, initrd, cmdline) +export function load_kernel(mem8, bzimage, initrd, cmdline) { dbg_log("Trying to load kernel of size " + bzimage.byteLength); diff --git a/src/lib.js b/src/lib.js index 682c1031..441390ef 100644 --- a/src/lib.js +++ b/src/lib.js @@ -1,52 +1,34 @@ "use strict"; -var goog = goog || {}; -goog.exportSymbol = function(name, sym) { - if(typeof module !== "undefined" && typeof module.exports !== "undefined") - { - module.exports[name] = sym; - } - else if(typeof window !== "undefined") - { - window[name] = sym; - } - else if(typeof importScripts === "function") - { - // web worker - self[name] = sym; - } -}; -goog.exportProperty = function() {}; - -var v86util = v86util || {}; +import { dbg_assert } from "./log.js"; // pad string with spaces on the right -v86util.pads = function(str, len) +export function pads(str, len) { str = (str || str === 0) ? str + "" : ""; return str.padEnd(len, " "); -}; +} // pad string with zeros on the left -v86util.pad0 = function(str, len) +export function pad0(str, len) { str = (str || str === 0) ? str + "" : ""; return str.padStart(len, "0"); -}; +} // generates array given size with zeros -v86util.zeros = function(size) +export function zeros(size) { return Array(size).fill(0); -}; +} // generates [0, 1, 2, ..., size-1] -v86util.range = function(size) +export function range(size) { return Array.from(Array(size).keys()); -}; +} -v86util.view = function(constructor, memory, offset, length) +export var view = function(constructor, memory, offset, length) { dbg_assert(offset >= 0); return new Proxy({}, @@ -78,7 +60,7 @@ v86util.view = function(constructor, memory, offset, length) * @param {number=} len * @return {string} */ -function h(n, len) +export function h(n, len) { if(!n) { @@ -89,14 +71,14 @@ function h(n, len) var str = n.toString(16); } - return "0x" + v86util.pad0(str.toUpperCase(), len || 1); + return "0x" + pad0(str.toUpperCase(), len || 1); } -function hex_dump(buffer) +export function hex_dump(buffer) { function hex(n, len) { - return v86util.pad0(n.toString(16).toUpperCase(), len); + return pad0(n.toString(16).toUpperCase(), len); } const result = []; @@ -144,11 +126,13 @@ function hex_dump(buffer) return "\n" + result.join("\n") + "\n"; } +/* global require */ +export var get_rand_int; if(typeof crypto !== "undefined" && crypto.getRandomValues) { const rand_data = new Int32Array(1); - v86util.get_rand_int = function() + get_rand_int = function() { crypto.getRandomValues(rand_data); return rand_data[0]; @@ -159,34 +143,41 @@ else if(typeof require !== "undefined") /** @type {{ randomBytes: Function }} */ const crypto = require("crypto"); - v86util.get_rand_int = function() + get_rand_int = function() { return crypto.randomBytes(4)["readInt32LE"](0); }; } +else if(typeof process !== "undefined") + { + import("node:" + "crypto").then(crypto => { + get_rand_int = function() + { + return crypto["randomBytes"](4)["readInt32LE"](0); + }; + }); + } else { dbg_assert(false, "Unsupported platform: No cryptographic random values"); } -(function() +export var int_log2; + +if(typeof Math.clz32 === "function" && Math.clz32(0) === 32 && Math.clz32(0x12345) === 15 && Math.clz32(-1) === 0) { - if(typeof Math.clz32 === "function" && Math.clz32(0) === 32 && Math.clz32(0x12345) === 15 && Math.clz32(-1) === 0) + /** + * calculate the integer logarithm base 2 + * @param {number} x + * @return {number} + */ + int_log2 = function(x) { - /** - * calculate the integer logarithm base 2 - * @param {number} x - * @return {number} - */ - v86util.int_log2 = function(x) - { - dbg_assert(x > 0); + dbg_assert(x > 0); - return 31 - Math.clz32(x); - }; - - return; - } + return 31 - Math.clz32(x); + }; +} else { var int_log2_table = new Int8Array(256); @@ -203,7 +194,7 @@ else * @param {number} x * @return {number} */ - v86util.int_log2 = function(x) + int_log2 = function(x) { x >>>= 0; dbg_assert(x > 0); @@ -236,28 +227,28 @@ else } } }; -})(); +} -v86util.round_up_to_next_power_of_2 = function(x) +export const round_up_to_next_power_of_2 = function(x) { dbg_assert(x >= 0); - return x <= 1 ? 1 : 1 << 1 + v86util.int_log2(x - 1); + return x <= 1 ? 1 : 1 << 1 + int_log2(x - 1); }; if(DEBUG) { - dbg_assert(v86util.int_log2(1) === 0); - dbg_assert(v86util.int_log2(2) === 1); - dbg_assert(v86util.int_log2(7) === 2); - dbg_assert(v86util.int_log2(8) === 3); - dbg_assert(v86util.int_log2(123456789) === 26); + dbg_assert(int_log2(1) === 0); + dbg_assert(int_log2(2) === 1); + dbg_assert(int_log2(7) === 2); + dbg_assert(int_log2(8) === 3); + dbg_assert(int_log2(123456789) === 26); - dbg_assert(v86util.round_up_to_next_power_of_2(0) === 1); - dbg_assert(v86util.round_up_to_next_power_of_2(1) === 1); - dbg_assert(v86util.round_up_to_next_power_of_2(2) === 2); - dbg_assert(v86util.round_up_to_next_power_of_2(7) === 8); - dbg_assert(v86util.round_up_to_next_power_of_2(8) === 8); - dbg_assert(v86util.round_up_to_next_power_of_2(123456789) === 134217728); + dbg_assert(round_up_to_next_power_of_2(0) === 1); + dbg_assert(round_up_to_next_power_of_2(1) === 1); + dbg_assert(round_up_to_next_power_of_2(2) === 2); + dbg_assert(round_up_to_next_power_of_2(7) === 8); + dbg_assert(round_up_to_next_power_of_2(8) === 8); + dbg_assert(round_up_to_next_power_of_2(123456789) === 134217728); } /** @@ -266,7 +257,7 @@ if(DEBUG) * Queue wrapper around Uint8Array * Used by devices such as the PS2 controller */ -function ByteQueue(size) +export function ByteQueue(size) { var data = new Uint8Array(size), start, @@ -337,7 +328,7 @@ function ByteQueue(size) * Queue wrapper around Float32Array * Used by devices such as the sound blaster sound card */ -function FloatQueue(size) +export function FloatQueue(size) { this.size = size; this.data = new Float32Array(size); @@ -465,7 +456,7 @@ CircularQueue.prototype.set = function(new_data) this.index = 0; }; -function dump_file(ab, name) +export function dump_file(ab, name) { if(!Array.isArray(ab)) { @@ -476,7 +467,7 @@ function dump_file(ab, name) download(blob, name); } -function download(file_or_blob, name) +export function download(file_or_blob, name) { var a = document.createElement("a"); a["download"] = name; @@ -502,7 +493,7 @@ function download(file_or_blob, name) * A simple 1d bitmap * @constructor */ -v86util.Bitmap = function(length_or_buffer) +export var Bitmap = function(length_or_buffer) { if(typeof length_or_buffer === "number") { @@ -514,11 +505,11 @@ v86util.Bitmap = function(length_or_buffer) } else { - dbg_assert(false, "v86util.Bitmap: Invalid argument"); + dbg_assert(false, "Bitmap: Invalid argument"); } }; -v86util.Bitmap.prototype.set = function(index, value) +Bitmap.prototype.set = function(index, value) { const bit_index = index & 7; const byte_index = index >> 3; @@ -528,7 +519,7 @@ v86util.Bitmap.prototype.set = function(index, value) value ? this.view[byte_index] | bit_mask : this.view[byte_index] & ~bit_mask; }; -v86util.Bitmap.prototype.get = function(index) +Bitmap.prototype.get = function(index) { const bit_index = index & 7; const byte_index = index >> 3; @@ -536,19 +527,20 @@ v86util.Bitmap.prototype.get = function(index) return this.view[byte_index] >> bit_index & 1; }; -v86util.Bitmap.prototype.get_buffer = function() +Bitmap.prototype.get_buffer = function() { return this.view.buffer; }; +export var load_file; if(typeof XMLHttpRequest === "undefined") { - v86util.load_file = load_file_nodejs; + load_file = load_file_nodejs; } else { - v86util.load_file = load_file; + load_file = _load_file; } /** @@ -556,7 +548,7 @@ else * @param {Object} options * @param {number=} n_tries */ -function load_file(filename, options, n_tries) +function _load_file(filename, options, n_tries) { var http = new XMLHttpRequest(); @@ -656,13 +648,11 @@ function load_file(filename, options, n_tries) function load_file_nodejs(filename, options) { - const fs = require("fs"); - if(options.range) { dbg_assert(!options.as_json); - fs["open"](filename, "r", (err, fd) => + import("node:" + "fs").then(fs => fs["open"](filename, "r", (err, fd) => { if(err) throw err; @@ -680,7 +670,7 @@ function load_file_nodejs(filename, options) if(err) throw err; }); }); - }); + })); } else { @@ -688,7 +678,7 @@ function load_file_nodejs(filename, options) encoding: options.as_json ? "utf-8" : null, }; - fs["readFile"](filename, o, function(err, data) + import("node:" + "fs").then(fs => fs["readFile"](filename, o, function(err, data) { if(err) { @@ -709,14 +699,14 @@ function load_file_nodejs(filename, options) options.done(result); } - }); + })); } } // Reads len characters at offset from Memory object mem as a JS string -v86util.read_sized_string_from_mem = function read_sized_string_from_mem(mem, offset, len) +export function read_sized_string_from_mem(mem, offset, len) { offset >>>= 0; len >>>= 0; return String.fromCharCode(...new Uint8Array(mem.buffer, offset, len)); -}; +} diff --git a/src/log.js b/src/log.js index 277316a2..d170266a 100644 --- a/src/log.js +++ b/src/log.js @@ -1,6 +1,10 @@ "use strict"; -var log_data = []; +import { LOG_NAMES } from "./const.js"; +import { LOG_TO_FILE, LOG_LEVEL } from "./config.js"; +import { pad0, pads } from "./lib.js"; + +export var log_data = []; function do_the_log(message) { @@ -18,7 +22,7 @@ function do_the_log(message) * @type {function((string|number), number=)} * @const */ -var dbg_log = (function() +export var dbg_log = (function() { if(!DEBUG) { @@ -47,7 +51,7 @@ var dbg_log = (function() if(level & LOG_LEVEL) { var level_name = dbg_names[level] || "", - message = "[" + v86util.pads(level_name, 4) + "] " + stuff; + message = "[" + pads(level_name, 4) + "] " + stuff; if(message === log_last_message) { @@ -60,10 +64,10 @@ var dbg_log = (function() } var now = new Date(); - var time_str = v86util.pad0(now.getHours(), 2) + ":" + - v86util.pad0(now.getMinutes(), 2) + ":" + - v86util.pad0(now.getSeconds(), 2) + "+" + - v86util.pad0(now.getMilliseconds(), 3) + " "; + var time_str = pad0(now.getHours(), 2) + ":" + + pad0(now.getMinutes(), 2) + ":" + + pad0(now.getSeconds(), 2) + "+" + + pad0(now.getMilliseconds(), 3) + " "; if(log_message_repetitions) { @@ -90,7 +94,7 @@ var dbg_log = (function() /** * @param {number=} level */ -function dbg_trace(level) +export function dbg_trace(level) { if(!DEBUG) return; @@ -102,7 +106,7 @@ function dbg_trace(level) * @param {string=} msg * @param {number=} level */ -function dbg_assert(cond, msg, level) +export function dbg_assert(cond, msg, level) { if(!DEBUG) return; @@ -113,7 +117,7 @@ function dbg_assert(cond, msg, level) } -function dbg_assert_failed(msg) +export function dbg_assert_failed(msg) { debugger; console.trace(); diff --git a/src/main.js b/src/main.js index 34a2f255..140197f3 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,12 @@ "use strict"; +import { CPU } from "./cpu.js"; + /** * @constructor * @param {Object=} wasm */ -function v86(bus, wasm) +export function v86(bus, wasm) { /** @type {boolean} */ this.running = false; @@ -98,6 +100,7 @@ if(typeof process !== "undefined") { v86.prototype.yield = function(t, tick) { + /* global global */ if(t < 1) { global.setImmediate(tick => this.yield_callback(tick), tick); @@ -205,7 +208,7 @@ v86.prototype.restore_state = function(state) return this.cpu.restore_state(state); }; - +/* global require */ if(typeof performance === "object" && performance.now) { v86.microtick = performance.now.bind(performance); diff --git a/src/memory.js b/src/memory.js index 60445e4f..521ec189 100644 --- a/src/memory.js +++ b/src/memory.js @@ -1,5 +1,9 @@ "use strict"; +import { MMAP_BLOCK_BITS } from "./const.js"; +import { CPU } from "./cpu.js"; +import { dbg_assert } from "./log.js"; + CPU.prototype.mmap_read8 = function(addr) { diff --git a/src/ne2k.js b/src/ne2k.js index 5a944af7..6f5a94b3 100644 --- a/src/ne2k.js +++ b/src/ne2k.js @@ -1,5 +1,14 @@ "use strict"; +import { LOG_NET } from "./const.js"; +import { h, hex_dump } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { PCI } from "./pci.js"; +import { BusConnector } from "./bus.js"; + // http://www.ethernut.de/pdf/8019asds.pdf const NE2K_LOG_VERBOSE = false; @@ -226,7 +235,7 @@ function translate_mac_address(packet, search_mac, replacement_mac) } } -function format_mac(mac) +export function format_mac(mac) { return [ mac[0].toString(16).padStart(2, "0"), @@ -288,7 +297,7 @@ function dump_packet(packet, prefix) * @param {Boolean} mac_address_translation * @param {number} [id=0] id */ -function Ne2k(cpu, bus, preserve_mac_from_state_image, mac_address_translation, id) +export function Ne2k(cpu, bus, preserve_mac_from_state_image, mac_address_translation, id) { /** @const @type {CPU} */ this.cpu = cpu; diff --git a/src/pci.js b/src/pci.js index f708f7c7..de0c16f2 100644 --- a/src/pci.js +++ b/src/pci.js @@ -1,8 +1,16 @@ "use strict"; +import { LOG_PCI } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; + + // http://wiki.osdev.org/PCI -var +export const /** @const */ PCI_CONFIG_ADDRESS = 0xCF8, /** @const */ PCI_CONFIG_DATA = 0xCFC; @@ -10,7 +18,7 @@ var * @constructor * @param {CPU} cpu */ -function PCI(cpu) +export function PCI(cpu) { this.pci_addr = new Uint8Array(4); this.pci_value = new Uint8Array(4); diff --git a/src/pit.js b/src/pit.js index f7813c15..272b36c7 100644 --- a/src/pit.js +++ b/src/pit.js @@ -1,17 +1,26 @@ "use strict"; +import { v86 } from "./main.js"; +import { LOG_PIT } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; + + /** * @const * In kHz */ -var OSCILLATOR_FREQ = 1193.1816666; // 1.193182 MHz +export const OSCILLATOR_FREQ = 1193.1816666; // 1.193182 MHz /** * @constructor * * Programmable Interval Timer */ -function PIT(cpu, bus) +export function PIT(cpu, bus) { /** @const @type {CPU} */ this.cpu = cpu; diff --git a/src/ps2.js b/src/ps2.js index bfee804b..3e8b96d0 100644 --- a/src/ps2.js +++ b/src/ps2.js @@ -1,5 +1,14 @@ "use strict"; +import { LOG_PS2 } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; +import { ByteQueue } from "./lib.js"; + /** @const */ const PS2_LOG_VERBOSE = false; @@ -8,7 +17,7 @@ const PS2_LOG_VERBOSE = false; * @param {CPU} cpu * @param {BusConnector} bus */ -function PS2(cpu, bus) +export function PS2(cpu, bus) { /** @const @type {CPU} */ this.cpu = cpu; diff --git a/src/rtc.js b/src/rtc.js index e4c03feb..e0fd43f8 100644 --- a/src/rtc.js +++ b/src/rtc.js @@ -1,56 +1,67 @@ "use strict"; -/** @const */ var CMOS_RTC_SECONDS = 0x00; -/** @const */ var CMOS_RTC_SECONDS_ALARM = 0x01; -/** @const */ var CMOS_RTC_MINUTES = 0x02; -/** @const */ var CMOS_RTC_MINUTES_ALARM = 0x03; -/** @const */ var CMOS_RTC_HOURS = 0x04; -/** @const */ var CMOS_RTC_HOURS_ALARM = 0x05; -/** @const */ var CMOS_RTC_DAY_WEEK = 0x06; -/** @const */ var CMOS_RTC_DAY_MONTH = 0x07; -/** @const */ var CMOS_RTC_MONTH = 0x08; -/** @const */ var CMOS_RTC_YEAR = 0x09; -/** @const */ var CMOS_STATUS_A = 0x0a; -/** @const */ var CMOS_STATUS_B = 0x0b; -/** @const */ var CMOS_STATUS_C = 0x0c; -/** @const */ var CMOS_STATUS_D = 0x0d; -/** @const */ var CMOS_RESET_CODE = 0x0f; +import { v86 } from "./main.js"; +import { LOG_RTC } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; -/** @const */ var CMOS_FLOPPY_DRIVE_TYPE = 0x10; -/** @const */ var CMOS_DISK_DATA = 0x12; -/** @const */ var CMOS_EQUIPMENT_INFO = 0x14; -/** @const */ var CMOS_MEM_BASE_LOW = 0x15; -/** @const */ var CMOS_MEM_BASE_HIGH = 0x16; -/** @const */ var CMOS_MEM_OLD_EXT_LOW = 0x17; -/** @const */ var CMOS_MEM_OLD_EXT_HIGH = 0x18; -/** @const */ var CMOS_DISK_DRIVE1_TYPE = 0x19; -/** @const */ var CMOS_DISK_DRIVE2_TYPE = 0x1a; -/** @const */ var CMOS_DISK_DRIVE1_CYL = 0x1b; -/** @const */ var CMOS_DISK_DRIVE2_CYL = 0x24; -/** @const */ var CMOS_MEM_EXTMEM_LOW = 0x30; -/** @const */ var CMOS_MEM_EXTMEM_HIGH = 0x31; -/** @const */ var CMOS_CENTURY = 0x32; -/** @const */ var CMOS_MEM_EXTMEM2_LOW = 0x34; -/** @const */ var CMOS_MEM_EXTMEM2_HIGH = 0x35; -/** @const */ var CMOS_CENTURY2 = 0x37; -/** @const */ var CMOS_BIOS_BOOTFLAG1 = 0x38; -/** @const */ var CMOS_BIOS_DISKTRANSFLAG = 0x39; -/** @const */ var CMOS_BIOS_BOOTFLAG2 = 0x3d; -/** @const */ var CMOS_MEM_HIGHMEM_LOW = 0x5b; -/** @const */ var CMOS_MEM_HIGHMEM_MID = 0x5c; -/** @const */ var CMOS_MEM_HIGHMEM_HIGH = 0x5d; -/** @const */ var CMOS_BIOS_SMP_COUNT = 0x5f; +// For Types Only +import { CPU } from "./cpu.js"; +import { DMA } from "./dma.js"; + + +/** @const */ export const CMOS_RTC_SECONDS = 0x00; +/** @const */ export const CMOS_RTC_SECONDS_ALARM = 0x01; +/** @const */ export const CMOS_RTC_MINUTES = 0x02; +/** @const */ export const CMOS_RTC_MINUTES_ALARM = 0x03; +/** @const */ export const CMOS_RTC_HOURS = 0x04; +/** @const */ export const CMOS_RTC_HOURS_ALARM = 0x05; +/** @const */ export const CMOS_RTC_DAY_WEEK = 0x06; +/** @const */ export const CMOS_RTC_DAY_MONTH = 0x07; +/** @const */ export const CMOS_RTC_MONTH = 0x08; +/** @const */ export const CMOS_RTC_YEAR = 0x09; +/** @const */ export const CMOS_STATUS_A = 0x0a; +/** @const */ export const CMOS_STATUS_B = 0x0b; +/** @const */ export const CMOS_STATUS_C = 0x0c; +/** @const */ export const CMOS_STATUS_D = 0x0d; +/** @const */ export const CMOS_RESET_CODE = 0x0f; + +/** @const */ export const CMOS_FLOPPY_DRIVE_TYPE = 0x10; +/** @const */ export const CMOS_DISK_DATA = 0x12; +/** @const */ export const CMOS_EQUIPMENT_INFO = 0x14; +/** @const */ export const CMOS_MEM_BASE_LOW = 0x15; +/** @const */ export const CMOS_MEM_BASE_HIGH = 0x16; +/** @const */ export const CMOS_MEM_OLD_EXT_LOW = 0x17; +/** @const */ export const CMOS_MEM_OLD_EXT_HIGH = 0x18; +/** @const */ export const CMOS_DISK_DRIVE1_TYPE = 0x19; +/** @const */ export const CMOS_DISK_DRIVE2_TYPE = 0x1a; +/** @const */ export const CMOS_DISK_DRIVE1_CYL = 0x1b; +/** @const */ export const CMOS_DISK_DRIVE2_CYL = 0x24; +/** @const */ export const CMOS_MEM_EXTMEM_LOW = 0x30; +/** @const */ export const CMOS_MEM_EXTMEM_HIGH = 0x31; +/** @const */ export const CMOS_CENTURY = 0x32; +/** @const */ export const CMOS_MEM_EXTMEM2_LOW = 0x34; +/** @const */ export const CMOS_MEM_EXTMEM2_HIGH = 0x35; +/** @const */ export const CMOS_CENTURY2 = 0x37; +/** @const */ export const CMOS_BIOS_BOOTFLAG1 = 0x38; +/** @const */ export const CMOS_BIOS_DISKTRANSFLAG = 0x39; +/** @const */ export const CMOS_BIOS_BOOTFLAG2 = 0x3d; +/** @const */ export const CMOS_MEM_HIGHMEM_LOW = 0x5b; +/** @const */ export const CMOS_MEM_HIGHMEM_MID = 0x5c; +/** @const */ export const CMOS_MEM_HIGHMEM_HIGH = 0x5d; +/** @const */ export const CMOS_BIOS_SMP_COUNT = 0x5f; // see CPU.prototype.fill_cmos -const BOOT_ORDER_CD_FIRST = 0x123; -const BOOT_ORDER_HD_FIRST = 0x312; -const BOOT_ORDER_FD_FIRST = 0x321; +export const BOOT_ORDER_CD_FIRST = 0x123; +export const BOOT_ORDER_HD_FIRST = 0x312; +export const BOOT_ORDER_FD_FIRST = 0x321; /** * RTC (real time clock) and CMOS * @constructor * @param {CPU} cpu */ +export function RTC(cpu) { /** @const @type {CPU} */ diff --git a/src/sb16.js b/src/sb16.js index 43007644..0c2bc263 100644 --- a/src/sb16.js +++ b/src/sb16.js @@ -1,5 +1,21 @@ "use strict"; +import { + LOG_SB16, + MIXER_CHANNEL_BOTH, MIXER_CHANNEL_LEFT, MIXER_CHANNEL_RIGHT, + MIXER_SRC_PCSPEAKER, MIXER_SRC_DAC, MIXER_SRC_MASTER, +} from "./const.js"; +import { h } from "./lib.js"; +import { dbg_log } from "./log.js"; +import { SyncBuffer } from "./buffer.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { DMA } from "./dma.js"; +import { IO } from "./io.js"; +import { BusConnector } from "./bus.js"; +import { ByteQueue, FloatQueue } from "./lib.js"; + // Useful documentation, articles, and source codes for reference: // =============================================================== // @@ -92,7 +108,7 @@ var FM_HANDLERS = []; * @param {CPU} cpu * @param {BusConnector} bus */ -function SB16(cpu, bus) +export function SB16(cpu, bus) { /** @const @type {CPU} */ this.cpu = cpu; @@ -150,7 +166,7 @@ function SB16(cpu, bus) this.dma_buffer_uint8 = new Uint8Array(this.dma_buffer); this.dma_buffer_int16 = new Int16Array(this.dma_buffer); this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer); - this.dma_syncbuffer = new v86util.SyncBuffer(this.dma_buffer); + this.dma_syncbuffer = new SyncBuffer(this.dma_buffer); this.dma_waiting_transfer = false; this.dma_paused = false; this.sampling_rate = 22050; @@ -399,7 +415,7 @@ SB16.prototype.set_state = function(state) this.dma_buffer_int8 = new Int8Array(this.dma_buffer); this.dma_buffer_int16 = new Int16Array(this.dma_buffer); this.dma_buffer_uint16 = new Uint16Array(this.dma_buffer); - this.dma_syncbuffer = new v86util.SyncBuffer(this.dma_buffer); + this.dma_syncbuffer = new SyncBuffer(this.dma_buffer); if(this.dma_paused) { diff --git a/src/state.js b/src/state.js index 133d5872..524cf1af 100644 --- a/src/state.js +++ b/src/state.js @@ -1,5 +1,9 @@ "use strict"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; +import { CPU } from "./cpu.js"; + /** @const */ var STATE_VERSION = 6; diff --git a/src/uart.js b/src/uart.js index a85c5c19..c8078861 100644 --- a/src/uart.js +++ b/src/uart.js @@ -1,5 +1,13 @@ "use strict"; +import { LOG_SERIAL } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; + /* * Serial ports * http://wiki.osdev.org/UART @@ -44,7 +52,7 @@ var DLAB = 0x80; * @param {number} port * @param {BusConnector} bus */ -function UART(cpu, port, bus) +export function UART(cpu, port, bus) { /** @const @type {BusConnector} */ this.bus = bus; diff --git a/src/vga.js b/src/vga.js index 0d85da06..61b0d605 100644 --- a/src/vga.js +++ b/src/vga.js @@ -1,5 +1,16 @@ "use strict"; +import { LOG_VGA } from "./const.js"; +import { h } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { ScreenAdapter } from "./browser/screen.js"; +import { BusConnector } from "./bus.js"; +import { DummyScreenAdapter } from "./browser/dummy_screen.js"; +import { round_up_to_next_power_of_2, view } from "./lib.js"; + // Always 64k const VGA_BANK_SIZE = 64 * 1024; @@ -51,7 +62,7 @@ const VGA_HOST_MEMORY_SPACE_SIZE = Uint32Array.from([ * @param {ScreenAdapter|DummyScreenAdapter} screen * @param {number} vga_memory_size */ -function VGAScreen(cpu, bus, screen, vga_memory_size) +export function VGAScreen(cpu, bus, screen, vga_memory_size) { this.cpu = cpu; @@ -216,7 +227,7 @@ function VGAScreen(cpu, bus, screen, vga_memory_size) else { // required for pci code - this.vga_memory_size = v86util.round_up_to_next_power_of_2(this.vga_memory_size); + this.vga_memory_size = round_up_to_next_power_of_2(this.vga_memory_size); } dbg_log("effective vga memory size: " + this.vga_memory_size, LOG_VGA); @@ -356,7 +367,7 @@ function VGAScreen(cpu, bus, screen, vga_memory_size) const vga_offset = cpu.svga_allocate_memory(this.vga_memory_size) >>> 0; - this.svga_memory = v86util.view(Uint8Array, cpu.wasm_memory, vga_offset, this.vga_memory_size); + this.svga_memory = view(Uint8Array, cpu.wasm_memory, vga_offset, this.vga_memory_size); this.diff_addr_min = this.vga_memory_size; this.diff_addr_max = 0; diff --git a/src/virtio.js b/src/virtio.js index e7bd6709..26be9836 100644 --- a/src/virtio.js +++ b/src/virtio.js @@ -1,5 +1,13 @@ "use strict"; +import { LOG_VIRTIO } from "./const.js"; +import { h, zeros, int_log2 } from "./lib.js"; +import { dbg_assert, dbg_log } from "./log.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { PCI } from "./pci.js"; + // http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html const VIRTIO_PCI_VENDOR_ID = 0x1AF4; @@ -32,9 +40,9 @@ const VIRTIO_ISR_DEVICE_CFG = 2; // Feature bits (bit positions). -const VIRTIO_F_RING_INDIRECT_DESC = 28; -const VIRTIO_F_RING_EVENT_IDX = 29; -const VIRTIO_F_VERSION_1 = 32; +export const VIRTIO_F_RING_INDIRECT_DESC = 28; +export const VIRTIO_F_RING_EVENT_IDX = 29; +export const VIRTIO_F_VERSION_1 = 32; // Queue struct sizes. @@ -153,7 +161,7 @@ var VirtIO_Options; * @param {CPU} cpu * @param {VirtIO_Options} options */ -function VirtIO(cpu, options) +export function VirtIO(cpu, options) { const io = cpu.io; @@ -224,7 +232,7 @@ function VirtIO(cpu, options) ]; // Prevent sparse arrays by preallocating. - this.pci_space = this.pci_space.concat(v86util.zeros(256 - this.pci_space.length)); + this.pci_space = this.pci_space.concat(zeros(256 - this.pci_space.length)); // Remaining PCI space is appended by capabilities further below. this.pci_id = options.pci_id; @@ -480,7 +488,7 @@ VirtIO.prototype.create_common_capability = function(options) dbg_log("Warning: dev<" + this.name +"> " + "Given queue size was not a power of 2. " + "Rounding up to next power of 2.", LOG_VIRTIO); - data = 1 << (v86util.int_log2(data - 1) + 1); + data = 1 << (int_log2(data - 1) + 1); } if(data > this.queue_selected.size_supported) { @@ -727,7 +735,7 @@ VirtIO.prototype.init_capabilities = function(capabilities) // Round up to next power of 2, // Minimum 16 bytes for its size to be detectable in general (esp. mmio). - bar_size = bar_size < 16 ? 16 : 1 << (v86util.int_log2(bar_size - 1) + 1); + bar_size = bar_size < 16 ? 16 : 1 << (int_log2(bar_size - 1) + 1); dbg_assert((cap.port & (bar_size - 1)) === 0, "VirtIO device<" + this.name + "> capability port should be aligned to pci bar size"); diff --git a/src/virtio_balloon.js b/src/virtio_balloon.js index 5880b55e..07ff3763 100644 --- a/src/virtio_balloon.js +++ b/src/virtio_balloon.js @@ -2,6 +2,15 @@ // https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-2900003 +import { LOG_PCI } from "./const.js"; +import { dbg_log } from "./log.js"; +import { VirtIO, VIRTIO_F_VERSION_1 } from "./virtio.js"; +import { marshall } from "../lib/marshall.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; + const VIRTIO_BALLOON_F_MUST_TELL_HOST = 0; const VIRTIO_BALLOON_F_STATS_VQ = 1; const VIRTIO_BALLOON_F_DEFLATE_ON_OOM = 2; @@ -25,7 +34,7 @@ const STAT_NAMES = [ * @param {CPU} cpu * @param {BusConnector} bus */ -function VirtioBalloon(cpu, bus) +export function VirtioBalloon(cpu, bus) { /** @const @type {BusConnector} */ this.bus = bus; diff --git a/src/virtio_console.js b/src/virtio_console.js index 4cae265e..c55c783e 100644 --- a/src/virtio_console.js +++ b/src/virtio_console.js @@ -1,7 +1,16 @@ "use strict"; +import { dbg_assert } from "./log.js"; +import { VirtIO, VIRTIO_F_VERSION_1 } from "./virtio.js"; +import { marshall } from "../lib/marshall.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; + // https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-2900003 + const VIRTIO_CONSOLE_DEVICE_READY = 0; const VIRTIO_CONSOLE_DEVICE_ADD = 1; const VIRTIO_CONSOLE_DEVICE_REMOVE = 2; @@ -20,7 +29,7 @@ const VIRTIO_CONSOLE_F_EMERG_WRITE = 2; * * @param {CPU} cpu */ -function VirtioConsole(cpu, bus) +export function VirtioConsole(cpu, bus) { /** @const @type {BusConnector} */ this.bus = bus; diff --git a/src/virtio_net.js b/src/virtio_net.js index 886aa763..2d0829f7 100644 --- a/src/virtio_net.js +++ b/src/virtio_net.js @@ -2,6 +2,14 @@ // https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-2900003 +import { dbg_assert } from "./log.js"; +import { VirtIO, VIRTIO_F_VERSION_1 } from "./virtio.js"; +import { format_mac } from "./ne2k.js"; +import { marshall } from "../lib/marshall.js"; + +// For Types Only +import { CPU } from "./cpu.js"; +import { BusConnector } from "./bus.js"; const VIRTIO_NET_F_MAC = 5; const VIRTIO_NET_F_CTRL_VQ = 17; @@ -19,7 +27,7 @@ const VIRTIO_NET_CTRL_MAC_ADDR_SET = 1; * @param {BusConnector} bus * @param {Boolean} preserve_mac_from_state_image */ -function VirtioNet(cpu, bus, preserve_mac_from_state_image) +export function VirtioNet(cpu, bus, preserve_mac_from_state_image) { /** @const @type {BusConnector} */ this.bus = bus; diff --git a/tests/api/clean-shutdown.js b/tests/api/clean-shutdown.js index f645d822..a9b080f2 100755 --- a/tests/api/clean-shutdown.js +++ b/tests/api/clean-shutdown.js @@ -1,13 +1,15 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + // This test checks that calling emulator.destroy() will remove all event // listeners, so that the nodejs process cleanly and automatically exits. const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const fs = require("fs"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); diff --git a/tests/api/floppy-insert-eject.js b/tests/api/floppy-insert-eject.js index f6536e6c..176609be 100755 --- a/tests/api/floppy-insert-eject.js +++ b/tests/api/floppy-insert-eject.js @@ -1,11 +1,14 @@ #!/usr/bin/env node "use strict"; +import {setTimeout as pause} from "timers/promises"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const pause = require("timers/promises").setTimeout; -const fs = require("fs"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; + +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); diff --git a/tests/api/pic.js b/tests/api/pic.js index a148352f..69131158 100755 --- a/tests/api/pic.js +++ b/tests/api/pic.js @@ -1,10 +1,12 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const fs = require("fs"); -const V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +import fs from "node:fs"; +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); const root_path = __dirname + "/../.."; diff --git a/tests/api/reboot.js b/tests/api/reboot.js index 03b454d8..2fc33f07 100755 --- a/tests/api/reboot.js +++ b/tests/api/reboot.js @@ -1,10 +1,13 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const fs = require("fs"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); @@ -30,7 +33,7 @@ let did_reboot = false; let serial_text = ""; const timeout = setTimeout(() => { - console.log(serial_data); + console.log(serial_text); throw new Error("Timeout"); }, 120 * 1000); diff --git a/tests/api/reset.js b/tests/api/reset.js index 630d2abc..651c7491 100755 --- a/tests/api/reset.js +++ b/tests/api/reset.js @@ -1,12 +1,15 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + // This test checks that reset works const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const fs = require("fs"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); diff --git a/tests/api/serial.js b/tests/api/serial.js index d9e1e45e..63728201 100755 --- a/tests/api/serial.js +++ b/tests/api/serial.js @@ -1,12 +1,15 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; +import assert from "node:assert/strict"; +import crypto from "node:crypto"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const assert = require("assert").strict; -const fs = require("fs"); -const crypto = require("crypto"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); diff --git a/tests/api/state.js b/tests/api/state.js index 152e2136..a6b992bb 100755 --- a/tests/api/state.js +++ b/tests/api/state.js @@ -1,13 +1,15 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; -const assert = require("assert").strict; -var fs = require("fs"); +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); const config_async_cdrom = { bios: { url: __dirname + "/../../bios/seabios.bin" }, diff --git a/tests/api/test.js b/tests/api/test.js index 1b12dcb4..b354ac5b 100755 --- a/tests/api/test.js +++ b/tests/api/test.js @@ -1,10 +1,12 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const fs = require("fs"); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); process.on("unhandledRejection", exn => { throw exn; }); diff --git a/tests/benchmark/arch-bytemark.js b/tests/benchmark/arch-bytemark.js index a9d13c9b..51d815ad 100755 --- a/tests/benchmark/arch-bytemark.js +++ b/tests/benchmark/arch-bytemark.js @@ -1,10 +1,13 @@ #!/usr/bin/env node "use strict"; +import path from "node:path"; +import url from "node:url"; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS; -const { V86, print_stats } = require(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`); -const path = require("path"); +const { V86, print_stats } = await import(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`); const V86_ROOT = path.join(__dirname, "../.."); diff --git a/tests/benchmark/arch-python.js b/tests/benchmark/arch-python.js index 1d16a104..e587660a 100755 --- a/tests/benchmark/arch-python.js +++ b/tests/benchmark/arch-python.js @@ -1,10 +1,13 @@ #!/usr/bin/env node "use strict"; +import path from "node:path"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS; -const { V86, print_stats } = require(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`); -const path = require("path"); +const { V86, print_stats } = await import(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`); const V86_ROOT = path.join(__dirname, "../.."); diff --git a/tests/benchmark/linux-boot.js b/tests/benchmark/linux-boot.js index 81529d76..883f2dc2 100755 --- a/tests/benchmark/linux-boot.js +++ b/tests/benchmark/linux-boot.js @@ -1,12 +1,15 @@ #!/usr/bin/env node "use strict"; -const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + +const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS; +const { V86, print_stats } = await import(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`).V86; -const V86 = require(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`).V86; -const print_stats = require("../../build/libv86.js").print_stats; -const fs = require("fs"); -const path = require("path"); const V86_ROOT = path.join(__dirname, "../.."); const LOG_SERIAL = true; diff --git a/tests/benchmark/snapshot.js b/tests/benchmark/snapshot.js index ab19cb4e..db53b814 100755 --- a/tests/benchmark/snapshot.js +++ b/tests/benchmark/snapshot.js @@ -1,12 +1,14 @@ #!/usr/bin/env node "use strict"; +import path from "node:path"; +import url from "node:url"; + const BENCH_COLLECT_STATS = +process.env.BENCH_COLLECT_STATS; -const V86 = require(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`).V86; -const print_stats = require("../../build/libv86.js").print_stats; -const fs = require("fs"); -const path = require("path"); +let { V86, print_stats } = await import(`../../build/${BENCH_COLLECT_STATS ? "libv86-debug" : "libv86"}.js`); + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const V86_ROOT = path.join(__dirname, "../.."); const LOG_SERIAL = true; diff --git a/tests/devices/fetch_network.js b/tests/devices/fetch_network.js index fc001950..b62b1f37 100755 --- a/tests/devices/fetch_network.js +++ b/tests/devices/fetch_network.js @@ -1,14 +1,16 @@ #!/usr/bin/env node "use strict"; +import assert from "assert/strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; const USE_VIRTIO = !!process.env.USE_VIRTIO; -const V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; - -const assert = require("assert").strict; +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); const SHOW_LOGS = false; function wait(time) { diff --git a/tests/devices/virtio_9p.js b/tests/devices/virtio_9p.js index 88bad53b..1dba5edf 100755 --- a/tests/devices/virtio_9p.js +++ b/tests/devices/virtio_9p.js @@ -1,14 +1,16 @@ #!/usr/bin/env node "use strict"; +import url from "node:url"; +import fs from "node:fs"; process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; -const fs = require("fs"); -const testfsjson = require("./testfs.json"); +const testfsjson = JSON.parse(fs.readFileSync(__dirname + "/testfs.json", "utf-8")); const SHOW_LOGS = false; const STOP_ON_FIRST_FAILURE = false; diff --git a/tests/devices/virtio_balloon.js b/tests/devices/virtio_balloon.js index f53e6eeb..89474aa0 100755 --- a/tests/devices/virtio_balloon.js +++ b/tests/devices/virtio_balloon.js @@ -1,13 +1,15 @@ #!/usr/bin/env node "use strict"; +import assert from "assert/strict"; +import url from "node:url"; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); -const assert = require("assert").strict; const SHOW_LOGS = false; function wait(time) { diff --git a/tests/devices/virtio_console.js b/tests/devices/virtio_console.js index 91d20b40..c7efefd4 100755 --- a/tests/devices/virtio_console.js +++ b/tests/devices/virtio_console.js @@ -1,13 +1,17 @@ #!/usr/bin/env node "use strict"; +import assert from "assert/strict"; +import fs from "node:fs"; +import url from "node:url"; +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; const SHOW_LOGS = false; -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; -const fs = require("fs"); +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); + const emulator = new V86({ bios: { url: __dirname + "/../../bios/seabios.bin" }, diff --git a/tests/devices/wisp_network.js b/tests/devices/wisp_network.js index f8bad868..dadd5836 100755 --- a/tests/devices/wisp_network.js +++ b/tests/devices/wisp_network.js @@ -1,13 +1,16 @@ #!/usr/bin/env -S node --experimental-websocket "use strict"; +import assert from "assert/strict"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); -const assert = require("assert").strict; const SHOW_LOGS = false; const tests = diff --git a/tests/expect/run.js b/tests/expect/run.js index 9b96072b..83888911 100755 --- a/tests/expect/run.js +++ b/tests/expect/run.js @@ -1,17 +1,23 @@ #!/usr/bin/env node "use strict"; +import fs from "node:fs"; +import path from "node:path"; +import assert from "node:assert/strict"; +import url from "node:url"; +import wabtfactory from "../../build/libwabt.cjs"; + + +import { spawnSync } from "node:child_process"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); -const { spawnSync } = require("child_process"); - -const libwabt = require("../../build/libwabt.js")(); +const libwabt = wabtfactory(); try { - var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; + var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); } catch(e) { console.error(e); diff --git a/tests/full/run.js b/tests/full/run.js index c65986d3..c2e8f319 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -1,6 +1,14 @@ #!/usr/bin/env node "use strict"; +import assert from "node:assert/strict"; +import cluster from "node:cluster"; +import os from "node:os"; +import fs from "node:fs"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + process.on("unhandledRejection", exn => { throw exn; }); var TIMEOUT_EXTRA_FACTOR = +process.env.TIMEOUT_EXTRA_FACTOR || 1; @@ -14,7 +22,7 @@ const LOG_SCREEN = false; try { - var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; + var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); } catch(e) { @@ -22,10 +30,6 @@ catch(e) process.exit(1); } -const assert = require("assert").strict; -var cluster = require("cluster"); -var os = require("os"); -var fs = require("fs"); var root_path = __dirname + "/../.."; var SCREEN_WIDTH = 80; @@ -79,7 +83,7 @@ function send_work_to_worker(worker, message) } } -if(cluster.isMaster) +if(cluster.isPrimary) { var tests = [ { @@ -918,7 +922,6 @@ if(cluster.isMaster) var worker = cluster.fork(); worker.on("message", send_work_to_worker.bind(null, worker)); - worker.on("online", send_work_to_worker.bind(null, worker)); worker.on("exit", function(code, signal) { @@ -949,6 +952,7 @@ else process.send("I'm done"); }); }); + process.send("up"); } function bytearray_starts_with(arr, search) diff --git a/tests/jit-paging/run.js b/tests/jit-paging/run.js index 4bdc903c..fc4396a7 100755 --- a/tests/jit-paging/run.js +++ b/tests/jit-paging/run.js @@ -1,12 +1,15 @@ #!/usr/bin/env node "use strict"; +import fs from "node:fs"; +import url from "node:url"; process.on("unhandledRejection", exn => { throw exn; }); +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; -var fs = require("fs"); +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); + var test_executable = new Uint8Array(fs.readFileSync(__dirname + "/test-jit")); diff --git a/tests/kvm-unit-tests/run.js b/tests/kvm-unit-tests/run.mjs similarity index 83% rename from tests/kvm-unit-tests/run.js rename to tests/kvm-unit-tests/run.mjs index ed683b3a..f8f64d46 100755 --- a/tests/kvm-unit-tests/run.js +++ b/tests/kvm-unit-tests/run.mjs @@ -1,12 +1,17 @@ #!/usr/bin/env node "use strict"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + process.on("unhandledRejection", exn => { throw exn; }); const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; -var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; -var fs = require("fs"); +var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); function readfile(path) { diff --git a/tests/nasm/create_tests.js b/tests/nasm/create_tests.js index 05d50470..9967955d 100755 --- a/tests/nasm/create_tests.js +++ b/tests/nasm/create_tests.js @@ -1,6 +1,20 @@ #!/usr/bin/env node "use strict"; +import fs from "node:fs"; +import fse from "node:fs/promises"; +import path from "node:path"; +import assert from "node:assert/strict"; +import util from "node:util"; +import url from "node:url"; +import { execFile as execFileAsync } from "node:child_process"; + +import encodings from "../../gen/x86_table.js"; +import Rand from "./rand.js"; + + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + // number of tests per instruction const NUMBER_TESTS = 5; // arithmetic tests @@ -19,14 +33,7 @@ const OF = 1 << 11; const BUILD_DIR = __dirname + "/build/"; const LOG_VERBOSE = false; -const assert = require("assert").strict; -const fs = require("fs"); -const fse = require("fs/promises"); -const path = require("path"); -const encodings = require("../../gen/x86_table.js"); -const util = require("util"); -const execFile = util.promisify(require("child_process").execFile); -const Rand = require("./rand.js"); +const execFile = util.promisify(execFileAsync); const header = fs.readFileSync(path.join(__dirname, "header.inc")); const footer = fs.readFileSync(path.join(__dirname, "footer.inc")); diff --git a/tests/nasm/gen_fixtures.js b/tests/nasm/gen_fixtures.js index 9e5302c8..36922117 100755 --- a/tests/nasm/gen_fixtures.js +++ b/tests/nasm/gen_fixtures.js @@ -1,11 +1,14 @@ #!/usr/bin/env node "use strict"; -const assert = require("assert").strict; -const fs = require("fs"); -const os = require("os"); -const path = require("path"); -const { spawn, spawnSync } = require("child_process"); +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import assert from "node:assert/strict"; +import os from "node:os"; +import { spawn, spawnSync } from "node:child_process"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const DEBUG = process.env.DEBUG || false; // Maximum number of gdb processes to spawn in parallel diff --git a/tests/nasm/rand.js b/tests/nasm/rand.js index eae47778..66076e49 100644 --- a/tests/nasm/rand.js +++ b/tests/nasm/rand.js @@ -1,5 +1,4 @@ "use strict"; -const assert = require("assert"); // From http://baagoe.com/en/RandomMusings/javascript/ // Johannes Baagøe , 2010 @@ -25,7 +24,7 @@ function Mash() { } // From http://baagoe.com/en/RandomMusings/javascript/ -function KISS07() { +export default function KISS07() { return (function(args) { // George Marsaglia, 2007-06-23 //http://groups.google.com/group/comp.lang.fortran/msg/6edb8ad6ec5421a5 @@ -100,5 +99,3 @@ function KISS07() { }; } (Array.prototype.slice.call(arguments))); } - -module.exports = KISS07; diff --git a/tests/nasm/run.js b/tests/nasm/run.js index 04a5ade9..8926a824 100755 --- a/tests/nasm/run.js +++ b/tests/nasm/run.js @@ -1,6 +1,15 @@ #!/usr/bin/env node "use strict"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import assert from "node:assert/strict"; +import os from "node:os"; +import cluster from "node:cluster"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + process.on("unhandledRejection", exn => { throw exn; }); // Mapping between signals and x86 exceptions: @@ -15,12 +24,6 @@ process.on("unhandledRejection", exn => { throw exn; }); // A #UD might indicate a bug in the test generation -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); -const os = require("os"); -const cluster = require("cluster"); - const MAX_PARALLEL_TESTS = +process.env.MAX_PARALLEL_TESTS || 99; const TEST_NAME = new RegExp(process.env.TEST_NAME || "", "i"); const SINGLE_TEST_TIMEOUT = 10000; @@ -29,6 +32,7 @@ const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; const TEST_DIR = __dirname + "/build/"; const DONE_MSG = "DONE"; const TERMINATE_MSG = "DONE"; +const READY_MSG = "READY"; const BSS = 0x100000; const STACK_TOP = 0x102000; @@ -47,7 +51,7 @@ const FPU_STATUS_MASK = 0xFFFF & ~(1 << 9 | 1 << 5 | 1 << 3 | 1 << 1); // bits t const FP_COMPARISON_SIGNIFICANT_DIGITS = 7; try { - var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; + var { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); } catch(e) { console.error(e); @@ -202,14 +206,12 @@ if(cluster.isMaster) let worker = cluster.fork(); worker.on("message", function(message) { - if(message !== DONE_MSG) { + if(message !== DONE_MSG && message !== READY_MSG) { failed_tests.push(message); } send_work_to_worker(this); }); - worker.on("online", send_work_to_worker.bind(null, worker)); - worker.on("exit", function(code, signal) { if(code !== 0 && code !== null) { console.log("Worker error code:", code); @@ -548,4 +550,6 @@ else { run_test(message); } }); + + process.send(READY_MSG); } diff --git a/tests/qemu/run-qemu.js b/tests/qemu/run-qemu.js index 6e54a45b..ce477bc3 100755 --- a/tests/qemu/run-qemu.js +++ b/tests/qemu/run-qemu.js @@ -1,12 +1,15 @@ #!/usr/bin/env node "use strict"; -const QEMU = "qemu-system-x86_64"; +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import assert from "node:assert/strict"; +import { spawn, spawnSync } from "node:child_process"; -const assert = require("assert").strict; -const fs = require("fs"); -const { spawn, spawnSync } = require("child_process"); -const path = require("path"); +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + +const QEMU = "qemu-system-x86_64"; const share_dir_9p = fs.mkdtempSync("/tmp/v86-test-qemu-9p"); diff --git a/tests/qemu/run.js b/tests/qemu/run.js index 44d540d3..877d4061 100755 --- a/tests/qemu/run.js +++ b/tests/qemu/run.js @@ -10,7 +10,7 @@ import path from "path"; import fs from "fs"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const { default: { V86 } } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`); +const { V86 } = await import(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.mjs`); var test_executable = new Uint8Array(fs.readFileSync(__dirname + "/test-i386")); diff --git a/tests/rust/verify-wasmgen-dummy-output.js b/tests/rust/verify-wasmgen-dummy-output.js index e8612e2a..85494334 100755 --- a/tests/rust/verify-wasmgen-dummy-output.js +++ b/tests/rust/verify-wasmgen-dummy-output.js @@ -1,11 +1,15 @@ #!/usr/bin/env node "use strict"; -process.on("unhandledRejection", exn => { throw exn; }); -const assert = require("assert").strict; -const fs = require("fs"); -const path = require("path"); +import fs from "node:fs"; +import path from "node:path"; +import url from "node:url"; +import assert from "node:assert/strict"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + +process.on("unhandledRejection", exn => { throw exn; }); const DUMMY_MODULE_PATH = path.resolve(__dirname, "../../build/dummy_output.wasm"); const dummy_module = fs.readFileSync(DUMMY_MODULE_PATH); diff --git a/tools/docker/alpine/build-state.js b/tools/docker/alpine/build-state.js index fd866b9b..616622dc 100755 --- a/tools/docker/alpine/build-state.js +++ b/tools/docker/alpine/build-state.js @@ -1,11 +1,14 @@ #!/usr/bin/env node "use strict"; +import path from "node:path"; +import fs from "node:fs"; +import url from "node:url"; + console.log("Don't forget to run `make all` before running this script"); -const path = require("path"); -const fs = require("fs"); -const V86 = require("./../../../build/libv86.js").V86; +const { V86 } = await import("./../../../build/libv86.js"); +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); const V86_ROOT = path.join(__dirname, "../../.."); const OUTPUT_FILE = path.join(V86_ROOT, "images/alpine-state.bin");