@@ -411,6 +411,68 @@ function efi_vars() {
411411 fi
412412}
413413
414+ # Reset CPU flags tracking (call when initialising new CPU string)
415+ function reset_cpu_flags() {
416+ CPU_FLAG_MAP=()
417+ }
418+
419+ # Add a CPU flag with deduplication and conflict detection
420+ # Usage: add_cpu_flag "+vmx" or add_cpu_flag ",+vmx"
421+ function add_cpu_flag() {
422+ local flag=" ${1# ,} " # Strip leading comma if present
423+
424+ # Skip empty flags
425+ [[ -z " ${flag} " ]] && return 0
426+
427+ # Validate flag format: must be [+-]?name or name=value
428+ if [[ ! " ${flag} " =~ ^[+-]? [a-zA-Z][a-zA-Z0-9._-]* (=.+)? $ ]]; then
429+ echo " WARNING: Invalid CPU flag format: '${flag} ' - skipping"
430+ return 1
431+ fi
432+
433+ # Extract base flag name (without +/- prefix and =value suffix)
434+ local prefix=" "
435+ local base=" ${flag} "
436+ if [[ " ${flag} " == [+-]* ]]; then
437+ prefix=" ${flag: 0: 1} "
438+ base=" ${flag: 1} "
439+ fi
440+ base=" ${base%% =* } "
441+
442+ # Check for exact duplicate
443+ if [[ -n " ${CPU_FLAG_MAP[${flag}]:- } " ]]; then
444+ return 0 # Silently skip duplicates
445+ fi
446+
447+ # Check for conflicts (opposite prefix)
448+ local opposite=" "
449+ if [[ " ${prefix} " == " +" ]]; then
450+ opposite=" -${base} "
451+ elif [[ " ${prefix} " == " -" ]]; then
452+ opposite=" +${base} "
453+ fi
454+
455+ if [[ -n " ${opposite} " ]] && [[ -n " ${CPU_FLAG_MAP[${opposite}]:- } " ]]; then
456+ echo " WARNING: Conflicting CPU flag '${flag} ' ignored (${opposite} already set)"
457+ return 1
458+ fi
459+
460+ # Check for value conflicts (e.g., flag=on vs flag=off)
461+ if [[ " ${flag} " == * = * ]]; then
462+ for existing in " ${! CPU_FLAG_MAP[@]} " ; do
463+ if [[ " ${existing%% =* } " == " ${base} " ]] && [[ " ${existing} " == * = * ]]; then
464+ echo " WARNING: Conflicting CPU flag '${flag} ' ignored (${existing} already set)"
465+ return 1
466+ fi
467+ done
468+ fi
469+
470+ # Add to tracking map and append to CPU string
471+ CPU_FLAG_MAP[" ${flag} " ]=1
472+ CPU+=" ,${flag} "
473+ return 0
474+ }
475+
414476function configure_cpu() {
415477 HOST_CPU_CORES=$( get_nproc)
416478 HOST_CPU_MODEL=$( get_cpu_info ' ^Model name:' )
@@ -499,6 +561,7 @@ function configure_cpu() {
499561 fi
500562
501563 CPU=" -cpu ${CPU_MODEL} "
564+ reset_cpu_flags
502565
503566 # Make any OS specific adjustments
504567 if [ " ${guest_os} " == " freedos" ] || [ " ${guest_os} " == " windows" ] || [ " ${guest_os} " == " windows-server" ]; then
@@ -522,6 +585,7 @@ function configure_cpu() {
522585 batocera|freedos|haiku|solaris) MACHINE_TYPE=" pc" ;;
523586 kolibrios|reactos)
524587 CPU=" -cpu qemu32"
588+ reset_cpu_flags
525589 MACHINE_TYPE=" pc" ;;
526590 macos)
527591 # If the host has an Intel CPU, passes the host CPU model features, model, stepping, exactly to the guest.
@@ -530,9 +594,11 @@ function configure_cpu() {
530594 if [ " ${HOST_CPU_VENDOR} " == " GenuineIntel" ] && [ -z " ${HYPERVISOR} " ]; then
531595 CPU_MODEL=" host"
532596 CPU=" -cpu ${CPU_MODEL} ,-pdpe1gb,+hypervisor"
597+ reset_cpu_flags
533598 else
534599 CPU_MODEL=" Haswell-v2"
535600 CPU=" -cpu ${CPU_MODEL} ,vendor=GenuineIntel,-pdpe1gb,+avx,+sse,+sse2,+ssse3,vmware-cpuid-freq=on"
601+ reset_cpu_flags
536602 fi
537603 # A CPU with fma is required for Metal support
538604 # A CPU with invtsc is required for macOS to boot
@@ -544,7 +610,8 @@ function configure_cpu() {
544610 # A CPU with AVX2 support is required for >= macOS Ventura
545611 if check_cpu_flag sse4_2 && check_cpu_flag avx2; then
546612 if [ " ${HOST_CPU_VENDOR} " != " GenuineIntel" ] && [ -z " ${HYPERVISOR} " ]; then
547- CPU+=" ,+avx2,+sse4.2"
613+ add_cpu_flag " +avx2"
614+ add_cpu_flag " +sse4.2"
548615 fi
549616 else
550617 echo " ERROR! macOS ${macos_release} requires a CPU with SSE 4.2 and AVX2 support."
@@ -555,7 +622,7 @@ function configure_cpu() {
555622 # A CPU with SSE4.2 support is required for >= macOS Catalina
556623 if check_cpu_flag sse4_2; then
557624 if [ " ${HOST_CPU_VENDOR} " != " GenuineIntel" ] && [ -z " ${HYPERVISOR} " ]; then
558- CPU+= " , +sse4.2"
625+ add_cpu_flag " +sse4.2"
559626 fi
560627 else
561628 echo " ERROR! macOS ${macos_release} requires a CPU with SSE 4.2 support."
@@ -565,7 +632,7 @@ function configure_cpu() {
565632 # A CPU with SSE4.1 support is required for >= macOS Sierra
566633 if check_cpu_flag sse4_1; then
567634 if [ " ${HOST_CPU_VENDOR} " != " GenuineIntel" ] && [ -z " ${HYPERVISOR} " ]; then
568- CPU+= " , +sse4.1"
635+ add_cpu_flag " +sse4.1"
569636 fi
570637 else
571638 echo " ERROR! macOS ${macos_release} requires a CPU with SSE 4.1 support."
@@ -579,12 +646,15 @@ function configure_cpu() {
579646 mca mce mmx movbe mpx msr mtrr nx pae pat pcid pge pse popcnt pse36 \
580647 rdrand rdtscp sep smep syscall tsc tsc_adjust vaes vbmi2 vmx vpclmulqdq \
581648 x2apic xgetbv1 xsave xsaveopt; do
582- CPU+=$( configure_cpu_flag " ${FLAG} " )
649+ local cpu_flag
650+ cpu_flag=$( configure_cpu_flag " ${FLAG} " )
651+ [[ -n " ${cpu_flag} " ]] && add_cpu_flag " ${cpu_flag# ,} "
583652 done
584653 # AMD CPUs with constant_tsc need explicit TSC flags for macOS stability
585654 # constant_tsc is AMD's equivalent of Intel's invtsc
586655 if [ " ${HOST_CPU_VENDOR} " == " AuthenticAMD" ] && check_cpu_flag invtsc; then
587- CPU+=" ,+tsc,+tsc-deadline"
656+ add_cpu_flag " +tsc"
657+ add_cpu_flag " +tsc-deadline"
588658 fi
589659 fi
590660 fi
@@ -602,12 +672,25 @@ function configure_cpu() {
602672 windows|windows-server)
603673 # Base CPU flags that work with all accelerators (KVM, HVF, TCG)
604674 CPU=" -cpu ${CPU_MODEL} ,+hypervisor,+invtsc,l3-cache=on"
675+ reset_cpu_flags
605676 # KVM-specific flags: migratable and Hyper-V enlightenments
606677 if [ " ${QEMU_ACCEL} " == " kvm" ]; then
607678 if [ " ${QEMU_VER_SHORT} " -gt 60 ]; then
608- CPU+=" ,migratable=no,hv_passthrough"
679+ add_cpu_flag " migratable=no"
680+ add_cpu_flag " hv_passthrough"
609681 else
610- CPU+=" ,migratable=no,hv_frequencies${CPU_KVM_UNHALT} ,hv_reenlightenment,hv_relaxed,hv_spinlocks=8191,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vendor_id=1234567890ab,hv_vpindex"
682+ add_cpu_flag " migratable=no"
683+ add_cpu_flag " hv_frequencies"
684+ [[ -n " ${CPU_KVM_UNHALT} " ]] && add_cpu_flag " ${CPU_KVM_UNHALT# ,} "
685+ add_cpu_flag " hv_reenlightenment"
686+ add_cpu_flag " hv_relaxed"
687+ add_cpu_flag " hv_spinlocks=8191"
688+ add_cpu_flag " hv_stimer"
689+ add_cpu_flag " hv_synic"
690+ add_cpu_flag " hv_time"
691+ add_cpu_flag " hv_vapic"
692+ add_cpu_flag " hv_vendor_id=1234567890ab"
693+ add_cpu_flag " hv_vpindex"
611694 fi
612695 fi
613696 # Disable S3 support in the VM to ensure Windows can boot with SecureBoot enabled
@@ -624,7 +707,7 @@ function configure_cpu() {
624707 esac
625708
626709 if [ " ${HOST_CPU_VENDOR} " == " AuthenticAMD" ] && [ " ${guest_os} " != " macos" ]; then
627- CPU+= " , topoext"
710+ add_cpu_flag " topoext"
628711 fi
629712
630713 if [ -z " ${cpu_cores} " ]; then
@@ -2308,6 +2391,9 @@ VMDIR=""
23082391VMNAME=" "
23092392VMPATH=" "
23102393
2394+ # CPU flag tracking map for deduplication and conflict detection
2395+ declare -A CPU_FLAG_MAP
2396+
23112397# shellcheck disable=SC2155
23122398readonly LAUNCHER=$( basename " ${0} " )
23132399readonly DISK_MIN_SIZE=$(( 197632 * 8 ))
0 commit comments