From b0e643d1c320b32ff83c11a1f0b6264550f06c04 Mon Sep 17 00:00:00 2001 From: Martin Wimpress Date: Sat, 24 Jan 2026 15:15:37 +0000 Subject: [PATCH] feat(quickemu): warn on unstable TSC for macOS Ventura+ on AMD - Add check_macos_tsc_stability() to detect unstable TSC on Linux hosts with AuthenticAMD CPUs when launching macOS Ventura+ guests - Log a clear warning to the VM log and prompt interactively to continue or abort to avoid guest freezes - Abort by default in non-interactive mode to prevent unattended VM hangs - Add --ignore-tsc-warning to bypass the check and invoke the check during vm_boot so it runs early in startup Closes #1273 Signed-off-by: Martin Wimpress --- quickemu | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/quickemu b/quickemu index 358be01..aaf1599 100755 --- a/quickemu +++ b/quickemu @@ -38,6 +38,94 @@ function ignore_msrs_alert() { fi } +# Check for TSC instability that can cause macOS Ventura+ to freeze on AMD Ryzen mobile CPUs. +# Returns 0 if check passes or user acknowledges warning, exits with 1 if user aborts. +# Reference: https://github.com/quickemu-project/quickemu/issues/1273 +function check_macos_tsc_stability() { + # Gate 1: Only on Linux hosts + if [ "${OS_KERNEL}" != "Linux" ]; then + return 0 + fi + + # Gate 2: Only for AMD CPUs + if [ "${HOST_CPU_VENDOR}" != "AuthenticAMD" ]; then + return 0 + fi + + # Gate 3: Only for macOS guests + if [ "${guest_os}" != "macos" ]; then + return 0 + fi + + # Gate 4: Only for macOS Ventura (13) and newer + case ${macos_release} in + ventura|sonoma|sequoia|tahoe) ;; + *) return 0 ;; + esac + + # Gate 5: Skip if user has already set tsc=reliable in kernel cmdline + local cmdline="" + if [ -r /proc/cmdline ]; then + cmdline=$(cat /proc/cmdline) + if [[ "${cmdline}" == *"tsc=reliable"* ]]; then + return 0 + fi + fi + + # Gate 6: Check if TSC is the current clocksource (indicates stable TSC) + local clocksource_path="/sys/devices/system/clocksource/clocksource0/current_clocksource" + local current_clocksource="" + if [ -r "${clocksource_path}" ]; then + current_clocksource=$(cat "${clocksource_path}") + if [ "${current_clocksource}" == "tsc" ]; then + return 0 + fi + else + # Cannot determine clocksource - assume OK and let user discover issues + return 0 + fi + + # All gates failed - this system is at risk + # Check if warning should be skipped + if [ "${IGNORE_TSC_WARNING}" == "1" ]; then + echo " - TSC: WARNING! Unstable TSC detected (clocksource: ${current_clocksource})" + echo " Proceeding anyway due to --ignore-tsc-warning flag." + return 0 + fi + + # Display warning and prompt user + echo " - TSC: WARNING! Unstable TSC detected (clocksource: ${current_clocksource})" + echo " macOS ${macos_release^} may freeze on AMD Ryzen mobile CPUs." + echo + echo " Fix: Add 'tsc=reliable' to kernel boot parameters and reboot." + echo " Or: Use macOS Big Sur (11) or Monterey (12) instead." + echo " See: https://github.com/quickemu-project/quickemu/wiki/03-Create-macOS-virtual-machines#tsc-instability-on-amd-ryzen-mobile-cpus" + echo + + # Log the warning + echo "TSC_WARNING: clocksource=${current_clocksource} macos_release=${macos_release} cpu_vendor=${HOST_CPU_VENDOR}" >> "${VMDIR}/${VMNAME}.log" + + # Interactive prompt - check if stdin is a terminal + if [ -t 0 ]; then + echo -n "Do you want to continue anyway? [y/N] " + read -r response + case "${response}" in + [yY]|[yY][eE][sS]) + echo " - TSC: Proceeding despite unstable TSC warning." + return 0 + ;; + *) + echo " - TSC: Aborting. Please apply one of the solutions above." + exit 1 + ;; + esac + else + # Non-interactive mode - abort by default for safety + echo "ERROR! Non-interactive mode detected. Use --ignore-tsc-warning to bypass this check." + exit 1 + fi +} + function delete_shortcut() { local SHORTCUT_DIR="${HOME}/.local/share/applications" if [ -e "${SHORTCUT_DIR}/${VMNAME}.desktop" ]; then @@ -1364,6 +1452,7 @@ function vm_boot() { configure_cpu configure_ram + check_macos_tsc_stability configure_bios configure_os_quirks configure_storage @@ -1848,6 +1937,7 @@ function usage() { echo " --display : Select display backend. 'sdl' (default), 'cocoa', 'gtk', 'none', 'spice' or 'spice-app'" echo " --fullscreen : Starts VM in full screen mode (Ctl+Alt+f to exit)" echo " --ignore-msrs-always : Configure KVM to always ignore unhandled machine-specific registers" + echo " --ignore-tsc-warning : Skip TSC stability warning for macOS VMs on AMD" echo " --kill : Kill the VM process if it is running" echo " --offline : Override all network settings and start the VM offline" echo " --shortcut : Create a desktop shortcut" @@ -2110,6 +2200,7 @@ sound_duplex="${sound_duplex:-hda-micro}" ACCESS="" ACTIONS=() BRAILLE="" +IGNORE_TSC_WARNING="" CPU_PINNING="" FULLSCREEN="" MONITOR_CMD="" @@ -2202,6 +2293,9 @@ else -ignore-msrs-always|--ignore-msrs-always) ignore_msrs_always exit;; + -ignore-tsc-warning|--ignore-tsc-warning) + IGNORE_TSC_WARNING="1" + shift;; -kill|--kill) ACTIONS+=(kill_vm) shift;;