@samitouri / QOSamiQemu / commits / 170de38560

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. */