hvf/arm: handle FEAT_SME2 migration
SME2 support adds the following state for HVF guests: - Vector registers Z0, ... , Z31 (introduced by FEAT_SVE but HVF does not support it) - Predicate registers P0, .., P15 (also FEAT_SVE) - ZA register - ZT0 register - PSTATE.{SM,ZA} bits (SVCR pseudo-register) - SMPRI_EL1 which handles the PE's priority in the SMCU - TPIDR2_EL0 the thread local ID register for SME Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr> Message-id: 20260306-sme2-hvf-v7-1-e72eeda41ed3@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Manos Pitsidianakis committed
Mar 6, 2026 at 14:45 UTC
170de3856023b0a045b9717561236f9f4bc59c0d
5 files changed
+518
-3
target/arm/hvf/hvf.c
+296
-2
@@ -395,6 +395,60 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
395
{ HV_SIMD_FP_REG_Q31, offsetof(CPUARMState, vfp.zregs[31]) },
396
};
397
398
+static const struct hvf_reg_match hvf_sme2_zreg_match[] = {
399
+ { HV_SME_Z_REG_0, offsetof(CPUARMState, vfp.zregs[0]) },
400
+ { HV_SME_Z_REG_1, offsetof(CPUARMState, vfp.zregs[1]) },
401
+ { HV_SME_Z_REG_2, offsetof(CPUARMState, vfp.zregs[2]) },
402
+ { HV_SME_Z_REG_3, offsetof(CPUARMState, vfp.zregs[3]) },
403
+ { HV_SME_Z_REG_4, offsetof(CPUARMState, vfp.zregs[4]) },
404
+ { HV_SME_Z_REG_5, offsetof(CPUARMState, vfp.zregs[5]) },
405
+ { HV_SME_Z_REG_6, offsetof(CPUARMState, vfp.zregs[6]) },
406
+ { HV_SME_Z_REG_7, offsetof(CPUARMState, vfp.zregs[7]) },
407
+ { HV_SME_Z_REG_8, offsetof(CPUARMState, vfp.zregs[8]) },
408
+ { HV_SME_Z_REG_9, offsetof(CPUARMState, vfp.zregs[9]) },
409
+ { HV_SME_Z_REG_10, offsetof(CPUARMState, vfp.zregs[10]) },
410
+ { HV_SME_Z_REG_11, offsetof(CPUARMState, vfp.zregs[11]) },
411
+ { HV_SME_Z_REG_12, offsetof(CPUARMState, vfp.zregs[12]) },
412
+ { HV_SME_Z_REG_13, offsetof(CPUARMState, vfp.zregs[13]) },
413
+ { HV_SME_Z_REG_14, offsetof(CPUARMState, vfp.zregs[14]) },
414
+ { HV_SME_Z_REG_15, offsetof(CPUARMState, vfp.zregs[15]) },
415
+ { HV_SME_Z_REG_16, offsetof(CPUARMState, vfp.zregs[16]) },
416
+ { HV_SME_Z_REG_17, offsetof(CPUARMState, vfp.zregs[17]) },
417
+ { HV_SME_Z_REG_18, offsetof(CPUARMState, vfp.zregs[18]) },
418
+ { HV_SME_Z_REG_19, offsetof(CPUARMState, vfp.zregs[19]) },
419
+ { HV_SME_Z_REG_20, offsetof(CPUARMState, vfp.zregs[20]) },
420
+ { HV_SME_Z_REG_21, offsetof(CPUARMState, vfp.zregs[21]) },
421
+ { HV_SME_Z_REG_22, offsetof(CPUARMState, vfp.zregs[22]) },
422
+ { HV_SME_Z_REG_23, offsetof(CPUARMState, vfp.zregs[23]) },
423
+ { HV_SME_Z_REG_24, offsetof(CPUARMState, vfp.zregs[24]) },
424
+ { HV_SME_Z_REG_25, offsetof(CPUARMState, vfp.zregs[25]) },
425
+ { HV_SME_Z_REG_26, offsetof(CPUARMState, vfp.zregs[26]) },
426
+ { HV_SME_Z_REG_27, offsetof(CPUARMState, vfp.zregs[27]) },
427
+ { HV_SME_Z_REG_28, offsetof(CPUARMState, vfp.zregs[28]) },
428
+ { HV_SME_Z_REG_29, offsetof(CPUARMState, vfp.zregs[29]) },
429
+ { HV_SME_Z_REG_30, offsetof(CPUARMState, vfp.zregs[30]) },
430
+ { HV_SME_Z_REG_31, offsetof(CPUARMState, vfp.zregs[31]) },
431
+};
432
+
433
+static const struct hvf_reg_match hvf_sme2_preg_match[] = {
434
+ { HV_SME_P_REG_0, offsetof(CPUARMState, vfp.pregs[0]) },
435
+ { HV_SME_P_REG_1, offsetof(CPUARMState, vfp.pregs[1]) },
436
+ { HV_SME_P_REG_2, offsetof(CPUARMState, vfp.pregs[2]) },
437
+ { HV_SME_P_REG_3, offsetof(CPUARMState, vfp.pregs[3]) },
438
+ { HV_SME_P_REG_4, offsetof(CPUARMState, vfp.pregs[4]) },
439
+ { HV_SME_P_REG_5, offsetof(CPUARMState, vfp.pregs[5]) },
440
+ { HV_SME_P_REG_6, offsetof(CPUARMState, vfp.pregs[6]) },
441
+ { HV_SME_P_REG_7, offsetof(CPUARMState, vfp.pregs[7]) },
442
+ { HV_SME_P_REG_8, offsetof(CPUARMState, vfp.pregs[8]) },
443
+ { HV_SME_P_REG_9, offsetof(CPUARMState, vfp.pregs[9]) },
444
+ { HV_SME_P_REG_10, offsetof(CPUARMState, vfp.pregs[10]) },
445
+ { HV_SME_P_REG_11, offsetof(CPUARMState, vfp.pregs[11]) },
446
+ { HV_SME_P_REG_12, offsetof(CPUARMState, vfp.pregs[12]) },
447
+ { HV_SME_P_REG_13, offsetof(CPUARMState, vfp.pregs[13]) },
448
+ { HV_SME_P_REG_14, offsetof(CPUARMState, vfp.pregs[14]) },
449
+ { HV_SME_P_REG_15, offsetof(CPUARMState, vfp.pregs[15]) },
450
+};
451
+
452
/*
453
* QEMU uses KVM system register ids in the migration format.
454
* Conveniently, HVF uses the same encoding of the op* and cr* parameters
@@ -406,22 +460,201 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
460
#define HVF_TO_KVMID(HVF) \
461
(CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF))
462
409
-/* Verify this at compile-time. */
463
+/*
464
+ * Verify this at compile-time.
465
+ *
466
+ * SME2 registers are guarded by a runtime availability attribute instead of a
467
+ * compile-time def, so verify those at runtime in hvf_arch_init_vcpu() below.
468
+ */
469
470
#define DEF_SYSREG(HVF_ID, ...) \
471
QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
472
+#define DEF_SYSREG_15_02(...)
473
474
#include "sysreg.c.inc"
475
476
#undef DEF_SYSREG
477
+#undef DEF_SYSREG_15_02
478
479
#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) HVF_ID,
480
+#define DEF_SYSREG_15_02(...)
481
482
static const hv_sys_reg_t hvf_sreg_list[] = {
483
#include "sysreg.c.inc"
484
};
485
486
#undef DEF_SYSREG
487
+#undef DEF_SYSREG_15_02
488
+
489
+#define DEF_SYSREG(...)
490
+#define DEF_SYSREG_15_02(HVF_ID, op0, op1, crn, crm, op2) HVF_ID,
491
+
492
+API_AVAILABLE(macos(15.2))
493
+static const hv_sys_reg_t hvf_sreg_list_sme2[] = {
494
+#include "sysreg.c.inc"
495
+};
496
+
497
+#undef DEF_SYSREG
498
+#undef DEF_SYSREG_15_02
499
+
500
+/*
501
+ * For FEAT_SME2 migration, we need to store PSTATE.{SM,ZA} bits which are
502
+ * accessible with the SVCR pseudo-register. However, in the HVF API this is
503
+ * not exposed as a system-register (i.e. HVF_SYS_REG_SVCR) but a custom
504
+ * struct, hv_vcpu_sme_state_t. So we need to define our own KVMID in order to
505
+ * store it in cpreg_values and make it migrateable.
506
+ */
507
+#define SVCR KVMID_AA64_SYS_REG64(3, 3, 4, 2, 2)
508
+
509
+API_AVAILABLE(macos(15.2))
510
+static void hvf_arch_put_sme(CPUState *cpu)
511
+{
512
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
513
+ CPUARMState *env = &arm_cpu->env;
514
+ const size_t svl_bytes = hvf_arm_sme2_get_svl();
515
+ const size_t z_size = svl_bytes;
516
+ const size_t preg_size = DIV_ROUND_UP(z_size, 8);
517
+ const size_t za_size = svl_bytes * svl_bytes;
518
+ hv_vcpu_sme_state_t sme_state = { 0 };
519
+ hv_return_t ret;
520
+ uint64_t svcr;
521
+ int n;
522
+
523
+ /*
524
+ * Set PSTATE.{SM,ZA} bits
525
+ */
526
+ svcr = arm_cpu->cpreg_values[arm_cpu->cpreg_array_len - 1];
527
+ env->svcr = svcr;
528
+
529
+ /*
530
+ * Construct SVCR (PSTATE.{SM,ZA}) state to pass to HVF:
531
+ */
532
+ sme_state.streaming_sve_mode_enabled = FIELD_EX64(env->svcr, SVCR, SM) > 0;
533
+ sme_state.za_storage_enabled = FIELD_EX64(env->svcr, SVCR, ZA) > 0;
534
+ ret = hv_vcpu_set_sme_state(cpu->accel->fd, &sme_state);
535
+ assert_hvf_ok(ret);
536
+
537
+ /*
538
+ * We only care about Z/P registers if we're in streaming SVE mode, i.e.
539
+ * PSTATE.SM is set, because only then can instructions that access them be
540
+ * used. We don't care about the register values otherwise. This is because
541
+ * when the processing unit exits/enters this mode, it zeroes out those
542
+ * registers.
543
+ */
544
+ if (sme_state.streaming_sve_mode_enabled) {
545
+ for (n = 0; n < ARRAY_SIZE(hvf_sme2_zreg_match); ++n) {
546
+ ret = hv_vcpu_set_sme_z_reg(cpu->accel->fd,
547
+ hvf_sme2_zreg_match[n].reg,
548
+ (uint8_t *)&env->vfp.zregs[n].d[0],
549
+ z_size);
550
+ assert_hvf_ok(ret);
551
+ }
552
+
553
+ for (n = 0; n < ARRAY_SIZE(hvf_sme2_preg_match); ++n) {
554
+ ret = hv_vcpu_set_sme_p_reg(cpu->accel->fd,
555
+ hvf_sme2_preg_match[n].reg,
556
+ (uint8_t *)&env->vfp.pregs[n].p[0],
557
+ preg_size);
558
+ assert_hvf_ok(ret);
559
+ }
560
+ }
561
+
562
+ /*
563
+ * If PSTATE.ZA bit is set then ZA and ZT0 are valid, otherwise they are
564
+ * zeroed out.
565
+ */
566
+ if (sme_state.za_storage_enabled) {
567
+ hv_sme_zt0_uchar64_t tmp = { 0 };
568
+
569
+ memcpy(&tmp, &env->za_state.zt0, 64);
570
+ ret = hv_vcpu_set_sme_zt0_reg(cpu->accel->fd, &tmp);
571
+ assert_hvf_ok(ret);
572
+
573
+ ret = hv_vcpu_set_sme_za_reg(cpu->accel->fd,
574
+ (uint8_t *)&env->za_state.za,
575
+ za_size);
576
+ assert_hvf_ok(ret);
577
+ }
578
+
579
+ return;
580
+}
581
+
582
+API_AVAILABLE(macos(15.2))
583
+static void hvf_arch_get_sme(CPUState *cpu)
584
+{
585
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
586
+ CPUARMState *env = &arm_cpu->env;
587
+ const size_t svl_bytes = hvf_arm_sme2_get_svl();
588
+ const size_t z_size = svl_bytes;
589
+ const size_t preg_size = DIV_ROUND_UP(z_size, 8);
590
+ const size_t za_size = svl_bytes * svl_bytes;
591
+ hv_vcpu_sme_state_t sme_state = { 0 };
592
+ hv_return_t ret;
593
+ uint64_t svcr;
594
+ int n;
595
+
596
+ /*
597
+ * Get SVCR (PSTATE.{SM,ZA}) state from HVF:
598
+ */
599
+ ret = hv_vcpu_get_sme_state(cpu->accel->fd, &sme_state);
600
+ assert_hvf_ok(ret);
601
+
602
+ /*
603
+ * Set SVCR first because changing it will zero out Z/P regs
604
+ */
605
+ svcr =
606
+ (sme_state.za_storage_enabled ? R_SVCR_ZA_MASK : 0)
607
+ | (sme_state.streaming_sve_mode_enabled ? R_SVCR_SM_MASK : 0);
608
+
609
+ aarch64_set_svcr(env, svcr, R_SVCR_ZA_MASK | R_SVCR_SM_MASK);
610
+ arm_cpu->cpreg_values[arm_cpu->cpreg_array_len - 1] = svcr;
611
+
612
+ /*
613
+ * We only care about Z/P registers if we're in streaming SVE mode, i.e.
614
+ * PSTATE.SM is set, because only then can instructions that access them be
615
+ * used. We don't care about the register values otherwise. This is because
616
+ * when the processing unit exits/enters this mode, it zeroes out those
617
+ * registers.
618
+ */
619
+ if (sme_state.streaming_sve_mode_enabled) {
620
+ for (n = 0; n < ARRAY_SIZE(hvf_sme2_zreg_match); ++n) {
621
+ ret = hv_vcpu_get_sme_z_reg(cpu->accel->fd,
622
+ hvf_sme2_zreg_match[n].reg,
623
+ (uint8_t *)&env->vfp.zregs[n].d[0],
624
+ z_size);
625
+ assert_hvf_ok(ret);
626
+ }
627
+
628
+ for (n = 0; n < ARRAY_SIZE(hvf_sme2_preg_match); ++n) {
629
+ ret = hv_vcpu_get_sme_p_reg(cpu->accel->fd,
630
+ hvf_sme2_preg_match[n].reg,
631
+ (uint8_t *)&env->vfp.pregs[n].p[0],
632
+ preg_size);
633
+ assert_hvf_ok(ret);
634
+ }
635
+ }
636
+
637
+ /*
638
+ * If PSTATE.ZA bit is set then ZA and ZT0 are valid, otherwise they are
639
+ * zeroed out.
640
+ */
641
+ if (sme_state.za_storage_enabled) {
642
+ hv_sme_zt0_uchar64_t tmp = { 0 };
643
+
644
+ /* Get ZT0 in a tmp vector, and then copy it to env.za_state.zt0 */
645
+ ret = hv_vcpu_get_sme_zt0_reg(cpu->accel->fd, &tmp);
646
+ assert_hvf_ok(ret);
647
+
648
+ memcpy(&env->za_state.zt0, &tmp, 64);
649
+ ret = hv_vcpu_get_sme_za_reg(cpu->accel->fd,
650
+ (uint8_t *)&env->za_state.za,
651
+ za_size);
652
+ assert_hvf_ok(ret);
653
+
654
+ }
655
+
656
+ return;
657
+}
658
659
static uint32_t hvf_reg2cp_reg(uint32_t reg)
660
{
@@ -534,6 +767,10 @@ int hvf_arch_get_registers(CPUState *cpu)
767
uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
768
int hvf_id = KVMID_TO_HVF(kvm_id);
769
770
+ if (kvm_id == HVF_TO_KVMID(SVCR)) {
771
+ continue;
772
+ }
773
+
774
if (cpu->accel->guest_debug_enabled) {
775
/* Handle debug registers */
776
switch (hvf_id) {
@@ -627,6 +864,13 @@ int hvf_arch_get_registers(CPUState *cpu)
864
865
arm_cpu->cpreg_values[i] = val;
866
}
867
+ if (cpu_isar_feature(aa64_sme, arm_cpu)) {
868
+ if (__builtin_available(macOS 15.2, *)) {
869
+ hvf_arch_get_sme(cpu);
870
+ } else {
871
+ g_assert_not_reached();
872
+ }
873
+ }
874
assert(write_list_to_cpustate(arm_cpu));
875
876
aarch64_restore_sp(env, arm_current_el(env));
@@ -643,6 +887,18 @@ int hvf_arch_put_registers(CPUState *cpu)
887
hv_simd_fp_uchar16_t fpval;
888
int i, n;
889
890
+ /*
891
+ * Set SVCR first because changing it will zero out Z/P (including NEON)
892
+ * regs
893
+ */
894
+ if (cpu_isar_feature(aa64_sme, arm_cpu)) {
895
+ if (__builtin_available(macOS 15.2, *)) {
896
+ hvf_arch_put_sme(cpu);
897
+ } else {
898
+ g_assert_not_reached();
899
+ }
900
+ }
901
+
902
for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
903
val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
904
ret = hv_vcpu_set_reg(cpu->accel->fd, hvf_reg_match[i].reg, val);
@@ -672,6 +928,10 @@ int hvf_arch_put_registers(CPUState *cpu)
928
uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
929
int hvf_id = KVMID_TO_HVF(kvm_id);
930
931
+ if (kvm_id == HVF_TO_KVMID(SVCR)) {
932
+ continue;
933
+ }
934
+
935
if (cpu->accel->guest_debug_enabled) {
936
/* Handle debug registers */
937
switch (hvf_id) {
@@ -985,6 +1245,20 @@ int hvf_arch_init_vcpu(CPUState *cpu)
1245
hv_return_t ret;
1246
int i;
1247
1248
+ if (__builtin_available(macOS 15.2, *)) {
1249
+ if (hvf_arm_sme2_supported()) {
1250
+ sregs_match_len += ARRAY_SIZE(hvf_sreg_list_sme2) + 1;
1251
+ }
1252
+
1253
+#define DEF_SYSREG_15_02(HVF_ID, ...) \
1254
+ g_assert(HVF_ID == KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
1255
+#define DEF_SYSREG(...)
1256
+
1257
+#include "sysreg.c.inc"
1258
+
1259
+#undef DEF_SYSREG
1260
+#undef DEF_SYSREG_15_02
1261
+ }
1262
env->aarch64 = true;
1263
1264
/* system count frequency sanity check */
@@ -1005,7 +1279,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
1279
memset(arm_cpu->cpreg_values, 0, sregs_match_len * sizeof(uint64_t));
1280
1281
/* Populate cp list for all known sysregs */
1008
- for (i = 0; i < sregs_match_len; i++) {
1282
+ for (i = 0; i < ARRAY_SIZE(hvf_sreg_list); i++) {
1283
hv_sys_reg_t hvf_id = hvf_sreg_list[i];
1284
uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
1285
uint32_t key = kvm_to_cpreg_id(kvm_id);
@@ -1016,6 +1290,26 @@ int hvf_arch_init_vcpu(CPUState *cpu)
1290
arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
1291
}
1292
}
1293
+ if (__builtin_available(macOS 15.2, *)) {
1294
+ if (hvf_arm_sme2_supported()) {
1295
+ for (i = 0; i < ARRAY_SIZE(hvf_sreg_list_sme2); i++) {
1296
+ hv_sys_reg_t hvf_id = hvf_sreg_list_sme2[i];
1297
+ uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
1298
+ uint32_t key = kvm_to_cpreg_id(kvm_id);
1299
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
1300
+
1301
+ if (ri) {
1302
+ assert(!(ri->type & ARM_CP_NO_RAW));
1303
+ arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
1304
+ }
1305
+ }
1306
+ /*
1307
+ * Add SVCR last. It is elsewhere assumed its index is after
1308
+ * hvf_sreg_list and hvf_sreg_list_sme2.
1309
+ */
1310
+ arm_cpu->cpreg_indexes[sregs_cnt++] = HVF_TO_KVMID(SVCR);
1311
+ }
1312
+ }
1313
arm_cpu->cpreg_array_len = sregs_cnt;
1314
arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
1315
target/arm/hvf/hvf_sme_stubs.h
new
+172
@@ -0,0 +1,172 @@
1
+/* SPDX-License-Identifier: GPL-2.0-or-later */
2
+
3
+typedef int32_t hv_return_t;
4
+typedef uint64_t hv_vcpu_t;
5
+
6
+static inline bool hvf_arm_sme2_supported(void)
7
+{
8
+ return false;
9
+}
10
+
11
+static inline uint32_t hvf_arm_sme2_get_svl(void)
12
+{
13
+ g_assert_not_reached();
14
+}
15
+
16
+typedef enum hv_sme_p_reg_t {
17
+ HV_SME_P_REG_0,
18
+ HV_SME_P_REG_1,
19
+ HV_SME_P_REG_2,
20
+ HV_SME_P_REG_3,
21
+ HV_SME_P_REG_4,
22
+ HV_SME_P_REG_5,
23
+ HV_SME_P_REG_6,
24
+ HV_SME_P_REG_7,
25
+ HV_SME_P_REG_8,
26
+ HV_SME_P_REG_9,
27
+ HV_SME_P_REG_10,
28
+ HV_SME_P_REG_11,
29
+ HV_SME_P_REG_12,
30
+ HV_SME_P_REG_13,
31
+ HV_SME_P_REG_14,
32
+ HV_SME_P_REG_15,
33
+} hv_sme_p_reg_t;
34
+
35
+/*
36
+ * The system version of this type declares it with
37
+ * __attribute__((ext_vector_type(64)))
38
+ * However, that is clang specific and not supported by GCC.
39
+ * Since these headers are only here for the case where the system
40
+ * headers do not provide these types (including both older macos
41
+ * and non-macos hosts), we don't need to make the type match
42
+ * exactly, so we declare it as a uint8_t array.
43
+ */
44
+typedef uint8_t hv_sme_zt0_uchar64_t[64];
45
+
46
+typedef enum hv_sme_z_reg_t {
47
+ HV_SME_Z_REG_0,
48
+ HV_SME_Z_REG_1,
49
+ HV_SME_Z_REG_2,
50
+ HV_SME_Z_REG_3,
51
+ HV_SME_Z_REG_4,
52
+ HV_SME_Z_REG_5,
53
+ HV_SME_Z_REG_6,
54
+ HV_SME_Z_REG_7,
55
+ HV_SME_Z_REG_8,
56
+ HV_SME_Z_REG_9,
57
+ HV_SME_Z_REG_10,
58
+ HV_SME_Z_REG_11,
59
+ HV_SME_Z_REG_12,
60
+ HV_SME_Z_REG_13,
61
+ HV_SME_Z_REG_14,
62
+ HV_SME_Z_REG_15,
63
+ HV_SME_Z_REG_16,
64
+ HV_SME_Z_REG_17,
65
+ HV_SME_Z_REG_18,
66
+ HV_SME_Z_REG_19,
67
+ HV_SME_Z_REG_20,
68
+ HV_SME_Z_REG_21,
69
+ HV_SME_Z_REG_22,
70
+ HV_SME_Z_REG_23,
71
+ HV_SME_Z_REG_24,
72
+ HV_SME_Z_REG_25,
73
+ HV_SME_Z_REG_26,
74
+ HV_SME_Z_REG_27,
75
+ HV_SME_Z_REG_28,
76
+ HV_SME_Z_REG_29,
77
+ HV_SME_Z_REG_30,
78
+ HV_SME_Z_REG_31,
79
+} hv_sme_z_reg_t;
80
+
81
+enum {
82
+ HV_SYS_REG_SMCR_EL1,
83
+ HV_SYS_REG_SMPRI_EL1,
84
+ HV_SYS_REG_TPIDR2_EL0,
85
+ HV_SYS_REG_ID_AA64ZFR0_EL1,
86
+ HV_SYS_REG_ID_AA64SMFR0_EL1,
87
+};
88
+
89
+enum {
90
+ HV_FEATURE_REG_ID_AA64SMFR0_EL1,
91
+ HV_FEATURE_REG_ID_AA64ZFR0_EL1,
92
+};
93
+
94
+typedef struct {
95
+ bool streaming_sve_mode_enabled;
96
+ bool za_storage_enabled;
97
+} hv_vcpu_sme_state_t;
98
+
99
+static inline hv_return_t hv_sme_config_get_max_svl_bytes(size_t *value)
100
+{
101
+ g_assert_not_reached();
102
+}
103
+
104
+static inline hv_return_t hv_vcpu_get_sme_state(hv_vcpu_t vcpu,
105
+ hv_vcpu_sme_state_t *sme_state)
106
+{
107
+ g_assert_not_reached();
108
+}
109
+
110
+static inline hv_return_t hv_vcpu_set_sme_state(hv_vcpu_t vcpu,
111
+ const hv_vcpu_sme_state_t *sme_state)
112
+{
113
+ g_assert_not_reached();
114
+}
115
+
116
+static inline hv_return_t hv_vcpu_get_sme_z_reg(hv_vcpu_t vcpu,
117
+ hv_sme_z_reg_t reg,
118
+ uint8_t *value,
119
+ size_t length)
120
+{
121
+ g_assert_not_reached();
122
+}
123
+
124
+static inline hv_return_t hv_vcpu_set_sme_z_reg(hv_vcpu_t vcpu,
125
+ hv_sme_z_reg_t reg,
126
+ const uint8_t *value,
127
+ size_t length)
128
+{
129
+ g_assert_not_reached();
130
+}
131
+
132
+static inline hv_return_t hv_vcpu_get_sme_p_reg(hv_vcpu_t vcpu,
133
+ hv_sme_p_reg_t reg,
134
+ uint8_t *value,
135
+ size_t length)
136
+{
137
+ g_assert_not_reached();
138
+}
139
+
140
+static inline hv_return_t hv_vcpu_set_sme_p_reg(hv_vcpu_t vcpu,
141
+ hv_sme_p_reg_t reg,
142
+ const uint8_t *value,
143
+ size_t length)
144
+{
145
+ g_assert_not_reached();
146
+}
147
+
148
+static inline hv_return_t hv_vcpu_get_sme_za_reg(hv_vcpu_t vcpu,
149
+ uint8_t *value,
150
+ size_t length)
151
+{
152
+ g_assert_not_reached();
153
+}
154
+
155
+static inline hv_return_t hv_vcpu_set_sme_za_reg(hv_vcpu_t vcpu,
156
+ const uint8_t *value,
157
+ size_t length)
158
+{
159
+ g_assert_not_reached();
160
+}
161
+
162
+static inline hv_return_t hv_vcpu_get_sme_zt0_reg(hv_vcpu_t vcpu,
163
+ hv_sme_zt0_uchar64_t *value)
164
+{
165
+ g_assert_not_reached();
166
+}
167
+
168
+static inline hv_return_t hv_vcpu_set_sme_zt0_reg(hv_vcpu_t vcpu,
169
+ const hv_sme_zt0_uchar64_t *value)
170
+{
171
+ g_assert_not_reached();
172
+}
target/arm/hvf/sysreg.c.inc
+8
@@ -145,3 +145,11 @@ DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 3, 3, 13, 0, 3)
145
DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 3, 3, 14, 3, 1)
146
DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 3, 3, 14, 3, 2)
147
DEF_SYSREG(HV_SYS_REG_SP_EL1, 3, 4, 4, 1, 0)
148
+
149
+DEF_SYSREG_15_02(HV_SYS_REG_SMCR_EL1, 3, 0, 1, 2, 6)
150
+DEF_SYSREG_15_02(HV_SYS_REG_SMPRI_EL1, 3, 0, 1, 2, 4)
151
+DEF_SYSREG_15_02(HV_SYS_REG_TPIDR2_EL0, 3, 3, 13, 0, 5)
152
+DEF_SYSREG_15_02(HV_SYS_REG_ID_AA64ZFR0_EL1, 3, 0, 0, 4, 4)
153
+DEF_SYSREG_15_02(HV_SYS_REG_ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5)
154
+DEF_SYSREG_15_02(HV_SYS_REG_SMPRI_EL1, 3, 0, 1, 2, 4)
155
+DEF_SYSREG_15_02(HV_SYS_REG_SMCR_EL1, 3, 0, 1, 2, 6)
target/arm/hvf_arm.h
+41
@@ -22,4 +22,45 @@ void hvf_arm_init_debug(void);
22
23
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
24
25
+/*
26
+ * We need access to types from macOS SDK >=15.2, so expose stubs if the
27
+ * headers are not available until we raise our minimum macOS version.
28
+ */
29
+#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
30
+ #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 150200)
31
+ #include "system/hvf_int.h"
32
+
33
+ static inline bool hvf_arm_sme2_supported(void)
34
+ {
35
+ if (__builtin_available(macOS 15.2, *)) {
36
+ size_t svl_bytes;
37
+ hv_return_t result = hv_sme_config_get_max_svl_bytes(&svl_bytes);
38
+ if (result == HV_UNSUPPORTED) {
39
+ return false;
40
+ }
41
+ assert_hvf_ok(result);
42
+ return svl_bytes > 0;
43
+ } else {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ static inline uint32_t hvf_arm_sme2_get_svl(void)
49
+ {
50
+ if (__builtin_available(macOS 15.2, *)) {
51
+ size_t svl_bytes;
52
+ hv_return_t result = hv_sme_config_get_max_svl_bytes(&svl_bytes);
53
+ assert_hvf_ok(result);
54
+ return svl_bytes;
55
+ } else {
56
+ abort();
57
+ }
58
+ }
59
+ #else /* (__MAC_OS_X_VERSION_MAX_ALLOWED >= 150200) */
60
+ #include "hvf/hvf_sme_stubs.h"
61
+ #endif /* (__MAC_OS_X_VERSION_MAX_ALLOWED >= 150200) */
62
+#else /* ifdef __MAC_OS_X_VERSION_MAX_ALLOWED */
63
+ #include "hvf/hvf_sme_stubs.h"
64
+#endif /* ifdef __MAC_OS_X_VERSION_MAX_ALLOWED */
65
+
66
#endif
target/arm/machine.c
+1
-1
@@ -233,7 +233,7 @@ static bool sve_needed(void *opaque)
233
{
234
ARMCPU *cpu = opaque;
235
236
- return cpu_isar_feature(aa64_sve, cpu);
236
+ return cpu_isar_feature(aa64_sve, cpu) || cpu_isar_feature(aa64_sme, cpu);
237
}
238
239
/* The first two words of each Zreg is stored in VFP state. */