Fixing Ubuntu Linux VM Freezing on UTM/MacOS with an Intel Mac: Complete Two-Step Solution

By David A. Wheeler (2025-10-15)

IMPORTANT: This applies ONLY to Intel-based Macs running x86/x86_64 Linux VMs on Apple's Hypervisor Framework (HVF) with UTM and similar, not Apple Silicon (ARM) Macs.

While I use a Mac, I spend a lot of my time in Linux virtual machines. So when a Linux virtual machine isn't reliable, it matters to me. This particular bug took a while to track down and fix. I hope writing this down will help others. The Linux kernel is awesome, but its proper performance requires reliable timers. When timers don't work well, say because the virtual machine monitor (VMM) configuration doesn't provide good timers, the Linux kernel's attempts to compensate are sometimes not enough. This is a tale of one such problem and how to fix it.

The Visible Problem: Severe UI Freezing

If you're running Ubuntu (or another Linux distribution) in a UTM virtual machine on an Intel Mac, you may experience severe UI freezing after it works for a short while. The symptoms are:

How to Detect This Problem

From within the guest Ubuntu system, you can quickly diagnose this issue:

cat /sys/devices/system/clocksource/clocksource0/current_clocksource

If the output shows only acpi_pm (ACPI Power Management timer), you have this problem. The system should be using tsc (Time Stamp Counter) for optimal performance.

You can also check available clocksources:

cat /sys/devices/system/clocksource/clocksource0/available_clocksource

If tsc is not listed in the available clocksources, the CPU type misconfiguration is preventing proper timer initialization.

Why This Happens: A Two-Part Problem (x86-Specific)

The root cause is actually two separate but related issues with x86 virtualization on Intel Macs:

Part 1: CPU Type Misconfiguration Prevents TSC at Boot

UTM's default CPU type setting prevents proper Time Stamp Counter (TSC) passthrough. TSC is an x86/x86_64 CPU feature critical for high-precision timing:

  1. QEMU/HVF fails to emulate the PIT timer correctly during boot with certain CPU type settings
  2. TSC calibration fails because the guest kernel cannot properly calibrate against the (improperly emulated) Programmable Interval Timer
  3. Kernel marks TSC as "unstable" and falls back to the much slower acpi_pm clocksource (approximately 1000x slower than TSC)

Part 2: TSC Watchdog Disables TSC at Runtime

Even if you fix the CPU type, there's a second problem:

  1. QEMU/HVF TSC emulation has timing drift - TSC drifts relative to the ACPI PM timer by approximately 0.1% (~480 microseconds over 497 milliseconds)
  2. The kernel's clocksource watchdog detects this drift after about half an hour of runtime
  3. Watchdog marks TSC unstable and disables it, falling back to acpi_pm
  4. UI freezing returns due to inadequate timer resolution

The TSC is critical for system performance. Modern x86-64 systems expect nanosecond-level timer precision, but acpi_pm only provides microsecond-level precision. This mismatch causes the kernel scheduler to make poor decisions, leading to the UI freezing behavior.

The drift occurs because QEMU/HVF lacks proper paravirtualization support (kvm-clock) and VM scheduling on macOS causes TSC discontinuities. However, the drift rate is small and acceptable for VM workloads - the watchdog is being overly sensitive.

The Complete Solution: Two Steps Required

Both steps are required for a permanent fix:

Step 1: Change UTM CPU Type Setting

This enables TSC at boot time:

  1. Shut down your Ubuntu VM completely
  2. Open UTM and select your Ubuntu virtual machine
  3. Click the "Edit" button (or right-click and select "Edit")
  4. Navigate to System settings
  5. Under CPU, find the CPU type dropdown
  6. Change from "Default" to "Enables all features supported by the accelerator in the current host (max)"
  7. Under the "QEMU" tab, select "Use Hypervisor". This uses Apple's Hypervisor Framework (HVF), which is the recommended and highest-performance virtualization option for Intel Macs.

  8. Click "Save"

Step 2: Add Kernel Boot Parameter

This prevents the watchdog from disabling TSC at runtime:

  1. Start your Ubuntu VM (with the new CPU type setting)
  2. Open a terminal
  3. Edit the GRUB configuration:
    sudo nano /etc/default/grub
    
  4. Find the line that starts with GRUB_CMDLINE_LINUX_DEFAULT
  5. Add tsc=reliable inside the quotes. For example, change:
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    
    to:
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash tsc=reliable"
    
  6. Save the file (Ctrl+O, Enter, Ctrl+X in nano)
  7. Update GRUB:
    sudo update-grub
    
  8. Reboot your VM:
    sudo reboot
    

Verify Both Fixes Work

After rebooting with both changes:

cat /sys/devices/system/clocksource/clocksource0/current_clocksource

You should see tsc as the current clocksource, and it should remain tsc even after hours of uptime. The UI freezing should be completely eliminated.

To monitor that TSC remains stable, you can check periodically:

watch -n 60 'cat /sys/devices/system/clocksource/clocksource0/current_clocksource'

It should continuously show tsc and never revert to acpi_pm.

Additional Optimization (Optional)

If you originally allocated 8 vCPUs, consider reducing to 4 vCPUs.

Understanding the tsc=reliable Parameter

The tsc=reliable kernel parameter tells Linux to trust the TSC even if the clocksource watchdog detects drift. This is safe because:

The watchdog's strict threshold is designed for bare metal systems where TSC should be perfectly stable. In VM environments, small drift is expected and acceptable.

Why Both Steps Are Necessary

Step 1 (CPU Type "max") provides:

Step 2 (tsc=reliable) provides:

Without Step 1, TSC never becomes available. Without Step 2, TSC gets disabled after about half an hour. Both steps together provide a complete, permanent fix.

Why This Problem Exists (Intel Mac / x86 Virtualization with HVF)

While HVF (Apple's Hypervisor Framework) is the recommended and fastest virtualization option for Intel Macs, QEMU/HVF has some limitations when virtualizing x86 Linux guests compared to KVM on Linux:

The kernel message "Booting paravirtualized kernel on bare hardware" reveals that the kernel expects paravirtualization support that QEMU/HVF doesn't provide. This is the fundamental limitation that requires the tsc=reliable workaround.

Why ARM Macs Don't Have This Problem

Apple Silicon Macs (M1/M2/M3) running ARM Linux VMs use:

The tsc=reliable kernel parameter doesn't even exist on ARM Linux - it's specific to x86/x86_64 architecture.

Conclusion

This two-step fix resolves a severe usability problem with x86/x86_64 Linux VMs on UTM running on Intel-based Macs. If you're experiencing UI freezing on an Intel Mac:

  1. Change UTM CPU type to "max" (enables TSC at boot)
  2. Add kernel parameter tsc=reliable (keeps TSC enabled permanently)

The diagnosis is straightforward (check the clocksource), the cause is well-understood (TSC calibration failure and watchdog drift detection), and the solution requires two simple configuration changes. The result is stable, high-performance VM operation without UI freezing.

Note: If you're using an Apple Silicon Mac (M1/M2/M3) with ARM Linux VMs, this fix does not apply - ARM uses completely different timer hardware and virtualization technology that doesn't have this TSC-related issue.

Note 2: I found the problem and solution working with Claude Code (thanks Anthropic!). However, my first foray was a complete failure. I learned that when debugging deep problems like this, AI/ML is often intellectually lazy; it often wants to repeatedly find something that might work and propose it. I went down various useless rabbit holes. I restarted and demanded that it list all possible causes of the problem, then repeatedly analyze to disprove all other options and prove the one remaining option. Demanding airtight proof didn't immediately get the answer, but forcing it to prove its diagnosis before doing stuff was a key in getting to success.