WEMU
The machine. Launched from a wemu-system-aarch64 command line, driven through QMP and the human monitor, exactly like a QEMU process.
WEMU is Warm64's one public interface. You launch it with the same command line you would give qemu-system-aarch64, and control it with QEMU's own protocol (QMP) and monitor (HMP). There is no separate options object: the command line is the machine's configuration.
import { WEMU } from "warm64";
import { nodeWEMUHost } from "warm64/wemu-node";
const vm = await WEMU.launch(
"-M virt -m 1G -S -display none -kernel vmlinuz-virt -initrd initramfs-virt -append console=ttyAMA0",
nodeWEMUHost(),
);
vm.serial[0].onData((bytes) => process.stdout.write(bytes));
await vm.qmp("cont");
const { code } = await vm.wait();Static methods
WEMU.launch()
Builds a machine from a command line and starts it.
WEMU.launch(args, host): Promise<WEMU>Parameters
| Parameter | Type | Description |
|---|---|---|
args | string, string[] or WEMUConfig | A wemu-system-aarch64 command line: one string split like a POSIX shell would (a leading qemu-system-aarch64 or wemu-system-aarch64 is dropped), an argv array, or a config already parsed by parseWEMUArgs(). See the command-line reference. |
host | WEMUHost | What the platform lends the machine: its WebAssembly modules, files, disks, sockets, display and sound. Use nodeWEMUHost() in Node or browserWEMUHost() in a browser. |
Return value
A promise that resolves to the running (or, with -S, paused) WEMU once the machine is built.
Exceptions
WEMUErrorwhen the command line is refused, in QEMU's wording: an unknown option, something this machine doesn't have (KVM, VNC,-dtb, more than 8 CPUs), or nothing to boot (no-kernel,-biosor-pflash).WEMUErrorcarrying the help or version text for-helpand-version.- A plain
Errorwhen a file can't be read (for example"<url>: 404 Not Found"in a browser) or the kernel image isn't one it can boot.
If anything fails after the machine is built, launch() releases it before rethrowing.
Tip Unless the command line has -S, the machine starts running inside launch(), before your code can attach listeners, so its first console output is lost. Launch with -S, attach onData, then await vm.qmp("cont").
Instance properties
| Property | Type | Description |
|---|---|---|
config | WEMUConfig | The parsed command line the machine was built from. |
host | WEMUHost | The host it was launched with. |
serial | WEMUChardevPort[] | The serial ports. serial[0] is the guest's ttyAMA0 console and always exists; serial[1] exists with a second -serial. |
chardevs | Map<string, WEMUChardevPort> | Every character device by id: serial0, serial1 and each -chardev. |
shares | Map<string, WEMUShare> | Shared folders by mount tag. See WEMUShare. |
status | WEMURunState | The run state, as query-status reports it (read-only). See Run states. |
Instance methods
qmp()
Runs a QMP command and resolves with its return value.
vm.qmp(command, args = {}): Promise<unknown>It rejects with a QmpError whose class and desc are what QEMU would send (GenericError, CommandNotFound, DeviceNotFound…). The commands are listed in the QMP reference.
const { status } = await vm.qmp("query-status"); // "running"
await vm.qmp("screendump", { filename: "shot.png", format: "png" });qmpJson()
Runs one QMP message given as JSON text and resolves with the reply as JSON text. It never rejects: errors come back as QMP error replies. Use it to bridge a QMP client you already have.
const reply = await vm.qmpJson('{"execute":"query-status"}');
// the reply as JSON text: {"return": {"status": "running", ...}}hmp()
Runs a human monitor command and resolves with the text it prints.
console.log(await vm.hmp("info block"));
await vm.hmp("savevm before-upgrade");It rejects with QmpError("GenericError", …) for an unknown command or bad arguments, for example unknown command: 'x'.
on()
Listens for a QMP event by name, or for every event with "*". Returns a function that removes the listener. Listeners are called synchronously, with a QmpEvent: { event, data?, timestamp: { seconds, microseconds } }.
const off = vm.on("SHUTDOWN", (e) => console.log(e.data.reason));
vm.on("*", (e) => console.log(e.event));See Events for what is emitted.
wait()
Resolves with { code } when the machine exits: on quit, or when the guest powers off (unless -no-shutdown keeps it). The code is what the wemu-system-aarch64 process would exit with: 0 normally, 1 after a panic with -action panic=shutdown.
setUIInfo()
Offers the guest a display size, the way resizing a QEMU window does. Returns false without a virtio-gpu device or when the size is refused.
vm.setUIInfo({ width: 1280, height: 800 });quit()
Stops the machine and releases it. Emits SHUTDOWN with reason: "host-qmp-quit" and resolves wait() with { code: 0 }. Calling it again does nothing.
Run states
status and query-status report QEMU's run states:
| State | When |
|---|---|
running | Running. |
prelaunch | Launched with -S and not yet continued. |
paused | Stopped with stop. |
inmigrate | Launched with -incoming defer, waiting for migrate-incoming. |
postmigrate | After migrate to a file. |
guest-panicked | The guest panicked with -action panic=pause (the default). |
shutdown | The guest powered off with -no-shutdown. cont is refused until the machine is reset. |
Events
| Event | Data | When |
|---|---|---|
STOP | none | The machine paused: stop, or a guest panic. |
RESUME | none | It continued. |
RESET | { guest, reason } | system_reset, or a guest reboot. |
POWERDOWN | none | system_powerdown pressed the power button. |
SHUTDOWN | { guest, reason } | The guest powered off (guest-shutdown), rebooted with -no-reboot (guest-reset), or the host quit (host-qmp-quit). |
GUEST_PANICKED | { action, info } | The guest kernel panicked. |
MIGRATION | { status } | A migrate or migrate-incoming changed state. |
JOB_STATUS_CHANGE | { id, status } | A snapshot-save, snapshot-load or snapshot-delete job moved on. |
DUMP_COMPLETED | none | dump-guest-memory finished. |
WEMUChardevPort
A serial port or -chardev: a stream of bytes to and from the guest.
| Member | Description |
|---|---|
id | The character device's id, for example serial0. |
onData(listener) | Calls listener(bytes: Uint8Array) with what the guest writes. The bytes are a fresh copy you may keep. Returns a function that removes the listener. |
write(data) | Sends a Uint8Array, or a string as UTF-8, to the guest. |
sendBreak() | Sends a serial break (only on serial0). |
hasRing | true for a ringbuf chardev, which QMP's ringbuf-read and ringbuf-write reach. |
vm.serial[0].onData((bytes) => process.stdout.write(bytes));
vm.serial[0].write("uname -a\n");WEMUShare
A shared folder the guest mounts with virtio-fs or 9p (see Shared folders). Its tree lives in memory: put files in before or while the guest runs, and read back what the guest wrote.
| Method | Description |
|---|---|
put(path, data, mode = 0o644) | Writes a file, creating its parent directories. Throws on failure. |
get(path) | The file's bytes, or null when it's absent or a directory. |
list(path = "/") | The directory's entries (subdirectories end with /), or null when it isn't a directory. |
mkdir(path) | Creates a directory. |
remove(path) | Removes a file or an empty directory. |
vm.shares.get("host").put("input/config.json", new TextEncoder().encode("{}"));See also
- Hosts:
WEMUHost,nodeWEMUHost(),browserWEMUHost() - Node helpers and utilities
- QMP reference and monitor reference