diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 7993085bea..924476480b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -184,11 +184,11 @@ typedef struct {
 
 #ifdef TARGET_AARCH64
 # define ARM_MAX_VQ    16
-void arm_cpu_sve_finalize(ARMCPU *cpu);
+void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
 uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
 #else
 # define ARM_MAX_VQ    1
-static inline void arm_cpu_sve_finalize(ARMCPU *cpu) { }
+static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
 static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
 { return 0; }
 #endif
@@ -924,12 +924,14 @@ struct ARMCPU {
     /*
      * In sve_vq_map each set bit is a supported vector length of
      * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
-     * length in quadwords. We need a map size twice the maximum
-     * quadword length though because we use two bits for each vector
-     * length in order to track four states: uninitialized, uninitialized
-     * but supported by KVM, off, and on.
+     * length in quadwords.
+     *
+     * While processing properties during initialization, corresponding
+     * sve_vq_init bits are set for bits in sve_vq_map that have been
+     * set by properties.
      */
-    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ * 2);
+    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
+    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
 };
 
 void arm_cpu_post_init(Object *obj);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 604f5c3651..a113c30def 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1255,8 +1255,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        arm_cpu_sve_finalize(cpu);
+    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+        arm_cpu_sve_finalize(cpu, &local_err);
+        if (local_err != NULL) {
+            error_propagate(errp, local_err);
+            return;
+        }
     }
 
     if (arm_feature(env, ARM_FEATURE_AARCH64) &&
@@ -2656,7 +2660,9 @@ static void arm_host_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
 
     kvm_arm_set_cpu_features_from_host(cpu);
-    aarch64_add_sve_properties(obj);
+    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+        aarch64_add_sve_properties(obj);
+    }
     arm_cpu_post_init(obj);
 }
 
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 0313eec88a..7c7e54ad78 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -257,165 +257,168 @@ static void aarch64_a72_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
 }
 
-/*
- * While we eventually use cpu->sve_vq_map as a typical bitmap, where each vq
- * has only two states (off/on), until we've finalized the map at realize time
- * we use an extra bit, at the vq - 1 + ARM_MAX_VQ bit number, to also allow
- * tracking of the uninitialized state and the uninitialized but supported by
- * KVM state. The arm_vq_state typedef and following functions allow us to more
- * easily work with the bitmap.
- */
-typedef enum arm_vq_state {
-    ARM_VQ_OFF,
-    ARM_VQ_ON,
-    ARM_VQ_UNINITIALIZED,
-    ARM_VQ_UNINITIALIZED_KVM_SUPPORTED
-    /*
-     * More states cannot be added without adding bits to sve_vq_map
-     * and modifying its supporting functions.
-     */
-} arm_vq_state;
-
-static arm_vq_state arm_cpu_vq_map_get(ARMCPU *cpu, uint32_t vq)
+void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
 {
-    assert(vq <= ARM_MAX_VQ);
-
-    return test_bit(vq - 1, cpu->sve_vq_map) |
-           test_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map) << 1;
-}
-
-static void arm_cpu_vq_map_set(ARMCPU *cpu, uint32_t vq, arm_vq_state state)
-{
-    assert(vq <= ARM_MAX_VQ);
-    assert(state == ARM_VQ_OFF || state == ARM_VQ_ON);
-
-    clear_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map);
-
-    if (state == ARM_VQ_ON) {
-        set_bit(vq - 1, cpu->sve_vq_map);
-    } else {
-        clear_bit(vq - 1, cpu->sve_vq_map);
-    }
-}
-
-static bool arm_cpu_vq_kvm_supported(ARMCPU *cpu, uint32_t vq)
-{
-    return arm_cpu_vq_map_get(cpu, vq) != ARM_VQ_UNINITIALIZED;
-}
-
-static bool arm_cpu_vq_uninitialized(ARMCPU *cpu, uint32_t vq)
-{
-    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
-
-    if (kvm_enabled()) {
-        return vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED;
-    }
-
-    return vq_state == ARM_VQ_UNINITIALIZED;
-}
-
-/*
- * Uninitialized vector lengths need a default value to use in case we need
- * to query their value prior to map finalization. Additionally map finalizing
- * itself needs to determine what value to assign uninitialized vector lengths.
- * The default is determined as follows:
- *
- *  * When no vector lengths have been explicitly enabled, i.e. either no
- *    input has been provided by the user at all, or vector lengths have
- *    only been disabled, then all uninitialized vector lengths default 'ON'.
- *
- *  * When one or more vector lengths have been enabled, then all uninitialized
- *    vector lengths default 'OFF'. Note, when checking for enabled vector
- *    lengths we do not discriminate between user-enabled vector lengths and
- *    auto-enabled vector lengths (which were auto-enabled in order to satisfy
- *    the user-enabled vector lengths). This implies the default can never
- *    transition back to 'ON', even if the user-enabled and auto-enabled vector
- *    lengths that initially transitioned it to 'OFF' are later disabled, as at
- *    least one vector length must remain enabled unless the SVE feature is
- *    completely disabled. If SVE is completely disabled then all vector
- *    lengths are effectively 'OFF'.
- */
-static bool arm_cpu_vq_map_get_default(ARMCPU *cpu)
-{
-    uint32_t vq;
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-/*
- * We need to be able to track the number of enabled (or will-be enabled)
- * vector lengths in order to ensure we never drop to zero. If the default
- * is 'ON', then we count enabled and uninitialized vector lengths. Otherwise,
- * if the default is 'OFF', then we only count enabled vector lengths.
- */
-static int arm_cpu_num_vqs_available(ARMCPU *cpu)
-{
-    uint32_t vq;
-    bool defval;
-    int num = 0;
-
-    defval = arm_cpu_vq_map_get_default(cpu);
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            ++num;
-        } else if (defval && arm_cpu_vq_uninitialized(cpu, vq)) {
-            ++num;
-        }
-    }
-
-    return num;
-}
-
-static void arm_cpu_vq_map_init(ARMCPU *cpu)
-{
-    /* Set all vq's to 0b10 (ARM_VQ_UNINITIALIZED) */
-    bitmap_clear(cpu->sve_vq_map, 0, ARM_MAX_VQ);
-    bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ);
-
-    if (kvm_enabled()) {
-        /*
-         * As the upper bits of the ARM_VQ_UNINITIALIZED_KVM_SUPPORTED (0b11)
-         * states have already been set with the bitmap_set() above, we only
-         * need to OR in the lower bits.
-         */
-        DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
+    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
+    DECLARE_BITMAP(test, ARM_MAX_VQ);
+    uint32_t vq, max_vq = 0;
 
+    /* Collect the set of VQ supported by KVM. */
+    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
         kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
-        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, kvm_supported, ARM_MAX_VQ);
+    } else {
+        bitmap_zero(kvm_supported, ARM_MAX_VQ);
     }
-}
 
-void arm_cpu_sve_finalize(ARMCPU *cpu)
-{
-    bool defval = arm_cpu_vq_map_get_default(cpu);
-    uint32_t vq, max_vq;
+    /*
+     * Process explicit sve<N> properties.
+     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
+     * Check first for any sve<N> enabled.
+     */
+    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
+        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
 
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-        } else if (arm_cpu_vq_uninitialized(cpu, vq)) {
-            if (defval) {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
-            } else {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
+            error_setg(errp, "cannot enable sve%d", max_vq * 128);
+            error_append_hint(errp, "sve%d is larger than the maximum vector "
+                              "length, sve-max-vq=%d (%d bits)\n",
+                              max_vq * 128, cpu->sve_max_vq,
+                              cpu->sve_max_vq * 128);
+            return;
+        }
+
+        /* Propagate enabled bits down through required powers-of-two. */
+        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
+                set_bit(vq - 1, cpu->sve_vq_map);
+                set_bit(vq - 1, cpu->sve_vq_init);
             }
         }
+
+        /*
+         * For KVM we have to automatically enable all supported unitialized
+         * lengths, even when the smaller lengths are not all powers-of-two.
+         */
+        if (kvm_enabled()) {
+            if (!kvm_arm_sve_supported(CPU(cpu))) {
+                error_setg(errp, "cannot enable sve%d", max_vq);
+                error_append_hint(errp, "SVE not supported by "
+                                  "KVM on this host\n");
+                return;
+            }
+            bitmap_andnot(test, kvm_supported, cpu->sve_vq_init, max_vq);
+            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
+            bitmap_or(cpu->sve_vq_init, cpu->sve_vq_init, test, max_vq);
+        }
+    } else if (cpu->sve_max_vq == 0) {
+        /*
+         * No explicit bits enabled, and no implicit bits from sve-max-vq.
+         */
+        if (!cpu_isar_feature(aa64_sve, cpu)) {
+            /* SVE is disabled and so are all vector lengths.  Good. */
+            return;
+        }
+
+        /* Disabling a power-of-two disables all larger lengths. */
+        if (test_bit(0, cpu->sve_vq_init)) {
+            error_setg(errp, "cannot disable sve128");
+            error_append_hint(errp, "Disabling sve128 results in all vector "
+                              "lengths being disabled.\n");
+            error_append_hint(errp, "With SVE enabled, at least one vector "
+                                  "length must be enabled.\n");
+
+            return;
+        }
+        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
+            if (test_bit(vq - 1, cpu->sve_vq_init)) {
+                break;
+            }
+        }
+        max_vq = (vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ);
+
+        /* Enable all supported bits other than those explicit disabled. */
+        if (kvm_enabled()) {
+            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
+                          cpu->sve_vq_init, max_vq);
+        } else {
+            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
+        }
+        bitmap_set(cpu->sve_vq_init, 0, max_vq);
+        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
     }
 
-    max_vq = arm_cpu_vq_map_next_smaller(cpu, ARM_MAX_VQ + 1);
+    /*
+     * Process the sve-max-vq property.
+     * Note that we know from the above that no bit above
+     * sve-max-vq is currently set.
+     */
+    if (cpu->sve_max_vq != 0) {
+        max_vq = cpu->sve_max_vq;
 
-    if (!cpu->sve_max_vq) {
-        cpu->sve_max_vq = max_vq;
+        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
+            test_bit(max_vq - 1, cpu->sve_vq_init)) {
+            error_setg(errp, "cannot disable sve%d", max_vq * 128);
+            error_append_hint(errp, "The maximum vector length must be "
+                              "enabled, sve-max-vq=%d (%d bits)\n",
+                              max_vq, max_vq * 128);
+            return;
+        }
+
+        /* Set all bits not explicitly set within sve-max-vq.  */
+        bitmap_complement(test, cpu->sve_vq_init, max_vq);
+        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
     }
 
-    assert(max_vq && cpu->sve_max_vq == max_vq);
+    /*
+     * At this point we will have found max_vq.  All bits implied from
+     * other properties are set or clear in cpu->sve_vq_map.
+     * All bits implied from other sve<N> are set in cpu->sve_vq_init.
+     * If sve_vq_map<N> & !sve_vq_init<N>, then the bit must have come
+     * sve-max-vq.
+     */
+    assert(max_vq != 0);
+
+    /* Ensure all required powers-of-two are enabled. */
+    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+            error_setg(errp, "cannot disable sve%d", vq * 128);
+            error_append_hint(errp, "sve%d is required as it "
+                              "is a power-of-2 length smaller than "
+                              "the maximum, sve%d\n",
+                              vq * 128, max_vq * 128);
+            return;
+        }
+    }
+
+    /* Ensure the set of lengths matches what KVM supports. */
+    if (kvm_enabled()) {
+        bitmap_xor(test, cpu->sve_vq_map, kvm_supported, max_vq);
+        if (!bitmap_empty(test, max_vq)) {
+            vq = find_last_bit(test, max_vq);
+            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+                error_setg(errp, "cannot disable sve%d", vq * 128);
+                error_append_hint(errp, "The KVM host requires all "
+                                  "supported vector lengths smaller "
+                                  "than %d bits to also be enabled.\n",
+                                  max_vq * 128);
+            } else if (test_bit(vq - 1, cpu->sve_vq_init)) {
+                error_setg(errp, "cannot enable sve%d", vq * 128);
+                error_append_hint(errp, "This KVM host does not support "
+                                  "the vector length %d-bits.\n", vq * 128);
+            } else {
+                error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq);
+                error_append_hint(errp, "This KVM host does not support "
+                                  "the vector length %d-bits.\n", vq * 128);
+                error_append_hint(errp, "It may not be possible to use "
+                                  "sve-max-vq with this KVM host. Try "
+                                  "using only sve<vl-bits> properties.\n");
+            }
+            return;
+        }
+    }
+
+    /* From now on sve_max_vq is the actual maximum supported length. */
+    cpu->sve_max_vq = max_vq;
 }
 
 uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
@@ -427,6 +430,7 @@ uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
      * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
      * function always returns the next smaller than the input.
      */
+    assert(vq > 1);
     assert(vq <= ARM_MAX_VQ + 1);
 
     bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
@@ -437,7 +441,15 @@ static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
                                    void *opaque, Error **errp)
 {
     ARMCPU *cpu = ARM_CPU(obj);
-    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
+    uint32_t value;
+
+    /* All vector lengths are disabled when SVE is off. */
+    if (!cpu_isar_feature(aa64_sve, cpu)) {
+        value = 0;
+    } else {
+        value = cpu->sve_max_vq;
+    }
+    visit_type_uint32(v, name, &value, errp);
 }
 
 static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
@@ -445,7 +457,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     Error *err = NULL;
-    uint32_t vq;
 
     visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
     if (err) {
@@ -465,27 +476,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
                           ARM_MAX_VQ);
         return;
     }
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (vq <= cpu->sve_max_vq) {
-            char tmp[8];
-
-            sprintf(tmp, "sve%d", vq * 128);
-            object_property_set_bool(obj, true, tmp, &err);
-            if (err) {
-                if (kvm_enabled()) {
-                    error_append_hint(&err, "It is not possible to use "
-                                      "sve-max-vq with this KVM host. Try "
-                                      "using only sve<vl-bits> "
-                                      "properties.\n");
-                }
-                error_propagate(errp, err);
-                return;
-            }
-        } else if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-        }
-    }
 }
 
 static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
@@ -493,24 +483,14 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq = atoi(&name[3]) / 128;
-    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
     bool value;
 
+    /* All vector lengths are disabled when SVE is off. */
     if (!cpu_isar_feature(aa64_sve, cpu)) {
-        /* All vector lengths are disabled when SVE is off. */
         value = false;
-    } else if (vq_state == ARM_VQ_ON) {
-        value = true;
-    } else if (vq_state == ARM_VQ_OFF) {
-        value = false;
-    } else if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-        value = false;
-    } else if (arm_cpu_vq_map_get_default(cpu)) {
-        value = true;
     } else {
-        value = false;
+        value = test_bit(vq - 1, cpu->sve_vq_map);
     }
-
     visit_type_bool(v, name, &value, errp);
 }
 
@@ -519,7 +499,6 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq = atoi(&name[3]) / 128;
-    uint32_t max_vq = 0;
     Error *err = NULL;
     bool value;
 
@@ -529,146 +508,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
         return;
     }
 
-    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
-        error_setg(errp, "cannot enable %s", name);
-        error_append_hint(errp, "SVE not supported by KVM on this host\n");
-        return;
-    }
-
-    /*
-     * We need to know the maximum vector length, which may just currently
-     * be the maximum length, in order to validate the enabling/disabling
-     * of this vector length.
-     */
-    if (!cpu->sve_max_vq) {
-        for (max_vq = ARM_MAX_VQ; max_vq >= 1; --max_vq) {
-            if (arm_cpu_vq_map_get(cpu, max_vq) == ARM_VQ_ON) {
-                break;
-            }
-        }
-    }
-
-    if (cpu->sve_max_vq && value && vq > cpu->sve_max_vq) {
-        error_setg(errp, "cannot enable %s", name);
-        error_append_hint(errp, "vq=%d (%d bits) is larger than the "
-                          "maximum vector length, sve-max-vq=%d "
-                          "(%d bits)\n", vq, vq * 128,
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (cpu->sve_max_vq && !value && vq == cpu->sve_max_vq) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "The maximum vector length must be "
-                          "enabled, sve-max-vq=%d (%d bits)\n",
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (!kvm_enabled() && cpu->sve_max_vq && !value &&
-               vq < cpu->sve_max_vq && is_power_of_2(vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "vq=%d (%d bits) is required as it is a "
-                          "power-of-2 length smaller than the maximum, "
-                          "sve-max-vq=%d (%d bits)\n", vq, vq * 128,
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (!kvm_enabled() && max_vq && !value && vq < max_vq &&
-               is_power_of_2(vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "Vector length %d-bits is required as it "
-                          "is a power-of-2 length smaller than another "
-                          "enabled vector length. Disable all larger vector "
-                          "lengths first.\n", vq * 128);
-    } else if (kvm_enabled() && !value && vq < max_vq &&
-                arm_cpu_vq_kvm_supported(cpu, vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "Vector length %d-bits is a KVM supported "
-                          "length smaller than another enabled vector "
-                          "length. Disable all larger vector lengths "
-                          "first.\n", vq * 128);
-    } else if (kvm_enabled() && value && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-        error_setg(errp, "cannot enable %s", name);
-        error_append_hint(errp, "This KVM host does not support "
-                          "the vector length %d-bits.\n", vq * 128);
+    if (value) {
+        set_bit(vq - 1, cpu->sve_vq_map);
     } else {
-        uint32_t s;
-
-        if (value) {
-            bool fail = false;
-
-            /*
-             * Enabling a vector length automatically enables all
-             * uninitialized power-of-2 lengths smaller than it, as
-             * per the architecture.
-             *
-             * For KVM we have to automatically enable all supported,
-             * uninitialized lengths smaller than this length, even
-             * when the smaller lengths are not power-of-2's.
-             */
-            for (s = 1; s < vq; ++s) {
-                if (kvm_enabled() || is_power_of_2(s)) {
-                    if (arm_cpu_vq_uninitialized(cpu, s)) {
-                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON);
-                    } else if (arm_cpu_vq_map_get(cpu, s) == ARM_VQ_OFF) {
-                        fail = true;
-                        break;
-                    }
-                }
-            }
-
-            if (!kvm_enabled() && fail) {
-                error_setg(errp, "cannot enable %s", name);
-                error_append_hint(errp, "Vector length %d-bits is disabled "
-                                  "and is a power-of-2 length smaller than "
-                                  "%s. All power-of-2 vector lengths smaller "
-                                  "than the maximum length are required.\n",
-                                  s * 128, name);
-
-            } else if (fail) {
-                error_setg(errp, "cannot enable %s", name);
-                error_append_hint(errp, "Vector length %d-bits is disabled "
-                                  "and the KVM host requires all supported "
-                                  "vector lengths smaller than %s to also be "
-                                  "enabled.\n", s * 128, name);
-            } else {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
-            }
-        } else {
-            /*
-             * When disabling vector lengths with KVM enabled if the vq wasn't
-             * supported then we leave it in the ARM_VQ_UNINITIALIZED state in
-             * order to keep that unsupported information. It'll be set to OFF
-             * later when we finalize the map.
-             *
-             * We would have errored-out already if we were attempting to
-             * disable a power-of-2 vector length less than another enabled
-             * vector length, but there may be uninitialized vector lengths
-             * larger than a power-of-2 vector length that we're disabling.
-             * We disable all of those lengths now too, as they can no longer
-             * be enabled. Additionally, for KVM, we have to automatically
-             * disable all supported, uninitialized lengths larger than this
-             * length, even when this length is not a power-of-2.
-             */
-            if (kvm_enabled() || is_power_of_2(vq)) {
-                for (s = vq + 1; s <= ARM_MAX_VQ; ++s) {
-                    if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
-                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
-                    }
-                }
-            }
-
-            if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-            }
-
-            /*
-             * We just disabled one or more vector lengths. We need to make
-             * sure we didn't disable them all when SVE is enabled.
-             */
-            if (cpu_isar_feature(aa64_sve, cpu) &&
-                !arm_cpu_num_vqs_available(cpu)) {
-                error_setg(errp, "cannot disable %s", name);
-                error_append_hint(errp, "Disabling %s results in all vector "
-                                  "lengths being disabled.\n", name);
-                error_append_hint(errp, "With SVE enabled, at least one vector "
-                                  "length must be enabled.\n");
-            }
-        }
+        clear_bit(vq - 1, cpu->sve_vq_map);
     }
+    set_bit(vq - 1, cpu->sve_vq_init);
 }
 
 static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
@@ -702,32 +547,15 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
     t = cpu->isar.id_aa64pfr0;
     t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
     cpu->isar.id_aa64pfr0 = t;
-
-    /*
-     * When SVE is enabled ensure that we have at least one vector
-     * length available.
-     */
-    if (cpu_isar_feature(aa64_sve, cpu) && !arm_cpu_num_vqs_available(cpu)) {
-        error_setg(errp, "cannot enable SVE");
-        error_append_hint(errp, "All possible SVE vector lengths have "
-                          "been disabled.\n");
-    }
 }
 
 void aarch64_add_sve_properties(Object *obj)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq;
 
     object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
                         cpu_arm_set_sve, NULL, NULL, &error_fatal);
 
-    /*
-     * sve_vq_map uses a special state while setting properties, so
-     * we initialize it here with its init function and finalize it
-     * in arm_cpu_realizefn().
-     */
-    arm_cpu_vq_map_init(cpu);
     for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
         char name[8];
         sprintf(name, "sve%d", vq * 128);
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index e2d559c230..433cbe9b53 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -195,6 +195,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         if (!err) {
             visit_check_struct(visitor, &err);
         }
+        if (!err) {
+            arm_cpu_sve_finalize(ARM_CPU(obj), &err);
+        }
         visit_end_struct(visitor, NULL);
         visit_free(visitor);
         if (err) {
@@ -202,6 +205,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
             error_propagate(errp, err);
             return NULL;
         }
+    } else {
+        Error *err = NULL;
+        arm_cpu_sve_finalize(ARM_CPU(obj), &err);
+        assert(err == NULL);
     }
 
     expansion_info = g_new0(CpuModelExpansionInfo, 1);
