# QEMURunner.gd # Alpine Linux ARM64 QEMU Runner as a Node # Add to your scene and call run_vm() extends Node # Configuration const ALP_ARCH = "aarch64" const PORT = "2221" var DISK_NAME = "alpine.%s.qcow2" % ALP_ARCH # Working directory - qemu/ folder in project root var working_dir: String = "" @export var run_button: Button @export var code_edit: CodeEdit signal vm_started() signal vm_stopped(exit_code: int) signal vm_error(error_message: String) var qemu_pid: int = -1 func handle_run(): print(code_edit.text) func _ready(): # Set working directory to PROJECT_ROOT/qemu/ working_dir = ProjectSettings.globalize_path("res://qemu/") print("QEMU working directory: %s" % working_dir) # Create qemu directory if it doesn't exist if not DirAccess.dir_exists_absolute(working_dir): DirAccess.make_dir_recursive_absolute(working_dir) print("Created qemu directory: %s" % working_dir) run_vm() run_button.button_up.connect(handle_run) func _exit_tree() -> void: stop_vm() func check_file_exists(filename: String) -> bool: """Check if required file exists in working directory""" var full_path = working_dir.path_join(filename) print(full_path) if not FileAccess.file_exists(full_path): print("Error: %s not found!" % full_path) return false return true func run_vm(): print("Alpine Linux ARM64 QEMU Runner") print() # Check required files var required_files = [ "AAVMF_CODE.fd", DISK_NAME ] var missing_files = [] for file in required_files: if not check_file_exists(file): missing_files.append(file) if not missing_files.is_empty(): print("\nMissing required files:") for file in missing_files: print(" - %s" % file) print("\nPlease run the setup script first to create these files.") vm_error.emit("Missing required files: " + str(missing_files)) return # Display connection info print("Starting Alpine Linux VM...") print("SSH Port: %s" % PORT) print("Connect with: ssh -p %s @localhost" % PORT) print() print("To exit QEMU: Press Ctrl+A then X") print() # Build QEMU command var qemu_cmd = PackedStringArray([ "qemu-system-aarch64", "-accel", "tcg,thread=multi", "-machine", "virt", "-cpu", "cortex-a53", "-smp", "cores=1", "-m", "512", "-bios", working_dir.path_join("AAVMF_CODE.fd"), "-nographic", "-drive", "if=virtio,id=hd,format=qcow2,file=%s" % working_dir.path_join(DISK_NAME), "-nic", "user,hostfwd=tcp::%s-:22,model=virtio" % PORT, "-device", "virtio-rng-pci", "-rtc", "base=utc,clock=host", "-s" ]) # Run QEMU vm_started.emit() qemu_pid = OS.create_process(qemu_cmd[0], qemu_cmd.slice(1)) if qemu_pid == -1: print("\nError: qemu-system-aarch64 not found in PATH") print("Please install QEMU for Windows: https://qemu.weilnetz.de/w64/") print("Make sure qemu-system-aarch64 is in your system PATH") vm_error.emit("Failed to start QEMU process") return print("QEMU started with PID: %d" % qemu_pid) func stop_vm(): print("Attempting to kill QEMU") if qemu_pid != -1: OS.kill(qemu_pid) print("QEMU stopped") vm_stopped.emit(0) qemu_pid = -1