diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/_index.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/_index.md new file mode 100644 index 0000000000..e6ca39d6f4 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/_index.md @@ -0,0 +1,53 @@ +--- +title: Windows on Arm virtual machine creation using Arm Linux, QEMU, and KVM + +draft: true +cascade: + draft: true + +minutes_to_complete: 90 + +who_is_this_for: This is for developers and system administrators who want to automate Windows on Arm virtual machine (VM) creation on Arm Linux systems using QEMU and KVM. + +learning_objectives: + - Understand the process of creating Windows on Arm virtual machine using Bash scripts. + - Run scripts for VM creation and management. + - Troubleshoot common VM setup and runtime issues. + - Use Windows on Arm virtual machines for software development and testing. + +prerequisites: + - An Arm Linux system with KVM support and a minimum of 8GB RAM and 50GB free disk space. + +author: Jason Andrews + +### Tags +skilllevels: Introductory +subjects: Migration to Arm +armips: + - Neoverse + - Cortex-A +operatingsystems: + - Linux + - Windows +tools_software_languages: + - QEMU + - KVM + - Bash + - RDP + +further_reading: + - resource: + title: Linaro Wiki - Windows on Arm + link: https://wiki.linaro.org/LEG/Engineering/Kernel/WindowsOnArm + type: documentation + - resource: + title: Botspot Virtual Machine (BVM) Project + link: https://github.com/Botspot/bvm + type: website + +### FIXED, DO NOT MODIFY +# ================================================================================ +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/_next-steps.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/_next-steps.md new file mode 100644 index 0000000000..c3db0de5a2 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ================================================================================ +# FIXED, DO NOT MODIFY THIS FILE +# ================================================================================ +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/images/win11arm.png b/content/learning-paths/laptops-and-desktops/win11-vm-automation/images/win11arm.png new file mode 100644 index 0000000000..4f31c8b4f5 Binary files /dev/null and b/content/learning-paths/laptops-and-desktops/win11-vm-automation/images/win11arm.png differ diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/prerequisites-1.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/prerequisites-1.md new file mode 100644 index 0000000000..47b42a4298 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/prerequisites-1.md @@ -0,0 +1,80 @@ +--- +title: System requirements +weight: 2 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +If you are building and testing Windows on Arm software you have a variety of options to run Windows on Arm. You can use local laptops, cloud virtual machines, and CI/CD platforms like GitHub Actions for development tasks. + +You can also use a local Arm Linux server to create virtual machines for Windows on Arm software development tasks. This Learning Path explains how to install and use Windows on Arm virtual machines on an Arm Linux system. Two scripts are provided to create and run Windows on Arm virtual machines to make the process easy. + +Before creating a Windows on Arm virtual machine, ensure your Arm Linux system meets the hardware and software requirements. This section covers everything you need to prepare to create a Windows on Arm virtual machine using QEMU and KVM. + +## Hardware requirements + +You need an Arm Linux system with enough performance, memory, and storage to run a Windows on Arm virtual machine. + +The provided scripts have been tested on a [Thelio Astra](https://system76.com/desktops/thelio-astra-a1.1-n1/configure?srsltid=AfmBOoplXbwXifyxppxFe_oyahYMJHUT0bp2BnIBSH5ADjqgZxB7wW75) running Ubuntu 24.04. + +Thelio Astra is an Arm-based desktop computer designed by System76 for autonomous vehicle development and other general-purpose Arm software development. It uses the Ampere Altra processor, which is based on the Arm Neoverse N1 CPU, and ships with the Ubuntu operating system. + +Other Arm Linux systems and other Linux distributions are possible, but have not been tested. General hardware requirements are listed below. + +The minimum hardware requirements for the Arm Linux system are: + +- 8 cores with hardware virtualization support +- 8 GB RAM +- 50 GB free disk space + +The scripts automatically allocate resources as listed below, but the details can be customized for your system. + +- CPU: half of available cores (minimum 4 cores) +- Memory: half of available RAM (minimum 4 GB) +- Disk: 40 GB VM disk + +## KVM support + +Kernel-based Virtual Machine (KVM) support is required for hardware-accelerated virtualization and good VM performance. + +KVM is a virtualization infrastructure built into the Linux kernel that allows you to run virtual machines with near-native performance. It leverages Arm's hardware virtualization extensions to provide efficient CPU virtualization, while QEMU handles device emulation and management. Without KVM, virtual machines run much slower using software emulation. + +Verify your system supports KVM by running: + +```console +sudo apt install cpu-checker -y +sudo kvm-ok +``` + +If KVM is available, you will see the messages: + +```output +INFO: /dev/kvm exists +KVM acceleration can be used +``` + +This confirms that: +- Your CPU supports hardware virtualization +- The KVM kernel module is loaded +- The `/dev/kvm` device exists + +## Required software + +The scripts require several software packages. + +Install the packages using the Linux package manager. + +```console +sudo apt update +sudo apt install qemu-system-arm qemu-utils genisoimage wget curl jq uuid-runtime -y +``` + +If needed, the [Remmina](https://remmina.org/) remote desktop (RDP) client is automatically installed by the run script so you don't need to install it now, but you can install it using the command below. + +```console +sudo apt install remmina remmina-plugin-rdp -y +``` + +Proceed to the next section to learn about the scripts. + diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/understanding-scripts-2.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/understanding-scripts-2.md new file mode 100644 index 0000000000..b6103b6733 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/understanding-scripts-2.md @@ -0,0 +1,100 @@ +--- +title: Understanding the virtual machine scripts + +weight: 3 + +layout: "learningpathall" +--- + +A GitHub project provides two Bash scripts. Understanding their architecture and design will help you use them effectively and enable you to customize the options for your specific needs. + +Start by cloning the project repository from GitHub to your Arm Linux system. + +```bash +git clone https://github.com/jasonrandrews/win11arm.git +cd win11arm +``` + +The remainder of this section explains the structure of the scripts, and the next section provides details to run the scripts to create a Windows virtual machine. + +## Project overview + +The project includes two Bash scripts. + +- VM create script: `create-win11-vm.sh` handles all VM creation tasks +- VM run script: `run-win11-vm.sh` manages VM execution and connectivity + +All configuration is available using command-line options. + +The VM create script also allows you to perform the entire VM creation with a single command or run each individual step to learn and monitor the process. + +This modular approach allows you to understand each component while maintaining the simplicity of automated execution. + +## Virtual machine creation + +The creation script, `create-win11-vm.sh` is responsible for building a complete Windows 11 on Arm VM from scratch. It handles everything from directory setup to Windows installation, with each step clearly defined and independently executable. + +The script handles resource detection and allocation, provides unattended Windows installation, and has a flexible command line to change default values. + +Virtual machine creation includes the following steps: + +- Download the Windows 11 for Arm ISO from Microsoft +- Configure VirtIO drivers for optimal performance +- Set up automated installation with custom credentials +- Create optimized disk images + +### Virtual machine creation details + +The `create-win11-vm.sh` script implements a four-step process that builds a Windows VM incrementally: + +### Step 1: Create VM directory + +Step 1 initializes the VM directory structure and configuration. It creates the VM directory, copies initial configuration files, and sets up the basic environment. As a result, the VM directory, configuration files, and connection profiles are created. + +### Step 2: Download Windows + +Step 2 downloads the Windows 11 ISO and VirtIO drivers. It downloads the Windows 11 Arm ISO from Microsoft, fetches VirtIO drivers, and prepares unattended installation files. The files created during this step include `installer.iso`, `virtio-win.iso`, and the unattended installation directory. This step takes some time as the Windows ISO download is large, but if you already have the file the script will save time and not repeat the download. + +### Step 3: Prepare VM disk image + +Step 3 creates the VM disk image and finalizes the installation setup. It builds the unattended installation ISO, creates the main VM disk image, and configures all installation media. The files created during this step include `disk.qcow2` and `unattended.iso`. + +{{% notice Note %}} +The product key used in the scripts is a generic key provided by Microsoft, which allows installation. This key is for testing purposes only and does not activate Windows. If you plan to continue using Windows beyond installation, you should replace it with a genuine product key. +{{% /notice %}} + +### Step 4: First Windows boot + +Step 4 executes the Windows installation. It boots the VM with installation media, runs the automated Windows setup, and completes the initial configuration. The result is a fully installed and configured Windows on Arm VM. + +Each step builds on the previous one, and you can run them individually for debugging or customization purposes. + +## Virtual machine execution + +The `run-win11-vm.sh` script runs virtual machines by managing their execution and connectivity. + +The script begins by checking if the VM is already active by validating QEMU processes and PID files. If the VM is running, it skips to establishing an RDP connection; otherwise, it proceeds to start the VM. + +Next, the script launches the VM in headless mode, optimized for RDP access, by configuring QEMU with a headless display, setting up port forwarding, and starting the VM as a background daemon process. + +Once the VM is running, the script waits for the RDP service to become available, configures the Remmina client, and establishes a desktop connection. + +This process ensures seamless access to the VM with proper display scaling and input handling. + +## Automatic resource detection and allocation + +The scripts try to manage resources based on your system. + +For CPU allocation, `/proc/cpuinfo` is used to determine the total number of CPU cores and use half of the available cores for the VM. A minimum of 2 cores for creation and 4 cores for runtime are required. + +For memory allocation, `/proc/meminfo` is used to determine total system RAM and allocate half of the available memory for the VM. A minimum of 2GB is required and memory usage is based on system capacity, with an option to override using a command line parameter. + +For storage, the default VM disk size is 40GB in QCOW2 format. The available disk space is validated before creation. + +All settings are customizable using command line arguments. + +## Script Integration and Workflow + +The create and run scripts share the same configuration files. Separating creation from execution enables you to create a VM once and then use the run script repeatedly. + +The next section explains how to create and run a Windows on Arm virtual machine. \ No newline at end of file diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-creation-3.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-creation-3.md new file mode 100644 index 0000000000..e5572a56ed --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-creation-3.md @@ -0,0 +1,262 @@ +--- +title: "Create a Windows on Arm virtual machine" +weight: 4 +layout: "learningpathall" +--- + +## What is the fastest way to create a new Windows on Arm virtual machine? + +The virtual machine creation script creates a complete Windows 11 on Arm virtual machine with the `all` option. The default values are used for all configurable parameters. The location to store the VM files is also provided as an argument. + +To create a new VM, run the command: + +```console +./create-win11-vm.sh all $HOME/win11-vm +``` + +This single command executes all required virtual machine creation steps as explained in the previous section. + +The VM data is stored in the `$HOME/win11-vm` directory, and Windows will install automatically without any user intervention. + +Once the VM creation is complete, you'll see: + +```output +QEMU closed successfully. +Windows installation should be complete! +You can now use: ./run-win11-vm.sh $HOME/win11-vm +``` + +Your Windows on Arm VM is now ready to use. You can proceed to the next section to run the VM or continue on this page to review additional information about modifying default values, running the individual steps of VM creation, and fixing common errors. + +## Configuration options + +The creation script supports several options to customize your virtual machine setup. + +For example, you can change the Windows user, password, and disk size using the arguments shown below. + +```console +./create-win11-vm.sh all $HOME/win11-vm --username MyUser --password MyPass --disksize 60 +``` + +The table below lists the configuration options and default values. + +| Flag | Description | Default Value | Example | +|------|-------------|---------------|---------| +| `--username ` | Windows user name | `win11arm` | `--username Admin` | +| `--password ` | Windows user password | `win11arm` | `--password MySecurePass` | +| `--disksize ` | Disk size in GB | `40` | `--disksize 60` | +| `--rdp-port ` | RDP port for remote connections | `3389` | `--rdp-port 3390` | +| `--language ` | Windows language | `"English (United States)"` | `--language "English International"` | +| `--vm-mem ` | VM memory in GB | half of system RAM | `--vm-mem 8` | + + +### Disk space requirements + +The creation script checks available disk space before starting. + +An estimate of required disk space is shown in the table below. + +| Component | Size | Description | +|-----------|------|-------------| +| Windows 11 ISO | ~5GB | Downloaded from Microsoft | +| VirtIO drivers | ~500MB | Performance drivers | +| VM disk image | Variable | Default is 40 GB | +| Temporary files | ~1GB | Installation workspace | +| Total needed | ~7GB + disk size | Example: 47GB for default 40GB disk | + +### Configuration examples + +Create a VM with custom disk size and network port: + +```console +./create-win11-vm.sh all $HOME/win11-vm --disksize 60 --rdp-port 3390 --username Admin +``` + +Set up a VM with English International language: + +```console +./create-win11-vm.sh all $HOME/win11-vm --language "English International" +``` + +## Alternative four-step creation process + +The VM creation process consists of four distinct steps that can be run individually. Understanding each step helps with troubleshooting and customization. + +### Step 1: Create VM directory structure + +```console +./create-win11-vm.sh create $HOME/win11-vm +``` + +Command summary: +- Creates the VM directory at the specified path +- Sets up the initial directory structure for VM files +- Creates a `vm-config.txt` file with your configuration settings for reference +- Copies the Remmina connection template if available + +Files created: +- `vm-config.txt` - Configuration reference file +- `connect.remmina` - RDP connection template (if available) + +Each VM stores its configuration in `vm-config.txt`: + +```bash +# VM Configuration (for reference) +# Generated by create-win11-vm.sh v2.0.0 +VM_PATH=$HOME/win11-vm +USERNAME=win11arm +PASSWORD=win11arm +DISKSIZE=40 +RDP_PORT=3389 +LANGUAGE=English (United States) +VM_MEM=8 +CREATED=Thu Aug 28 10:30:45 UTC 2025 +``` + +This step is lightweight and completes quickly. It establishes the workspace where all VM files will be stored. + +### Step 2: Download Windows 11 and drivers + +```console +./create-win11-vm.sh download $HOME/win11-vm +``` + +Command summary: +- Downloads the Windows 11 Arm64 ISO directly from Microsoft's servers +- Patches the ISO to boot automatically without requiring a keypress +- Downloads VirtIO drivers for optimal VM performance +- Extracts and organizes drivers for the unattended installation +- Creates unattended installation configuration files +- Sets up the autounattend.xml with your specified username, password, and language + +Files created: +- `installer.iso` - Windows 11 Arm64 installation media +- `unattended/` directory - Contains drivers and installation automation files +- `unattended/autounattend.xml` - Windows unattended installation configuration +- `unattended/firstlogin.ps1` - Post-installation script + +If you already downloaded the Windows 11 installer ISO, you can copy it to your VM directory as `installer.iso` before running this step. The script will detect the existing file and ask if you want to use it or download a fresh copy: + +```output +installer.iso already exists. Delete it and download a fresh copy? [Y/n] +``` + +Choosing 'n' will skip the download and use your existing ISO, saving significant time and bandwidth. + +Download Process Details: +The script uses an automated process to download Windows 11 from Microsoft's official servers: + +1. Parse Microsoft's download page - Extracts product edition information +2. Get language SKU ID - Identifies the correct language variant +3. Obtain download link - Retrieves the direct download URL for Arm64 +4. Download and verify - Downloads the ISO and verifies its integrity + +### Step 3: Prepare VM disk + +```console +./create-win11-vm.sh prepare $HOME/win11-vm +``` + +Command summary: +- Creates the `unattended.iso` containing drivers and installation files +- Sets up the main VM hard drive as a QCOW2 disk image +- Allocates the specified disk space with optimized settings +- Prepares all components needed for the automated installation + +Files created: +- `unattended.iso` - ISO containing drivers and automation scripts +- `disk.qcow2` - Main VM hard drive (empty, ready for Windows installation) + +Disk Creation Details: +The script creates a QCOW2 disk image with these optimizations: +- Cluster size: 2 MB for better performance +- No copy-on-write: Disabled for improved I/O performance +- Metadata preallocation: Reduces fragmentation during VM operation + +Important Note: If `disk.qcow2` already exists, the script will warn you that proceeding will delete the existing VM's hard drive and start over with a clean installation. + +### Step 4: First boot and Windows installation + +```console +./create-win11-vm.sh firstboot $HOME/win11-vm +``` + +Command summary: +- Launches QEMU with the Windows installer +- Boots from the Windows 11 ISO with unattended installation +- Automatically installs Windows with your specified settings +- Installs VirtIO drivers for optimal performance +- Configures the user account and system settings +- Completes the entire Windows setup process without user intervention + +System Requirements Check: +Before starting, the script verifies: +- Desktop environment is available (DISPLAY or WAYLAND_DISPLAY) +- All required files exist (installer.iso, unattended.iso, disk.qcow2) +- Sufficient system resources are available + +Automatic Resource Allocation: +If you don't specify `--vm-mem`, the script automatically allocates: +- Memory: Half of your system's total RAM (minimum 2GB) +- CPU cores: Half of your system's total cores (minimum 2 cores) + +For example, on a system with 16GB RAM and 8 CPU cores: +- VM gets 8GB RAM and 4 CPU cores +- Host system retains 8GB RAM and 4 CPU cores for other tasks + +The script launches QEMU with these settings: +- Machine type: `virt` with KVM acceleration +- CPU: Host CPU passthrough for best performance +- Graphics: RamFB with GTK display and OpenGL acceleration +- Input: USB keyboard and tablet for proper mouse integration +- Network: User-mode networking with virtio-net for performance +- Storage: VirtIO block device with optimized caching +- Random number generator: Hardware entropy for security + +The installation process performs the following steps: +1. UEFI boot - VM starts with UEFI firmware +2. Windows installer loads - Boots from installer.iso +3. Unattended installation begins - Uses autounattend.xml configuration +4. Driver installation - VirtIO drivers installed automatically +5. User account creation - Your specified username and password +6. System configuration - Language, region, and basic settings +7. First login script - Runs firstlogin.ps1 for final setup + +The entire installation process typically takes 20-30 minutes depending on your system's performance. + +## Troubleshooting common problems + +### Insufficient disk space + +If you see an error about insufficient disk space: +```output +Error: Insufficient free disk space. 40 GB is needed, but you only have 25 GB. +``` + +Use the following options to correct the error: +- Free up disk space on your system +- Use a smaller disk size: `--disksize 30` +- Choose a different location with more space + +### Download failures + +If Windows ISO download fails: + +```output +Error: Failed to download Windows 11 installer.iso from Microsoft +``` + +Use the following options to correct the error: +- Check your internet connection +- Try again later (Microsoft can block frequent automated downloads) +- Manually download the ISO from Microsoft's website and save it as `installer.iso` + +### Memory allocation issues + +If the VM fails to start due to memory issues: + +Use the following options to correct the error: +- Reduce VM memory: `--vm-mem 4` +- Close other applications to free system memory + +You now have a good understanding of virtual machine creation. The next section will cover how to run and connect to your VM using the run script. \ No newline at end of file diff --git a/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-execution-4.md b/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-execution-4.md new file mode 100644 index 0000000000..e05656d100 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/win11-vm-automation/vm-execution-4.md @@ -0,0 +1,282 @@ +--- +title: "Run a Windows on Arm virtual machine" +weight: 5 +layout: "learningpathall" +--- + +## Basic VM launch command + +After your Windows 11 Arm VM is created, launching it is simple with the unified run script: + +```console +./run-win11-vm.sh $HOME/win11-vm +``` + +This single command handles the entire VM startup and connection process automatically. The script performs three key steps: checks if the VM is already running, starts it in headless mode if needed, and connects you via RDP using Remmina. + +When the virtual machine starts you will see it on your Linux desktop: + +![Windows on Arm VM](./images/win11arm.png) + +## What does the run script do? + +Understanding the run script flow helps you troubleshoot issues and customize the VM runtime behavior. + +### Step 1: Check if VM is already running + +The script first checks if your VM is already running to avoid conflicts. + +Here is a fragment of the code: + +```bash +# Check for existing VM process +if [ -f "$vm_path/qemu.pid" ]; then + local vm_pid=$(cat "$vm_path/qemu.pid" 2>/dev/null) + if process_exists "$vm_pid"; then + status "VM is already running (PID: $vm_pid)" + fi +fi +``` + +The run script looks for the `qemu.pid` file in your VM directory, verifies the process ID is still active, cleans up stale PID files from previous sessions, and skips VM startup if already running. + +If this happens you will see output similar to: + +```output +VM is already running (PID: 12345) +Waiting for RDP service on port 3389... +``` + +### Step 2: Start VM in headless mode + +If the VM isn't running, the script starts it in headless mode (no GUI window) using QEMU. + +The arguments to QEMU are shown below: + +```bash +qemu-system-aarch64 \ + -M virt,accel=kvm \ + -cpu host \ + -m ${vm_mem}G \ + -smp $num_cores \ + -name "Windows on Arm" \ + -pidfile "$vm_path/qemu.pid" \ + -display none \ + -netdev user,id=nic,hostfwd=tcp:127.0.0.1:${rdp_port}-:3389 \ + -device virtio-net-pci,netdev=nic \ + -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \ + -drive file="$vm_path/disk.qcow2",if=virtio,discard=unmap,aio=threads,cache=none \ + -daemonize +``` + +The important arguments to QEMU are: +- `-M virt,accel=kvm` - Uses ARM virtualization with KVM acceleration +- `-cpu host` - Passes through your host CPU features for best performance +- `-display none` - Runs headless (no QEMU window) +- `-daemonize` - Runs QEMU as a background daemon +- `-netdev user,hostfwd=...` - Sets up port forwarding for RDP access +- `-pidfile` - Creates a PID file for process management + +The script automatically detects and allocates CPU and memory resources. + +The code is shown below: + +```bash +# Memory: Half of available RAM (minimum 2GB) +local total_ram_gb=$(awk '/MemTotal/ {print int($2/1048576)}' /proc/meminfo) +local vm_mem=$((total_ram_gb / 2)) +[ "$vm_mem" -lt 2 ] && vm_mem=2 + +# CPU: Half of available cores (minimum 4) +local total_cores=$(grep -c ^processor /proc/cpuinfo) +local num_cores=$((total_cores / 2)) +[ "$num_cores" -lt 4 ] && num_cores=4 +``` + +When the run script executes, you will see the CPU and RAM allocated: + +```output +Starting Windows VM in headless mode... +Using 8GB RAM and 4 CPU cores +VM started successfully +``` + +### Step 3: Connect via RDP + +Once the VM is running, the script waits for the RDP service and connects automatically. + +Here is the function which waits for the port to be ready: + +```bash +# Wait for RDP service to be available +wait_for_rdp() { + local port="$1" + local max_attempts=60 + + while [ $attempt -le $max_attempts ]; do + if timeout 3 bash -c "echo >/dev/tcp/localhost/$port" 2>/dev/null; then + return 0 + fi + sleep 2 + attempt=$((attempt + 1)) + done +} +``` + +Once the RDP service is ready, Remmina is started and connects. + +The related output is shown below: + +```output +Waiting for RDP service on port 3389... +RDP service is available! +Connecting to VM via RDP (localhost:3389)... +Username: win11arm +``` + +## Run script options and examples + +The run script supports several options for different use cases: + +### Custom RDP port + +```console +./run-win11-vm.sh /path/to/vm --rdp-port 3390 +``` +Uses a custom RDP port, useful when running multiple VMs or avoiding port conflicts. + +### Help information + +```console +./run-win11-vm.sh --help +``` +Displays usage information and all available options. + +## Remmina integration + +The script uses Remmina as the RDP client and creates a Remmina profile with the connection settings. + +The file name is `connect.remmina` and you can review and edit as needed. + +```ini +[remmina] +name=VM Connect +protocol=RDP +scale=2 +quality=9 +disable_fastpath=0 +glyph-cache=0 +multitransport=0 +relax-order-checks=1 +ignore-tls-errors=1 +cert_ignore=1 +window_width=1024 +window_height=768 +window_maximize=0 +disableautoreconnect=1 +viewmode=1 +network=lan #change viewmode=1 to viewmode=3 for fullscreen +sound=local #to get microphone input working, change to sound=remote, and USB passthrough your m +icrophone to the VM. +colordepth=63 +``` + + +## VM shutdown + +The preferred method is to shut down Windows normally from within the virtual machine. + +1. Click the Start button in Windows +2. Select Power → Shut down +3. Wait for Windows to complete shutdown +4. VM automatically stops when Windows finishes shutting down +5. Remmina exits automatically when the connection closes + +You should avoid killing QEMU directly as it may corrupt the VM disk as well as avoid exiting Remmina as it may leave the VM running in the background. + +## Runtime monitoring and management + +### Checking VM status + +To check if your VM is running without connecting: + +```console +# Check for VM process +ps aux | grep "Windows on Arm" + +# Check PID file +cat $HOME/win11-vm/qemu.pid + +# Test RDP connectivity +timeout 3 bash -c "echo >/dev/tcp/localhost/3389" +``` + +If the RDP connectivity fails the output is: + +```output +bash: connect: Connection refused +bash: line 1: /dev/tcp/localhost/3389: Connection refused +``` + +### Resource usage monitoring + +Monitor VM resource usage while running: + +```console +# CPU and memory usage +top -p $(cat $HOME/win11-vm/qemu.pid) + +# Detailed process information +ps -p $(cat $HOME/win11-vm/qemu.pid) -o pid,ppid,cmd,%cpu,%mem,etime +``` + +### Multiple VM management + +Running multiple VMs requires different RDP ports: + +```console +# First VM (default port 3389) +./run-win11-vm.sh $HOME/vm1 + +# Second VM (custom port 3390) +./run-win11-vm.sh $HOME/vm2 --rdp-port 3390 + +# Third VM (custom port 3391) +./run-win11-vm.sh $HOME/vm3 --rdp-port 3391 +``` + +Each VM needs its own directory and unique RDP port to avoid conflicts. + +## Troubleshooting runtime issues + +### RDP connection failures + +If RDP connection fails: + +```output +Error: RDP service did not become available after 120 seconds +``` + +Check VM is actually running: + +```console +ps aux | grep qemu-system-aarch64 +``` + +Verify RDP port: +```console +netstat -tlnp | grep 3389 +``` + +### Known Remmina crash issue + +When disconnecting from RDP, Remmina may crash with: + +```output +./run-win11-vm.sh: line 143: 60433 Aborted (core dumped) remmina -c "$remmina_file" $remmina_flags 2> /dev/null +RDP session ended +``` + +This is a known Remmina issue and does not affect VM functionality. + +You have learned how to create Windows on Arm virtual machines on an Arm Linux system with QEMU and KVM. You can use these virtual machines for software development and testing. You can speedup your development tasks by using an Arm Linux desktop or server with high processor count and plenty of RAM. \ No newline at end of file