virtual-machine 0.0.31 → 0.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export { WorkerErrorMessage, WorkerHaltedMessage, WorkerInitMessage, WorkerOutboundMessage, WorkerReadyMessage } from './worker.js';
2
-
3
1
  /* tslint:disable */
4
2
  /* eslint-disable */
5
3
 
@@ -18,6 +16,9 @@ declare class WasmVm {
18
16
  [Symbol.dispose](): void;
19
17
  /**
20
18
  * Get a byte from the UART output buffer, if available.
19
+ *
20
+ * In SMP mode, this checks both the shared UART output buffer (for worker output)
21
+ * and the local UART buffer (for hart 0 output).
21
22
  */
22
23
  get_output(): number | undefined;
23
24
  /**
@@ -29,15 +30,42 @@ declare class WasmVm {
29
30
  * Print a status message to UART output (visible in browser).
30
31
  */
31
32
  print_status(message: string): void;
33
+ /**
34
+ * Start worker threads for secondary harts (1..num_harts).
35
+ *
36
+ * Workers run in parallel with the main thread, sharing DRAM and CLINT
37
+ * via SharedArrayBuffer.
38
+ *
39
+ * # Arguments
40
+ * * `worker_url` - URL to the worker script (e.g., "/worker.js")
41
+ */
42
+ start_workers(worker_url: string): void;
32
43
  /**
33
44
  * Get the current network connection status.
34
45
  * This checks the actual connection state by seeing if an IP was assigned.
35
46
  */
36
47
  network_status(): NetworkStatus;
48
+ /**
49
+ * Create a new VM instance with a specified number of harts.
50
+ *
51
+ * # Arguments
52
+ * * `kernel` - ELF kernel binary
53
+ * * `num_harts` - Number of harts (0 = auto-detect)
54
+ */
55
+ static new_with_harts(kernel: Uint8Array, num_harts: number): WasmVm;
37
56
  /**
38
57
  * Get current memory usage (DRAM size) in bytes.
39
58
  */
40
59
  get_memory_usage(): bigint;
60
+ /**
61
+ * Get the SharedArrayBuffer for external worker management.
62
+ * Returns None if not in SMP mode.
63
+ */
64
+ get_shared_buffer(): SharedArrayBuffer | undefined;
65
+ /**
66
+ * Terminate all workers.
67
+ */
68
+ terminate_workers(): void;
41
69
  /**
42
70
  * Disconnect from the network.
43
71
  */
@@ -52,19 +80,74 @@ declare class WasmVm {
52
80
  * Note: Connection is asynchronous. Check network_status() to monitor connection state.
53
81
  */
54
82
  connect_webtransport(url: string, cert_hash?: string | null): void;
83
+ /**
84
+ * Inject a network packet to be received by the guest.
85
+ * Called from JavaScript when the native WebTransport addon receives a packet.
86
+ */
87
+ inject_network_packet(packet: Uint8Array): boolean;
88
+ /**
89
+ * Extract a network packet sent by the guest.
90
+ * Returns the packet data or null if no packet is pending.
91
+ */
92
+ extract_network_packet(): Uint8Array | undefined;
93
+ /**
94
+ * Set up an external network backend for packet bridging.
95
+ * This is used by the Node.js CLI to bridge packets between the native
96
+ * WebTransport addon and the WASM VM.
97
+ *
98
+ * @param mac_bytes - MAC address as 6 bytes [0x52, 0x54, 0x00, 0x12, 0x34, 0x56]
99
+ */
100
+ setup_external_network(mac_bytes: Uint8Array): void;
101
+ /**
102
+ * Set the assigned IP address for the external network.
103
+ * Called when the native WebTransport addon receives an IP assignment.
104
+ */
105
+ set_external_network_ip(ip_bytes: Uint8Array): boolean;
106
+ /**
107
+ * Get the number of pending RX packets.
108
+ */
109
+ external_network_rx_pending(): number;
110
+ /**
111
+ * Get the number of pending TX packets.
112
+ */
113
+ external_network_tx_pending(): number;
114
+ /**
115
+ * Extract all pending network packets sent by the guest.
116
+ * Returns an array of packet data.
117
+ */
118
+ extract_all_network_packets(): Array<any>;
119
+ /**
120
+ * Check if external network is connected (has IP assigned).
121
+ */
122
+ is_external_network_connected(): boolean;
55
123
  /**
56
124
  * Create a new VM instance and load a kernel (ELF or raw binary).
125
+ *
126
+ * If SharedArrayBuffer is available, the VM will use true parallel
127
+ * execution with Web Workers. Otherwise, falls back to single-threaded mode.
128
+ *
129
+ * Hart count is auto-detected as half of hardware_concurrency.
130
+ * Use `new_with_harts()` to specify a custom hart count.
57
131
  */
58
132
  constructor(kernel: Uint8Array);
59
133
  /**
60
- * Execute one instruction on each CPU (round-robin).
134
+ * Execute one instruction on hart 0 (primary hart).
135
+ *
136
+ * In SMP mode, secondary harts run in Web Workers and execute in parallel.
137
+ * This method only steps hart 0, which handles I/O coordination.
138
+ *
61
139
  * Returns true if the VM is still running, false if halted.
62
140
  */
63
141
  step(): boolean;
64
142
  /**
65
143
  * Push an input byte to the UART.
144
+ * In SMP mode, this also writes to the shared input buffer so workers can receive it.
66
145
  */
67
146
  input(byte: number): void;
147
+ /**
148
+ * Check if running in SMP mode (with workers).
149
+ */
150
+ is_smp(): boolean;
68
151
  /**
69
152
  * Execute up to N instructions in a batch.
70
153
  * Returns the number of instructions actually executed.
@@ -86,15 +169,75 @@ declare class WasmVm {
86
169
  * This should be called before starting execution if the kernel needs a filesystem.
87
170
  */
88
171
  load_disk(disk_image: Uint8Array): void;
172
+ /**
173
+ * Get the number of harts configured.
174
+ */
175
+ num_harts(): number;
176
+ }
177
+
178
+ declare class WorkerState {
179
+ free(): void;
180
+ [Symbol.dispose](): void;
181
+ /**
182
+ * Execute a batch of instructions and return.
183
+ *
184
+ * This is designed to be called repeatedly from JavaScript, allowing
185
+ * the event loop to yield between batches. This prevents the worker
186
+ * from blocking indefinitely and allows it to respond to messages.
187
+ *
188
+ * Returns a WorkerStepResult indicating whether to continue, halt, etc.
189
+ */
190
+ step_batch(batch_size: number): WorkerStepResult;
191
+ /**
192
+ * Get the total step count.
193
+ */
194
+ step_count(): bigint;
195
+ /**
196
+ * Create a new worker state for a secondary hart.
197
+ */
198
+ constructor(hart_id: number, shared_mem: any, entry_pc: bigint);
199
+ /**
200
+ * Get the hart ID.
201
+ */
202
+ hart_id(): number;
203
+ }
204
+
205
+ /**
206
+ * Result of executing a batch of instructions.
207
+ */
208
+ declare enum WorkerStepResult {
209
+ /**
210
+ * Continue executing - call step_batch again
211
+ */
212
+ Continue = 0,
213
+ /**
214
+ * Halt requested via control region
215
+ */
216
+ Halted = 1,
217
+ /**
218
+ * Shutdown requested by guest (RequestedTrap)
219
+ */
220
+ Shutdown = 2,
221
+ /**
222
+ * Fatal error occurred
223
+ */
224
+ Error = 3,
89
225
  }
90
226
 
91
227
  /**
92
- * Worker entry point, called from JavaScript.
228
+ * Check interrupts for this hart using the shared CLINT.
93
229
  *
94
- * # Arguments
95
- * * `hart_id` - This worker's hart ID (1, 2, 3, ...)
96
- * * `shared_mem` - SharedArrayBuffer containing DRAM
97
- * * `entry_pc` - Kernel entry point address
230
+ * This is called periodically by the worker to check for:
231
+ * - Software interrupts (IPI via MSIP)
232
+ * - Timer interrupts (MTIP)
233
+ */
234
+ declare function worker_check_interrupts(hart_id: number, shared_mem: any): bigint;
235
+
236
+ /**
237
+ * Legacy worker entry point - DEPRECATED.
238
+ *
239
+ * This function runs a blocking infinite loop. Use WorkerState + step_batch instead
240
+ * for cooperative scheduling that doesn't block the worker's event loop.
98
241
  */
99
242
  declare function worker_entry(hart_id: number, shared_mem: any, entry_pc: bigint): void;
100
243
 
@@ -103,27 +246,48 @@ type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Modul
103
246
  interface InitOutput {
104
247
  readonly memory: WebAssembly.Memory;
105
248
  readonly __wbg_wasmvm_free: (a: number, b: number) => void;
249
+ readonly __wbg_workerstate_free: (a: number, b: number) => void;
106
250
  readonly wasmvm_connect_webtransport: (a: number, b: number, c: number, d: number, e: number) => [number, number];
107
251
  readonly wasmvm_disconnect_network: (a: number) => void;
252
+ readonly wasmvm_external_network_rx_pending: (a: number) => number;
253
+ readonly wasmvm_external_network_tx_pending: (a: number) => number;
254
+ readonly wasmvm_extract_all_network_packets: (a: number) => any;
255
+ readonly wasmvm_extract_network_packet: (a: number) => any;
108
256
  readonly wasmvm_get_memory_usage: (a: number) => bigint;
109
257
  readonly wasmvm_get_output: (a: number) => number;
258
+ readonly wasmvm_get_shared_buffer: (a: number) => any;
110
259
  readonly wasmvm_halt_code: (a: number) => bigint;
260
+ readonly wasmvm_inject_network_packet: (a: number, b: any) => number;
111
261
  readonly wasmvm_input: (a: number, b: number) => void;
262
+ readonly wasmvm_is_external_network_connected: (a: number) => number;
112
263
  readonly wasmvm_is_halted: (a: number) => number;
264
+ readonly wasmvm_is_smp: (a: number) => number;
113
265
  readonly wasmvm_load_disk: (a: number, b: number, c: number) => void;
114
266
  readonly wasmvm_network_status: (a: number) => number;
115
267
  readonly wasmvm_new: (a: number, b: number) => [number, number, number];
268
+ readonly wasmvm_new_with_harts: (a: number, b: number, c: number) => [number, number, number];
269
+ readonly wasmvm_num_harts: (a: number) => number;
116
270
  readonly wasmvm_print_banner: (a: number) => void;
117
271
  readonly wasmvm_print_status: (a: number, b: number, c: number) => void;
272
+ readonly wasmvm_set_external_network_ip: (a: number, b: any) => number;
273
+ readonly wasmvm_setup_external_network: (a: number, b: any) => [number, number];
274
+ readonly wasmvm_start_workers: (a: number, b: number, c: number) => [number, number];
118
275
  readonly wasmvm_step: (a: number) => number;
119
276
  readonly wasmvm_step_n: (a: number, b: number) => number;
277
+ readonly wasmvm_terminate_workers: (a: number) => void;
120
278
  readonly wasmvm_uart_output_pending: (a: number) => number;
279
+ readonly worker_check_interrupts: (a: number, b: any) => bigint;
121
280
  readonly worker_entry: (a: number, b: any, c: bigint) => void;
122
- readonly wasm_bindgen__convert__closures_____invoke__h5a9b831ab69bf07a: (a: number, b: number) => void;
123
- readonly wasm_bindgen__closure__destroy__h101a38767d457860: (a: number, b: number) => void;
124
- readonly wasm_bindgen__convert__closures_____invoke__hc493fd296d4613a9: (a: number, b: number) => void;
281
+ readonly workerstate_hart_id: (a: number) => number;
282
+ readonly workerstate_new: (a: number, b: any, c: bigint) => number;
283
+ readonly workerstate_step_batch: (a: number, b: number) => number;
284
+ readonly workerstate_step_count: (a: number) => bigint;
285
+ readonly wasm_bindgen__convert__closures_____invoke__hbde9876d0cea708c: (a: number, b: number, c: any) => void;
286
+ readonly wasm_bindgen__closure__destroy__h1a8abd1a91785820: (a: number, b: number) => void;
125
287
  readonly wasm_bindgen__convert__closures_____invoke__h39d3e89751b07765: (a: number, b: number, c: any) => void;
126
288
  readonly wasm_bindgen__closure__destroy__hf225e18fc5ab9bc1: (a: number, b: number) => void;
289
+ readonly wasm_bindgen__convert__closures_____invoke__he7a35327fb096d07: (a: number, b: number) => void;
290
+ readonly wasm_bindgen__convert__closures_____invoke__h749506e285e0c000: (a: number, b: number) => void;
127
291
  readonly __wbindgen_malloc: (a: number, b: number) => number;
128
292
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
129
293
  readonly __wbindgen_exn_store: (a: number) => void;
@@ -163,11 +327,64 @@ declare const __pkg_riscv_vm_NetworkStatus: typeof NetworkStatus;
163
327
  type __pkg_riscv_vm_SyncInitInput = SyncInitInput;
164
328
  type __pkg_riscv_vm_WasmVm = WasmVm;
165
329
  declare const __pkg_riscv_vm_WasmVm: typeof WasmVm;
330
+ type __pkg_riscv_vm_WorkerState = WorkerState;
331
+ declare const __pkg_riscv_vm_WorkerState: typeof WorkerState;
332
+ type __pkg_riscv_vm_WorkerStepResult = WorkerStepResult;
333
+ declare const __pkg_riscv_vm_WorkerStepResult: typeof WorkerStepResult;
166
334
  declare const __pkg_riscv_vm_initSync: typeof initSync;
335
+ declare const __pkg_riscv_vm_worker_check_interrupts: typeof worker_check_interrupts;
167
336
  declare const __pkg_riscv_vm_worker_entry: typeof worker_entry;
168
337
  declare namespace __pkg_riscv_vm {
169
- export { type __pkg_riscv_vm_InitInput as InitInput, type __pkg_riscv_vm_InitOutput as InitOutput, __pkg_riscv_vm_NetworkStatus as NetworkStatus, type __pkg_riscv_vm_SyncInitInput as SyncInitInput, __pkg_riscv_vm_WasmVm as WasmVm, __wbg_init as default, __pkg_riscv_vm_initSync as initSync, __pkg_riscv_vm_worker_entry as worker_entry };
338
+ export { type __pkg_riscv_vm_InitInput as InitInput, type __pkg_riscv_vm_InitOutput as InitOutput, __pkg_riscv_vm_NetworkStatus as NetworkStatus, type __pkg_riscv_vm_SyncInitInput as SyncInitInput, __pkg_riscv_vm_WasmVm as WasmVm, __pkg_riscv_vm_WorkerState as WorkerState, __pkg_riscv_vm_WorkerStepResult as WorkerStepResult, __wbg_init as default, __pkg_riscv_vm_initSync as initSync, __pkg_riscv_vm_worker_check_interrupts as worker_check_interrupts, __pkg_riscv_vm_worker_entry as worker_entry };
339
+ }
340
+
341
+ /**
342
+ * Worker utility types and functions.
343
+ *
344
+ * This module contains only types and side-effect-free utility functions
345
+ * that can be safely imported in Node.js or browser environments.
346
+ *
347
+ * The actual worker entry point is in worker.ts (browser-only).
348
+ */
349
+ /** Message sent from main thread to initialize the worker */
350
+ interface WorkerInitMessage {
351
+ hartId: number;
352
+ /** SharedArrayBuffer containing control + CLINT + DRAM */
353
+ sharedMem: SharedArrayBuffer;
354
+ entryPc: number;
170
355
  }
356
+ /** Message sent when worker is ready to execute */
357
+ interface WorkerReadyMessage {
358
+ type: "ready";
359
+ hartId: number;
360
+ }
361
+ /** Message sent when worker has halted */
362
+ interface WorkerHaltedMessage {
363
+ type: "halted";
364
+ hartId: number;
365
+ stepCount?: number;
366
+ }
367
+ /** Message sent when an error occurs */
368
+ interface WorkerErrorMessage {
369
+ type: "error";
370
+ hartId?: number;
371
+ error: string;
372
+ }
373
+ type WorkerOutboundMessage = WorkerReadyMessage | WorkerHaltedMessage | WorkerErrorMessage;
374
+ /**
375
+ * Check if halt has been requested in the shared control region.
376
+ * This can be used for JS-side polling if needed.
377
+ */
378
+ declare function isHaltRequested(sharedMem: SharedArrayBuffer): boolean;
379
+ /**
380
+ * Request halt by setting the flag in shared memory.
381
+ * This can be called from any thread.
382
+ */
383
+ declare function requestHalt(sharedMem: SharedArrayBuffer): void;
384
+ /**
385
+ * Check if VM has halted.
386
+ */
387
+ declare function isHalted(sharedMem: SharedArrayBuffer): boolean;
171
388
 
172
389
  declare function WasmInternal(): Promise<typeof __pkg_riscv_vm>;
173
390
 
@@ -178,7 +395,10 @@ interface VmOptions {
178
395
  workerScript?: string;
179
396
  }
180
397
  /**
181
- * Create a VM instance and optionally start workers for multi-hart execution.
398
+ * Create a VM instance with optional SMP support.
399
+ *
400
+ * If SharedArrayBuffer is available (requires COOP/COEP headers), the VM
401
+ * will run in true parallel mode with Web Workers for secondary harts.
182
402
  *
183
403
  * @param kernelData - ELF kernel binary
184
404
  * @param options - VM configuration options
@@ -188,6 +408,9 @@ declare function createVM(kernelData: Uint8Array, options?: VmOptions): Promise<
188
408
  /**
189
409
  * Run the VM with an output callback for UART data.
190
410
  *
411
+ * This function manages the main execution loop, stepping hart 0 on the
412
+ * main thread. Secondary harts (if any) run in Web Workers.
413
+ *
191
414
  * @param vm - WasmVm instance
192
415
  * @param onOutput - Callback for each character output
193
416
  * @param options - Run options
@@ -198,6 +421,7 @@ declare function runVM(vm: WasmVm, onOutput: (char: string) => void, options?: {
198
421
  }): () => void;
199
422
  interface SharedMemorySupport {
200
423
  supported: boolean;
424
+ crossOriginIsolated: boolean;
201
425
  message: string;
202
426
  }
203
427
  /**
@@ -211,5 +435,41 @@ declare function checkSharedMemorySupport(): SharedMemorySupport;
211
435
  * Check if the page is cross-origin isolated (required for SharedArrayBuffer).
212
436
  */
213
437
  declare function isCrossOriginIsolated(): boolean;
438
+ /**
439
+ * Headers required for SharedArrayBuffer support.
440
+ *
441
+ * For Vite dev server, add to vite.config.ts:
442
+ * ```ts
443
+ * server: {
444
+ * headers: {
445
+ * "Cross-Origin-Opener-Policy": "same-origin",
446
+ * "Cross-Origin-Embedder-Policy": "require-corp",
447
+ * },
448
+ * },
449
+ * ```
450
+ *
451
+ * For production, configure your web server to add these headers.
452
+ */
453
+ declare const REQUIRED_HEADERS: {
454
+ readonly "Cross-Origin-Opener-Policy": "same-origin";
455
+ readonly "Cross-Origin-Embedder-Policy": "require-corp";
456
+ };
457
+ /**
458
+ * Manually create and manage workers for advanced use cases.
459
+ *
460
+ * Most users should use createVM() which handles workers automatically.
461
+ */
462
+ interface WorkerManager {
463
+ /** Start a worker for a specific hart */
464
+ startWorker(hartId: number, sharedMem: SharedArrayBuffer, entryPc: number, workerScript?: string): Worker;
465
+ /** Terminate all workers */
466
+ terminateAll(): void;
467
+ /** Get number of active workers */
468
+ count(): number;
469
+ }
470
+ /**
471
+ * Create a worker manager for manual worker control.
472
+ */
473
+ declare function createWorkerManager(): WorkerManager;
214
474
 
215
- export { NetworkStatus, type SharedMemorySupport, type VmOptions, WasmInternal, WasmVm, checkSharedMemorySupport, createVM, isCrossOriginIsolated, runVM };
475
+ export { NetworkStatus, REQUIRED_HEADERS, type SharedMemorySupport, type VmOptions, WasmInternal, WasmVm, type WorkerErrorMessage, type WorkerHaltedMessage, type WorkerInitMessage, type WorkerManager, type WorkerOutboundMessage, type WorkerReadyMessage, checkSharedMemorySupport, createVM, createWorkerManager, isCrossOriginIsolated, isHaltRequested, isHalted, requestHalt, runVM };