--- target/arm/hvf/hvf.c.orig
+++ target/arm/hvf/hvf.c
@@ -478,6 +478,20 @@
  */
 #if !defined(MAC_OS_VERSION_26_0)
 #define HV_SYS_REG_MDCR_EL2 0xe089
+#endif
+
+/*
+ * Nested virtualization and the in-kernel vGIC use Hypervisor.framework
+ * APIs and system register constants that first appeared in the macOS 15.0
+ * SDK.  Older SDKs do not declare them at all, so the -Wunguarded-availability
+ * suppression below is not enough: the code has to be compiled out entirely.
+ * Nothing is lost by doing so, as the __builtin_available() checks guarding
+ * these paths can only ever succeed on macOS 15.0 and later anyway.
+ */
+#if defined(MAC_OS_VERSION_15_0)
+#define HVF_HAVE_MACOS_15_SDK 1
+#else
+#define HVF_HAVE_MACOS_15_SDK 0
 #endif
 
 /*
@@ -497,14 +511,19 @@
   QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
 #define DEF_SYSREG_15_02(...)
 
-#define DEF_SYSREG_EL2(HVF_ID, ...) \
+#define DEF_SYSREG_VGIC(HVF_ID, ...) \
   QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
 
-#define DEF_SYSREG_VGIC(HVF_ID, ...) \
+#if HVF_HAVE_MACOS_15_SDK
+#define DEF_SYSREG_EL2(HVF_ID, ...) \
   QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
 
 #define DEF_SYSREG_VGIC_EL2(HVF_ID, ...) \
   QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
+#else
+#define DEF_SYSREG_EL2(...)
+#define DEF_SYSREG_VGIC_EL2(...)
+#endif
 
 #include "sysreg.c.inc"
 
@@ -516,9 +535,14 @@
 
 #define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2)  {HVF_ID},
 #define DEF_SYSREG_15_02(...)
-#define DEF_SYSREG_EL2(HVF_ID, op0, op1, crn, crm, op2)  {HVF_ID, .el2 = true},
 #define DEF_SYSREG_VGIC(HVF_ID, op0, op1, crn, crm, op2)  {HVF_ID, .vgic = true},
+#if HVF_HAVE_MACOS_15_SDK
+#define DEF_SYSREG_EL2(HVF_ID, op0, op1, crn, crm, op2)  {HVF_ID, .el2 = true},
 #define DEF_SYSREG_VGIC_EL2(HVF_ID, op0, op1, crn, crm, op2)  {HVF_ID, true, true},
+#else
+#define DEF_SYSREG_EL2(...)
+#define DEF_SYSREG_VGIC_EL2(...)
+#endif
 
 struct hvf_sreg {
     hv_sys_reg_t sreg;
@@ -1309,6 +1333,7 @@
 
 static bool hvf_arm_el2_supported(void)
 {
+#if HVF_HAVE_MACOS_15_SDK
     bool is_nested_virt_supported;
     if (__builtin_available(macOS 15.0, *)) {
         hv_return_t ret = hv_vm_config_get_el2_supported(&is_nested_virt_supported);
@@ -1317,6 +1342,9 @@
         return false;
     }
     return is_nested_virt_supported;
+#else
+    return false;
+#endif
 }
 
 
@@ -1331,6 +1359,7 @@
     }
     chosen_ipa_bit_size = pa_range;
 
+#if HVF_HAVE_MACOS_15_SDK
     if (__builtin_available(macOS 15.0, *)) {
         if (hvf_nested_virt_enabled()) {
             if (!hvf_arm_el2_supported()) {
@@ -1343,10 +1372,18 @@
                 goto cleanup;
             }
         }
+    }
+#else
+    if (hvf_nested_virt_enabled() && !hvf_arm_el2_supported()) {
+        error_report("Nested virtualization not supported on this system.");
+        ret = HV_UNSUPPORTED;
+        goto cleanup;
     }
+#endif
 
     ret = hv_vm_create(config);
     if (hvf_irqchip_in_kernel()) {
+#if HVF_HAVE_MACOS_15_SDK
         if (__builtin_available(macOS 15.0, *)) {
             /*
              * Instantiate GIC.
@@ -1367,6 +1404,11 @@
             ret = HV_UNSUPPORTED;
             goto cleanup;
         }
+#else
+        error_report("HVF: Unsupported OS for platform vGIC.");
+        ret = HV_UNSUPPORTED;
+        goto cleanup;
+#endif
     }
 
 cleanup:
@@ -1749,9 +1791,11 @@
         /* Dummy register */
         return 0;
     case SYSREG_CNTHCTL_EL2:
+#if HVF_HAVE_MACOS_15_SDK
         if (__builtin_available(macOS 15.0, *)) {
             assert_hvf_ok(hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTHCTL_EL2, val));
         }
+#endif
         return 0;
     case SYSREG_MDCCINT_EL1:
         assert_hvf_ok(hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_MDCCINT_EL1, val));
@@ -2047,9 +2091,11 @@
         /* Dummy register */
         return 0;
     case SYSREG_CNTHCTL_EL2:
+#if HVF_HAVE_MACOS_15_SDK
         if (__builtin_available(macOS 15.0, *)) {
             assert_hvf_ok(hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTHCTL_EL2, val));
         }
+#endif
         return 0;
     case SYSREG_MDCCINT_EL1:
         assert_hvf_ok(hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_MDCCINT_EL1, val));
--- hw/intc/arm_gicv3_hvf.c.orig
+++ hw/intc/arm_gicv3_hvf.c
@@ -30,6 +30,15 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunguarded-availability"
 
+/*
+ * The whole hv_gic_* API first appeared in the macOS 15.0 SDK; older SDKs do
+ * not declare it at all, so suppressing the availability diagnostic above is
+ * not enough and the implementation has to be compiled out.  Nothing is lost:
+ * hvf_arch_vm_create() refuses to start with the in-kernel vGIC enabled when
+ * built this way, exactly as it does at run time on macOS versions before 15.
+ */
+#if defined(MAC_OS_VERSION_15_0)
+
 struct HVFARMGICv3Class {
     ARMGICv3CommonClass parent_class;
     DeviceRealize parent_realize;
@@ -831,5 +840,26 @@
 }
 
 type_init(hvf_gicv3_register_types)
+
+#else /* !defined(MAC_OS_VERSION_15_0) */
+
+/*
+ * Migration state only, mirroring hw/intc/arm_gicv3_hvf_stub.c.  The device
+ * type itself is never instantiated, as TYPE_HVF_GICV3 is only selected when
+ * hvf_irqchip_in_kernel() is set, which cannot be reached here.
+ */
+static bool gicv3_is_hvf(void *opaque)
+{
+    return false;
+}
 
+const VMStateDescription vmstate_gicv3_hvf = {
+    .name = "arm_gicv3/hvf_gic_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = gicv3_is_hvf,
+};
+
+#endif /* defined(MAC_OS_VERSION_15_0) */
+
 #pragma clang diagnostic pop
