167730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0-only
267730e6cSSean Christopherson /*
367730e6cSSean Christopherson * set_id_regs - Test for setting ID register from usersapce.
467730e6cSSean Christopherson *
567730e6cSSean Christopherson * Copyright (c) 2023 Google LLC.
667730e6cSSean Christopherson *
767730e6cSSean Christopherson *
867730e6cSSean Christopherson * Test that KVM supports setting ID registers from userspace and handles the
967730e6cSSean Christopherson * feature set correctly.
1067730e6cSSean Christopherson */
1167730e6cSSean Christopherson
1267730e6cSSean Christopherson #include <stdint.h>
1367730e6cSSean Christopherson #include "kvm_util.h"
1467730e6cSSean Christopherson #include "processor.h"
1567730e6cSSean Christopherson #include "test_util.h"
1667730e6cSSean Christopherson #include <linux/bitfield.h>
1767730e6cSSean Christopherson
18*69018866SBen Horgan bool have_cap_arm_mte;
19*69018866SBen Horgan
2067730e6cSSean Christopherson enum ftr_type {
2167730e6cSSean Christopherson FTR_EXACT, /* Use a predefined safe value */
2267730e6cSSean Christopherson FTR_LOWER_SAFE, /* Smaller value is safe */
2367730e6cSSean Christopherson FTR_HIGHER_SAFE, /* Bigger value is safe */
2467730e6cSSean Christopherson FTR_HIGHER_OR_ZERO_SAFE, /* Bigger value is safe, but 0 is biggest */
2567730e6cSSean Christopherson FTR_END, /* Mark the last ftr bits */
2667730e6cSSean Christopherson };
2767730e6cSSean Christopherson
2867730e6cSSean Christopherson #define FTR_SIGNED true /* Value should be treated as signed */
2967730e6cSSean Christopherson #define FTR_UNSIGNED false /* Value should be treated as unsigned */
3067730e6cSSean Christopherson
3167730e6cSSean Christopherson struct reg_ftr_bits {
3267730e6cSSean Christopherson char *name;
3367730e6cSSean Christopherson bool sign;
3467730e6cSSean Christopherson enum ftr_type type;
3567730e6cSSean Christopherson uint8_t shift;
3667730e6cSSean Christopherson uint64_t mask;
3767730e6cSSean Christopherson /*
3867730e6cSSean Christopherson * For FTR_EXACT, safe_val is used as the exact safe value.
3967730e6cSSean Christopherson * For FTR_LOWER_SAFE, safe_val is used as the minimal safe value.
4067730e6cSSean Christopherson */
4167730e6cSSean Christopherson int64_t safe_val;
4267730e6cSSean Christopherson };
4367730e6cSSean Christopherson
4467730e6cSSean Christopherson struct test_feature_reg {
4567730e6cSSean Christopherson uint32_t reg;
4667730e6cSSean Christopherson const struct reg_ftr_bits *ftr_bits;
4767730e6cSSean Christopherson };
4867730e6cSSean Christopherson
4967730e6cSSean Christopherson #define __REG_FTR_BITS(NAME, SIGNED, TYPE, SHIFT, MASK, SAFE_VAL) \
5067730e6cSSean Christopherson { \
5167730e6cSSean Christopherson .name = #NAME, \
5267730e6cSSean Christopherson .sign = SIGNED, \
5367730e6cSSean Christopherson .type = TYPE, \
5467730e6cSSean Christopherson .shift = SHIFT, \
5567730e6cSSean Christopherson .mask = MASK, \
5667730e6cSSean Christopherson .safe_val = SAFE_VAL, \
5767730e6cSSean Christopherson }
5867730e6cSSean Christopherson
5967730e6cSSean Christopherson #define REG_FTR_BITS(type, reg, field, safe_val) \
6067730e6cSSean Christopherson __REG_FTR_BITS(reg##_##field, FTR_UNSIGNED, type, reg##_##field##_SHIFT, \
6167730e6cSSean Christopherson reg##_##field##_MASK, safe_val)
6267730e6cSSean Christopherson
6367730e6cSSean Christopherson #define S_REG_FTR_BITS(type, reg, field, safe_val) \
6467730e6cSSean Christopherson __REG_FTR_BITS(reg##_##field, FTR_SIGNED, type, reg##_##field##_SHIFT, \
6567730e6cSSean Christopherson reg##_##field##_MASK, safe_val)
6667730e6cSSean Christopherson
6767730e6cSSean Christopherson #define REG_FTR_END \
6867730e6cSSean Christopherson { \
6967730e6cSSean Christopherson .type = FTR_END, \
7067730e6cSSean Christopherson }
7167730e6cSSean Christopherson
7267730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64dfr0_el1[] = {
7367730e6cSSean Christopherson S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, DoubleLock, 0),
7467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, WRPs, 0),
7567730e6cSSean Christopherson S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, PMUVer, 0),
7667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64DFR0_EL1, DebugVer, ID_AA64DFR0_EL1_DebugVer_IMP),
7767730e6cSSean Christopherson REG_FTR_END,
7867730e6cSSean Christopherson };
7967730e6cSSean Christopherson
8067730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_dfr0_el1[] = {
8167730e6cSSean Christopherson S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, PerfMon, ID_DFR0_EL1_PerfMon_PMUv3),
8267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_DFR0_EL1, CopDbg, ID_DFR0_EL1_CopDbg_Armv8),
8367730e6cSSean Christopherson REG_FTR_END,
8467730e6cSSean Christopherson };
8567730e6cSSean Christopherson
8667730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64isar0_el1[] = {
8767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, RNDR, 0),
8867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, TLB, 0),
8967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, TS, 0),
9067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, FHM, 0),
9167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, DP, 0),
9267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, SM4, 0),
9367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, SM3, 0),
9467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, SHA3, 0),
9567730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, RDM, 0),
9667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, TME, 0),
9767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, ATOMIC, 0),
9867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, CRC32, 0),
9967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, SHA2, 0),
10067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, SHA1, 0),
10167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR0_EL1, AES, 0),
10267730e6cSSean Christopherson REG_FTR_END,
10367730e6cSSean Christopherson };
10467730e6cSSean Christopherson
10567730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64isar1_el1[] = {
10667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, LS64, 0),
10767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, XS, 0),
10867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, I8MM, 0),
10967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, DGH, 0),
11067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, BF16, 0),
11167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, SPECRES, 0),
11267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, SB, 0),
11367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, FRINTTS, 0),
11467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, LRCPC, 0),
11567730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, FCMA, 0),
11667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, JSCVT, 0),
11767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR1_EL1, DPB, 0),
11867730e6cSSean Christopherson REG_FTR_END,
11967730e6cSSean Christopherson };
12067730e6cSSean Christopherson
12167730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64isar2_el1[] = {
12267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR2_EL1, BC, 0),
12367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR2_EL1, RPRES, 0),
12467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR2_EL1, WFxT, 0),
12567730e6cSSean Christopherson REG_FTR_END,
12667730e6cSSean Christopherson };
12767730e6cSSean Christopherson
12867730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64pfr0_el1[] = {
12967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV3, 0),
13067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV2, 0),
13167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, DIT, 0),
13267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, SEL2, 0),
13367730e6cSSean Christopherson REG_FTR_BITS(FTR_EXACT, ID_AA64PFR0_EL1, GIC, 0),
134b60e285bSMarc Zyngier REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL3, 1),
135b60e285bSMarc Zyngier REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL2, 1),
136b60e285bSMarc Zyngier REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL1, 1),
137b60e285bSMarc Zyngier REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, EL0, 1),
13867730e6cSSean Christopherson REG_FTR_END,
13967730e6cSSean Christopherson };
14067730e6cSSean Christopherson
14167730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64pfr1_el1[] = {
14267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR1_EL1, CSV2_frac, 0),
14367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR1_EL1, SSBS, ID_AA64PFR1_EL1_SSBS_NI),
14467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR1_EL1, BT, 0),
14567730e6cSSean Christopherson REG_FTR_END,
14667730e6cSSean Christopherson };
14767730e6cSSean Christopherson
14867730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64mmfr0_el1[] = {
14967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, ECV, 0),
15067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, EXS, 0),
151edfd826bSSebastian Ott REG_FTR_BITS(FTR_EXACT, ID_AA64MMFR0_EL1, TGRAN4_2, 1),
152edfd826bSSebastian Ott REG_FTR_BITS(FTR_EXACT, ID_AA64MMFR0_EL1, TGRAN64_2, 1),
153edfd826bSSebastian Ott REG_FTR_BITS(FTR_EXACT, ID_AA64MMFR0_EL1, TGRAN16_2, 1),
15467730e6cSSean Christopherson S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, TGRAN4, 0),
15567730e6cSSean Christopherson S_REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, TGRAN64, 0),
15667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, TGRAN16, 0),
15767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, BIGENDEL0, 0),
15867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, SNSMEM, 0),
15967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, BIGEND, 0),
16067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR0_EL1, PARANGE, 0),
16167730e6cSSean Christopherson REG_FTR_END,
16267730e6cSSean Christopherson };
16367730e6cSSean Christopherson
16467730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64mmfr1_el1[] = {
16567730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, TIDCP1, 0),
16667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, AFP, 0),
16767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, ETS, 0),
16867730e6cSSean Christopherson REG_FTR_BITS(FTR_HIGHER_SAFE, ID_AA64MMFR1_EL1, SpecSEI, 0),
16967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, PAN, 0),
17067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, LO, 0),
17167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, HPDS, 0),
17267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, HAFDBS, 0),
17367730e6cSSean Christopherson REG_FTR_END,
17467730e6cSSean Christopherson };
17567730e6cSSean Christopherson
17667730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64mmfr2_el1[] = {
17767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, E0PD, 0),
17867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, BBM, 0),
17967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, TTL, 0),
18067730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, AT, 0),
18167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, ST, 0),
18267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, VARange, 0),
18367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, IESB, 0),
18467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, LSM, 0),
18567730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, UAO, 0),
18667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR2_EL1, CnP, 0),
18767730e6cSSean Christopherson REG_FTR_END,
18867730e6cSSean Christopherson };
18967730e6cSSean Christopherson
19067730e6cSSean Christopherson static const struct reg_ftr_bits ftr_id_aa64zfr0_el1[] = {
19167730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, F64MM, 0),
19267730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, F32MM, 0),
19367730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, I8MM, 0),
19467730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, SM4, 0),
19567730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, SHA3, 0),
19667730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, BF16, 0),
19767730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, BitPerm, 0),
19867730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, AES, 0),
19967730e6cSSean Christopherson REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ZFR0_EL1, SVEver, 0),
20067730e6cSSean Christopherson REG_FTR_END,
20167730e6cSSean Christopherson };
20267730e6cSSean Christopherson
20367730e6cSSean Christopherson #define TEST_REG(id, table) \
20467730e6cSSean Christopherson { \
20567730e6cSSean Christopherson .reg = id, \
20667730e6cSSean Christopherson .ftr_bits = &((table)[0]), \
20767730e6cSSean Christopherson }
20867730e6cSSean Christopherson
20967730e6cSSean Christopherson static struct test_feature_reg test_regs[] = {
21067730e6cSSean Christopherson TEST_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
21167730e6cSSean Christopherson TEST_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0_el1),
21267730e6cSSean Christopherson TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
21367730e6cSSean Christopherson TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
21467730e6cSSean Christopherson TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
21567730e6cSSean Christopherson TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
21667730e6cSSean Christopherson TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
21767730e6cSSean Christopherson TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
21867730e6cSSean Christopherson TEST_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
21967730e6cSSean Christopherson TEST_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
22067730e6cSSean Christopherson TEST_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
22167730e6cSSean Christopherson };
22267730e6cSSean Christopherson
22367730e6cSSean Christopherson #define GUEST_REG_SYNC(id) GUEST_SYNC_ARGS(0, id, read_sysreg_s(id), 0, 0);
22467730e6cSSean Christopherson
guest_code(void)22567730e6cSSean Christopherson static void guest_code(void)
22667730e6cSSean Christopherson {
22767730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64DFR0_EL1);
22867730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_DFR0_EL1);
22967730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64ISAR0_EL1);
23067730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64ISAR1_EL1);
23167730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64ISAR2_EL1);
23267730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64PFR0_EL1);
23367730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64MMFR0_EL1);
23467730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1);
23567730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1);
23667730e6cSSean Christopherson GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1);
23767730e6cSSean Christopherson GUEST_REG_SYNC(SYS_CTR_EL0);
238a88c7c22SSebastian Ott GUEST_REG_SYNC(SYS_MIDR_EL1);
239a88c7c22SSebastian Ott GUEST_REG_SYNC(SYS_REVIDR_EL1);
240a88c7c22SSebastian Ott GUEST_REG_SYNC(SYS_AIDR_EL1);
24167730e6cSSean Christopherson
24267730e6cSSean Christopherson GUEST_DONE();
24367730e6cSSean Christopherson }
24467730e6cSSean Christopherson
24567730e6cSSean Christopherson /* Return a safe value to a given ftr_bits an ftr value */
get_safe_value(const struct reg_ftr_bits * ftr_bits,uint64_t ftr)24667730e6cSSean Christopherson uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
24767730e6cSSean Christopherson {
24867730e6cSSean Christopherson uint64_t ftr_max = GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0);
24967730e6cSSean Christopherson
25067730e6cSSean Christopherson if (ftr_bits->sign == FTR_UNSIGNED) {
25167730e6cSSean Christopherson switch (ftr_bits->type) {
25267730e6cSSean Christopherson case FTR_EXACT:
25367730e6cSSean Christopherson ftr = ftr_bits->safe_val;
25467730e6cSSean Christopherson break;
25567730e6cSSean Christopherson case FTR_LOWER_SAFE:
25667730e6cSSean Christopherson if (ftr > ftr_bits->safe_val)
25767730e6cSSean Christopherson ftr--;
25867730e6cSSean Christopherson break;
25967730e6cSSean Christopherson case FTR_HIGHER_SAFE:
26067730e6cSSean Christopherson if (ftr < ftr_max)
26167730e6cSSean Christopherson ftr++;
26267730e6cSSean Christopherson break;
26367730e6cSSean Christopherson case FTR_HIGHER_OR_ZERO_SAFE:
26467730e6cSSean Christopherson if (ftr == ftr_max)
26567730e6cSSean Christopherson ftr = 0;
26667730e6cSSean Christopherson else if (ftr != 0)
26767730e6cSSean Christopherson ftr++;
26867730e6cSSean Christopherson break;
26967730e6cSSean Christopherson default:
27067730e6cSSean Christopherson break;
27167730e6cSSean Christopherson }
27267730e6cSSean Christopherson } else if (ftr != ftr_max) {
27367730e6cSSean Christopherson switch (ftr_bits->type) {
27467730e6cSSean Christopherson case FTR_EXACT:
27567730e6cSSean Christopherson ftr = ftr_bits->safe_val;
27667730e6cSSean Christopherson break;
27767730e6cSSean Christopherson case FTR_LOWER_SAFE:
27867730e6cSSean Christopherson if (ftr > ftr_bits->safe_val)
27967730e6cSSean Christopherson ftr--;
28067730e6cSSean Christopherson break;
28167730e6cSSean Christopherson case FTR_HIGHER_SAFE:
28267730e6cSSean Christopherson if (ftr < ftr_max - 1)
28367730e6cSSean Christopherson ftr++;
28467730e6cSSean Christopherson break;
28567730e6cSSean Christopherson case FTR_HIGHER_OR_ZERO_SAFE:
28667730e6cSSean Christopherson if (ftr != 0 && ftr != ftr_max - 1)
28767730e6cSSean Christopherson ftr++;
28867730e6cSSean Christopherson break;
28967730e6cSSean Christopherson default:
29067730e6cSSean Christopherson break;
29167730e6cSSean Christopherson }
29267730e6cSSean Christopherson }
29367730e6cSSean Christopherson
29467730e6cSSean Christopherson return ftr;
29567730e6cSSean Christopherson }
29667730e6cSSean Christopherson
29767730e6cSSean Christopherson /* Return an invalid value to a given ftr_bits an ftr value */
get_invalid_value(const struct reg_ftr_bits * ftr_bits,uint64_t ftr)29867730e6cSSean Christopherson uint64_t get_invalid_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
29967730e6cSSean Christopherson {
30067730e6cSSean Christopherson uint64_t ftr_max = GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0);
30167730e6cSSean Christopherson
30267730e6cSSean Christopherson if (ftr_bits->sign == FTR_UNSIGNED) {
30367730e6cSSean Christopherson switch (ftr_bits->type) {
30467730e6cSSean Christopherson case FTR_EXACT:
30567730e6cSSean Christopherson ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1);
30667730e6cSSean Christopherson break;
30767730e6cSSean Christopherson case FTR_LOWER_SAFE:
30867730e6cSSean Christopherson ftr++;
30967730e6cSSean Christopherson break;
31067730e6cSSean Christopherson case FTR_HIGHER_SAFE:
31167730e6cSSean Christopherson ftr--;
31267730e6cSSean Christopherson break;
31367730e6cSSean Christopherson case FTR_HIGHER_OR_ZERO_SAFE:
31467730e6cSSean Christopherson if (ftr == 0)
31567730e6cSSean Christopherson ftr = ftr_max;
31667730e6cSSean Christopherson else
31767730e6cSSean Christopherson ftr--;
31867730e6cSSean Christopherson break;
31967730e6cSSean Christopherson default:
32067730e6cSSean Christopherson break;
32167730e6cSSean Christopherson }
32267730e6cSSean Christopherson } else if (ftr != ftr_max) {
32367730e6cSSean Christopherson switch (ftr_bits->type) {
32467730e6cSSean Christopherson case FTR_EXACT:
32567730e6cSSean Christopherson ftr = max((uint64_t)ftr_bits->safe_val + 1, ftr + 1);
32667730e6cSSean Christopherson break;
32767730e6cSSean Christopherson case FTR_LOWER_SAFE:
32867730e6cSSean Christopherson ftr++;
32967730e6cSSean Christopherson break;
33067730e6cSSean Christopherson case FTR_HIGHER_SAFE:
33167730e6cSSean Christopherson ftr--;
33267730e6cSSean Christopherson break;
33367730e6cSSean Christopherson case FTR_HIGHER_OR_ZERO_SAFE:
33467730e6cSSean Christopherson if (ftr == 0)
33567730e6cSSean Christopherson ftr = ftr_max - 1;
33667730e6cSSean Christopherson else
33767730e6cSSean Christopherson ftr--;
33867730e6cSSean Christopherson break;
33967730e6cSSean Christopherson default:
34067730e6cSSean Christopherson break;
34167730e6cSSean Christopherson }
34267730e6cSSean Christopherson } else {
34367730e6cSSean Christopherson ftr = 0;
34467730e6cSSean Christopherson }
34567730e6cSSean Christopherson
34667730e6cSSean Christopherson return ftr;
34767730e6cSSean Christopherson }
34867730e6cSSean Christopherson
test_reg_set_success(struct kvm_vcpu * vcpu,uint64_t reg,const struct reg_ftr_bits * ftr_bits)34967730e6cSSean Christopherson static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg,
35067730e6cSSean Christopherson const struct reg_ftr_bits *ftr_bits)
35167730e6cSSean Christopherson {
35267730e6cSSean Christopherson uint8_t shift = ftr_bits->shift;
35367730e6cSSean Christopherson uint64_t mask = ftr_bits->mask;
35467730e6cSSean Christopherson uint64_t val, new_val, ftr;
35567730e6cSSean Christopherson
35667730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg);
35767730e6cSSean Christopherson ftr = (val & mask) >> shift;
35867730e6cSSean Christopherson
35967730e6cSSean Christopherson ftr = get_safe_value(ftr_bits, ftr);
36067730e6cSSean Christopherson
36167730e6cSSean Christopherson ftr <<= shift;
36267730e6cSSean Christopherson val &= ~mask;
36367730e6cSSean Christopherson val |= ftr;
36467730e6cSSean Christopherson
36567730e6cSSean Christopherson vcpu_set_reg(vcpu, reg, val);
36667730e6cSSean Christopherson new_val = vcpu_get_reg(vcpu, reg);
36767730e6cSSean Christopherson TEST_ASSERT_EQ(new_val, val);
36867730e6cSSean Christopherson
36967730e6cSSean Christopherson return new_val;
37067730e6cSSean Christopherson }
37167730e6cSSean Christopherson
test_reg_set_fail(struct kvm_vcpu * vcpu,uint64_t reg,const struct reg_ftr_bits * ftr_bits)37267730e6cSSean Christopherson static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
37367730e6cSSean Christopherson const struct reg_ftr_bits *ftr_bits)
37467730e6cSSean Christopherson {
37567730e6cSSean Christopherson uint8_t shift = ftr_bits->shift;
37667730e6cSSean Christopherson uint64_t mask = ftr_bits->mask;
37767730e6cSSean Christopherson uint64_t val, old_val, ftr;
37867730e6cSSean Christopherson int r;
37967730e6cSSean Christopherson
38067730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg);
38167730e6cSSean Christopherson ftr = (val & mask) >> shift;
38267730e6cSSean Christopherson
38367730e6cSSean Christopherson ftr = get_invalid_value(ftr_bits, ftr);
38467730e6cSSean Christopherson
38567730e6cSSean Christopherson old_val = val;
38667730e6cSSean Christopherson ftr <<= shift;
38767730e6cSSean Christopherson val &= ~mask;
38867730e6cSSean Christopherson val |= ftr;
38967730e6cSSean Christopherson
39067730e6cSSean Christopherson r = __vcpu_set_reg(vcpu, reg, val);
39167730e6cSSean Christopherson TEST_ASSERT(r < 0 && errno == EINVAL,
39267730e6cSSean Christopherson "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
39367730e6cSSean Christopherson
39467730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg);
39567730e6cSSean Christopherson TEST_ASSERT_EQ(val, old_val);
39667730e6cSSean Christopherson }
39767730e6cSSean Christopherson
39867730e6cSSean Christopherson static uint64_t test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE];
39967730e6cSSean Christopherson
40067730e6cSSean Christopherson #define encoding_to_range_idx(encoding) \
40167730e6cSSean Christopherson KVM_ARM_FEATURE_ID_RANGE_IDX(sys_reg_Op0(encoding), sys_reg_Op1(encoding), \
40267730e6cSSean Christopherson sys_reg_CRn(encoding), sys_reg_CRm(encoding), \
40367730e6cSSean Christopherson sys_reg_Op2(encoding))
40467730e6cSSean Christopherson
40567730e6cSSean Christopherson
test_vm_ftr_id_regs(struct kvm_vcpu * vcpu,bool aarch64_only)40667730e6cSSean Christopherson static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
40767730e6cSSean Christopherson {
40867730e6cSSean Christopherson uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE];
40967730e6cSSean Christopherson struct reg_mask_range range = {
41067730e6cSSean Christopherson .addr = (__u64)masks,
41167730e6cSSean Christopherson };
41267730e6cSSean Christopherson int ret;
41367730e6cSSean Christopherson
41467730e6cSSean Christopherson /* KVM should return error when reserved field is not zero */
41567730e6cSSean Christopherson range.reserved[0] = 1;
41667730e6cSSean Christopherson ret = __vm_ioctl(vcpu->vm, KVM_ARM_GET_REG_WRITABLE_MASKS, &range);
41767730e6cSSean Christopherson TEST_ASSERT(ret, "KVM doesn't check invalid parameters.");
41867730e6cSSean Christopherson
41967730e6cSSean Christopherson /* Get writable masks for feature ID registers */
42067730e6cSSean Christopherson memset(range.reserved, 0, sizeof(range.reserved));
42167730e6cSSean Christopherson vm_ioctl(vcpu->vm, KVM_ARM_GET_REG_WRITABLE_MASKS, &range);
42267730e6cSSean Christopherson
42367730e6cSSean Christopherson for (int i = 0; i < ARRAY_SIZE(test_regs); i++) {
42467730e6cSSean Christopherson const struct reg_ftr_bits *ftr_bits = test_regs[i].ftr_bits;
42567730e6cSSean Christopherson uint32_t reg_id = test_regs[i].reg;
42667730e6cSSean Christopherson uint64_t reg = KVM_ARM64_SYS_REG(reg_id);
42767730e6cSSean Christopherson int idx;
42867730e6cSSean Christopherson
42967730e6cSSean Christopherson /* Get the index to masks array for the idreg */
43067730e6cSSean Christopherson idx = encoding_to_range_idx(reg_id);
43167730e6cSSean Christopherson
43267730e6cSSean Christopherson for (int j = 0; ftr_bits[j].type != FTR_END; j++) {
43367730e6cSSean Christopherson /* Skip aarch32 reg on aarch64 only system, since they are RAZ/WI. */
43467730e6cSSean Christopherson if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
43567730e6cSSean Christopherson ksft_test_result_skip("%s on AARCH64 only system\n",
43667730e6cSSean Christopherson ftr_bits[j].name);
43767730e6cSSean Christopherson continue;
43867730e6cSSean Christopherson }
43967730e6cSSean Christopherson
44067730e6cSSean Christopherson /* Make sure the feature field is writable */
44167730e6cSSean Christopherson TEST_ASSERT_EQ(masks[idx] & ftr_bits[j].mask, ftr_bits[j].mask);
44267730e6cSSean Christopherson
44367730e6cSSean Christopherson test_reg_set_fail(vcpu, reg, &ftr_bits[j]);
44467730e6cSSean Christopherson
44567730e6cSSean Christopherson test_reg_vals[idx] = test_reg_set_success(vcpu, reg,
44667730e6cSSean Christopherson &ftr_bits[j]);
44767730e6cSSean Christopherson
44867730e6cSSean Christopherson ksft_test_result_pass("%s\n", ftr_bits[j].name);
44967730e6cSSean Christopherson }
45067730e6cSSean Christopherson }
45167730e6cSSean Christopherson }
45267730e6cSSean Christopherson
45367730e6cSSean Christopherson #define MPAM_IDREG_TEST 6
test_user_set_mpam_reg(struct kvm_vcpu * vcpu)45467730e6cSSean Christopherson static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu)
45567730e6cSSean Christopherson {
45667730e6cSSean Christopherson uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE];
45767730e6cSSean Christopherson struct reg_mask_range range = {
45867730e6cSSean Christopherson .addr = (__u64)masks,
45967730e6cSSean Christopherson };
46067730e6cSSean Christopherson uint64_t val;
46167730e6cSSean Christopherson int idx, err;
46267730e6cSSean Christopherson
46367730e6cSSean Christopherson /*
46467730e6cSSean Christopherson * If ID_AA64PFR0.MPAM is _not_ officially modifiable and is zero,
46567730e6cSSean Christopherson * check that if it can be set to 1, (i.e. it is supported by the
46667730e6cSSean Christopherson * hardware), that it can't be set to other values.
46767730e6cSSean Christopherson */
46867730e6cSSean Christopherson
46967730e6cSSean Christopherson /* Get writable masks for feature ID registers */
47067730e6cSSean Christopherson memset(range.reserved, 0, sizeof(range.reserved));
47167730e6cSSean Christopherson vm_ioctl(vcpu->vm, KVM_ARM_GET_REG_WRITABLE_MASKS, &range);
47267730e6cSSean Christopherson
47367730e6cSSean Christopherson /* Writeable? Nothing to test! */
47467730e6cSSean Christopherson idx = encoding_to_range_idx(SYS_ID_AA64PFR0_EL1);
47567730e6cSSean Christopherson if ((masks[idx] & ID_AA64PFR0_EL1_MPAM_MASK) == ID_AA64PFR0_EL1_MPAM_MASK) {
47667730e6cSSean Christopherson ksft_test_result_skip("ID_AA64PFR0_EL1.MPAM is officially writable, nothing to test\n");
47767730e6cSSean Christopherson return;
47867730e6cSSean Christopherson }
47967730e6cSSean Christopherson
48067730e6cSSean Christopherson /* Get the id register value */
48167730e6cSSean Christopherson val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));
48267730e6cSSean Christopherson
48367730e6cSSean Christopherson /* Try to set MPAM=0. This should always be possible. */
48467730e6cSSean Christopherson val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
48567730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR0_EL1_MPAM_MASK, 0);
48667730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), val);
48767730e6cSSean Christopherson if (err)
48867730e6cSSean Christopherson ksft_test_result_fail("ID_AA64PFR0_EL1.MPAM=0 was not accepted\n");
48967730e6cSSean Christopherson else
49067730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR0_EL1.MPAM=0 worked\n");
49167730e6cSSean Christopherson
49267730e6cSSean Christopherson /* Try to set MPAM=1 */
49367730e6cSSean Christopherson val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
49467730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR0_EL1_MPAM_MASK, 1);
49567730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), val);
49667730e6cSSean Christopherson if (err)
49767730e6cSSean Christopherson ksft_test_result_skip("ID_AA64PFR0_EL1.MPAM is not writable, nothing to test\n");
49867730e6cSSean Christopherson else
49967730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR0_EL1.MPAM=1 was writable\n");
50067730e6cSSean Christopherson
50167730e6cSSean Christopherson /* Try to set MPAM=2 */
50267730e6cSSean Christopherson val &= ~ID_AA64PFR0_EL1_MPAM_MASK;
50367730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR0_EL1_MPAM_MASK, 2);
50467730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), val);
50567730e6cSSean Christopherson if (err)
50667730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR0_EL1.MPAM not arbitrarily modifiable\n");
50767730e6cSSean Christopherson else
50867730e6cSSean Christopherson ksft_test_result_fail("ID_AA64PFR0_EL1.MPAM value should not be ignored\n");
50967730e6cSSean Christopherson
51067730e6cSSean Christopherson /* And again for ID_AA64PFR1_EL1.MPAM_frac */
51167730e6cSSean Christopherson idx = encoding_to_range_idx(SYS_ID_AA64PFR1_EL1);
51267730e6cSSean Christopherson if ((masks[idx] & ID_AA64PFR1_EL1_MPAM_frac_MASK) == ID_AA64PFR1_EL1_MPAM_frac_MASK) {
51367730e6cSSean Christopherson ksft_test_result_skip("ID_AA64PFR1_EL1.MPAM_frac is officially writable, nothing to test\n");
51467730e6cSSean Christopherson return;
51567730e6cSSean Christopherson }
51667730e6cSSean Christopherson
51767730e6cSSean Christopherson /* Get the id register value */
51867730e6cSSean Christopherson val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
51967730e6cSSean Christopherson
52067730e6cSSean Christopherson /* Try to set MPAM_frac=0. This should always be possible. */
52167730e6cSSean Christopherson val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK;
52267730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR1_EL1_MPAM_frac_MASK, 0);
52367730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1), val);
52467730e6cSSean Christopherson if (err)
52567730e6cSSean Christopherson ksft_test_result_fail("ID_AA64PFR0_EL1.MPAM_frac=0 was not accepted\n");
52667730e6cSSean Christopherson else
52767730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR0_EL1.MPAM_frac=0 worked\n");
52867730e6cSSean Christopherson
52967730e6cSSean Christopherson /* Try to set MPAM_frac=1 */
53067730e6cSSean Christopherson val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK;
53167730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR1_EL1_MPAM_frac_MASK, 1);
53267730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1), val);
53367730e6cSSean Christopherson if (err)
53467730e6cSSean Christopherson ksft_test_result_skip("ID_AA64PFR1_EL1.MPAM_frac is not writable, nothing to test\n");
53567730e6cSSean Christopherson else
53667730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR0_EL1.MPAM_frac=1 was writable\n");
53767730e6cSSean Christopherson
53867730e6cSSean Christopherson /* Try to set MPAM_frac=2 */
53967730e6cSSean Christopherson val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK;
54067730e6cSSean Christopherson val |= FIELD_PREP(ID_AA64PFR1_EL1_MPAM_frac_MASK, 2);
54167730e6cSSean Christopherson err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1), val);
54267730e6cSSean Christopherson if (err)
54367730e6cSSean Christopherson ksft_test_result_pass("ID_AA64PFR1_EL1.MPAM_frac not arbitrarily modifiable\n");
54467730e6cSSean Christopherson else
54567730e6cSSean Christopherson ksft_test_result_fail("ID_AA64PFR1_EL1.MPAM_frac value should not be ignored\n");
54667730e6cSSean Christopherson }
54767730e6cSSean Christopherson
548*69018866SBen Horgan #define MTE_IDREG_TEST 1
test_user_set_mte_reg(struct kvm_vcpu * vcpu)549*69018866SBen Horgan static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
550*69018866SBen Horgan {
551*69018866SBen Horgan uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE];
552*69018866SBen Horgan struct reg_mask_range range = {
553*69018866SBen Horgan .addr = (__u64)masks,
554*69018866SBen Horgan };
555*69018866SBen Horgan uint64_t val;
556*69018866SBen Horgan uint64_t mte;
557*69018866SBen Horgan uint64_t mte_frac;
558*69018866SBen Horgan int idx, err;
559*69018866SBen Horgan
560*69018866SBen Horgan if (!have_cap_arm_mte) {
561*69018866SBen Horgan ksft_test_result_skip("MTE capability not supported, nothing to test\n");
562*69018866SBen Horgan return;
563*69018866SBen Horgan }
564*69018866SBen Horgan
565*69018866SBen Horgan /* Get writable masks for feature ID registers */
566*69018866SBen Horgan memset(range.reserved, 0, sizeof(range.reserved));
567*69018866SBen Horgan vm_ioctl(vcpu->vm, KVM_ARM_GET_REG_WRITABLE_MASKS, &range);
568*69018866SBen Horgan
569*69018866SBen Horgan idx = encoding_to_range_idx(SYS_ID_AA64PFR1_EL1);
570*69018866SBen Horgan if ((masks[idx] & ID_AA64PFR1_EL1_MTE_frac_MASK) == ID_AA64PFR1_EL1_MTE_frac_MASK) {
571*69018866SBen Horgan ksft_test_result_skip("ID_AA64PFR1_EL1.MTE_frac is officially writable, nothing to test\n");
572*69018866SBen Horgan return;
573*69018866SBen Horgan }
574*69018866SBen Horgan
575*69018866SBen Horgan /*
576*69018866SBen Horgan * When MTE is supported but MTE_ASYMM is not (ID_AA64PFR1_EL1.MTE == 2)
577*69018866SBen Horgan * ID_AA64PFR1_EL1.MTE_frac == 0xF indicates MTE_ASYNC is unsupported
578*69018866SBen Horgan * and MTE_frac == 0 indicates it is supported.
579*69018866SBen Horgan *
580*69018866SBen Horgan * As MTE_frac was previously unconditionally read as 0, check
581*69018866SBen Horgan * that the set to 0 succeeds but does not change MTE_frac
582*69018866SBen Horgan * from unsupported (0xF) to supported (0).
583*69018866SBen Horgan *
584*69018866SBen Horgan */
585*69018866SBen Horgan val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
586*69018866SBen Horgan
587*69018866SBen Horgan mte = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE), val);
588*69018866SBen Horgan mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val);
589*69018866SBen Horgan if (mte != ID_AA64PFR1_EL1_MTE_MTE2 ||
590*69018866SBen Horgan mte_frac != ID_AA64PFR1_EL1_MTE_frac_NI) {
591*69018866SBen Horgan ksft_test_result_skip("MTE_ASYNC or MTE_ASYMM are supported, nothing to test\n");
592*69018866SBen Horgan return;
593*69018866SBen Horgan }
594*69018866SBen Horgan
595*69018866SBen Horgan /* Try to set MTE_frac=0. */
596*69018866SBen Horgan val &= ~ID_AA64PFR1_EL1_MTE_frac_MASK;
597*69018866SBen Horgan val |= FIELD_PREP(ID_AA64PFR1_EL1_MTE_frac_MASK, 0);
598*69018866SBen Horgan err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1), val);
599*69018866SBen Horgan if (err) {
600*69018866SBen Horgan ksft_test_result_fail("ID_AA64PFR1_EL1.MTE_frac=0 was not accepted\n");
601*69018866SBen Horgan return;
602*69018866SBen Horgan }
603*69018866SBen Horgan
604*69018866SBen Horgan val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
605*69018866SBen Horgan mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val);
606*69018866SBen Horgan if (mte_frac == ID_AA64PFR1_EL1_MTE_frac_NI)
607*69018866SBen Horgan ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac=0 accepted and still 0xF\n");
608*69018866SBen Horgan else
609*69018866SBen Horgan ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n");
610*69018866SBen Horgan }
611*69018866SBen Horgan
test_guest_reg_read(struct kvm_vcpu * vcpu)61267730e6cSSean Christopherson static void test_guest_reg_read(struct kvm_vcpu *vcpu)
61367730e6cSSean Christopherson {
61467730e6cSSean Christopherson bool done = false;
61567730e6cSSean Christopherson struct ucall uc;
61667730e6cSSean Christopherson
61767730e6cSSean Christopherson while (!done) {
61867730e6cSSean Christopherson vcpu_run(vcpu);
61967730e6cSSean Christopherson
62067730e6cSSean Christopherson switch (get_ucall(vcpu, &uc)) {
62167730e6cSSean Christopherson case UCALL_ABORT:
62267730e6cSSean Christopherson REPORT_GUEST_ASSERT(uc);
62367730e6cSSean Christopherson break;
62467730e6cSSean Christopherson case UCALL_SYNC:
62567730e6cSSean Christopherson /* Make sure the written values are seen by guest */
62667730e6cSSean Christopherson TEST_ASSERT_EQ(test_reg_vals[encoding_to_range_idx(uc.args[2])],
62767730e6cSSean Christopherson uc.args[3]);
62867730e6cSSean Christopherson break;
62967730e6cSSean Christopherson case UCALL_DONE:
63067730e6cSSean Christopherson done = true;
63167730e6cSSean Christopherson break;
63267730e6cSSean Christopherson default:
63367730e6cSSean Christopherson TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
63467730e6cSSean Christopherson }
63567730e6cSSean Christopherson }
63667730e6cSSean Christopherson }
63767730e6cSSean Christopherson
63867730e6cSSean Christopherson /* Politely lifted from arch/arm64/include/asm/cache.h */
63967730e6cSSean Christopherson /* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
64067730e6cSSean Christopherson #define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1))
64167730e6cSSean Christopherson #define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level))
64267730e6cSSean Christopherson #define CLIDR_CTYPE(clidr, level) \
64367730e6cSSean Christopherson (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
64467730e6cSSean Christopherson
test_clidr(struct kvm_vcpu * vcpu)64567730e6cSSean Christopherson static void test_clidr(struct kvm_vcpu *vcpu)
64667730e6cSSean Christopherson {
64767730e6cSSean Christopherson uint64_t clidr;
64867730e6cSSean Christopherson int level;
64967730e6cSSean Christopherson
65067730e6cSSean Christopherson clidr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CLIDR_EL1));
65167730e6cSSean Christopherson
65267730e6cSSean Christopherson /* find the first empty level in the cache hierarchy */
65367730e6cSSean Christopherson for (level = 1; level < 7; level++) {
65467730e6cSSean Christopherson if (!CLIDR_CTYPE(clidr, level))
65567730e6cSSean Christopherson break;
65667730e6cSSean Christopherson }
65767730e6cSSean Christopherson
65867730e6cSSean Christopherson /*
65967730e6cSSean Christopherson * If you have a mind-boggling 7 levels of cache, congratulations, you
66067730e6cSSean Christopherson * get to fix this.
66167730e6cSSean Christopherson */
66267730e6cSSean Christopherson TEST_ASSERT(level <= 7, "can't find an empty level in cache hierarchy");
66367730e6cSSean Christopherson
66467730e6cSSean Christopherson /* stick in a unified cache level */
66567730e6cSSean Christopherson clidr |= BIT(2) << CLIDR_CTYPE_SHIFT(level);
66667730e6cSSean Christopherson
66767730e6cSSean Christopherson vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CLIDR_EL1), clidr);
66867730e6cSSean Christopherson test_reg_vals[encoding_to_range_idx(SYS_CLIDR_EL1)] = clidr;
66967730e6cSSean Christopherson }
67067730e6cSSean Christopherson
test_ctr(struct kvm_vcpu * vcpu)67167730e6cSSean Christopherson static void test_ctr(struct kvm_vcpu *vcpu)
67267730e6cSSean Christopherson {
67367730e6cSSean Christopherson u64 ctr;
67467730e6cSSean Christopherson
67567730e6cSSean Christopherson ctr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CTR_EL0));
67667730e6cSSean Christopherson ctr &= ~CTR_EL0_DIC_MASK;
67767730e6cSSean Christopherson if (ctr & CTR_EL0_IminLine_MASK)
67867730e6cSSean Christopherson ctr--;
67967730e6cSSean Christopherson
68067730e6cSSean Christopherson vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CTR_EL0), ctr);
68167730e6cSSean Christopherson test_reg_vals[encoding_to_range_idx(SYS_CTR_EL0)] = ctr;
68267730e6cSSean Christopherson }
68367730e6cSSean Christopherson
test_id_reg(struct kvm_vcpu * vcpu,u32 id)684a88c7c22SSebastian Ott static void test_id_reg(struct kvm_vcpu *vcpu, u32 id)
68567730e6cSSean Christopherson {
68667730e6cSSean Christopherson u64 val;
68767730e6cSSean Christopherson
688a88c7c22SSebastian Ott val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(id));
689a88c7c22SSebastian Ott val++;
690a88c7c22SSebastian Ott vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(id), val);
691a88c7c22SSebastian Ott test_reg_vals[encoding_to_range_idx(id)] = val;
692a88c7c22SSebastian Ott }
693a88c7c22SSebastian Ott
test_vcpu_ftr_id_regs(struct kvm_vcpu * vcpu)694a88c7c22SSebastian Ott static void test_vcpu_ftr_id_regs(struct kvm_vcpu *vcpu)
695a88c7c22SSebastian Ott {
69667730e6cSSean Christopherson test_clidr(vcpu);
69767730e6cSSean Christopherson test_ctr(vcpu);
69867730e6cSSean Christopherson
699a88c7c22SSebastian Ott test_id_reg(vcpu, SYS_MPIDR_EL1);
700a88c7c22SSebastian Ott ksft_test_result_pass("%s\n", __func__);
701a88c7c22SSebastian Ott }
70267730e6cSSean Christopherson
test_vcpu_non_ftr_id_regs(struct kvm_vcpu * vcpu)703a88c7c22SSebastian Ott static void test_vcpu_non_ftr_id_regs(struct kvm_vcpu *vcpu)
704a88c7c22SSebastian Ott {
705a88c7c22SSebastian Ott test_id_reg(vcpu, SYS_MIDR_EL1);
706a88c7c22SSebastian Ott test_id_reg(vcpu, SYS_REVIDR_EL1);
707a88c7c22SSebastian Ott test_id_reg(vcpu, SYS_AIDR_EL1);
708a88c7c22SSebastian Ott
70967730e6cSSean Christopherson ksft_test_result_pass("%s\n", __func__);
71067730e6cSSean Christopherson }
71167730e6cSSean Christopherson
test_assert_id_reg_unchanged(struct kvm_vcpu * vcpu,uint32_t encoding)71267730e6cSSean Christopherson static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding)
71367730e6cSSean Christopherson {
71467730e6cSSean Christopherson size_t idx = encoding_to_range_idx(encoding);
71567730e6cSSean Christopherson uint64_t observed;
71667730e6cSSean Christopherson
71767730e6cSSean Christopherson observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
71867730e6cSSean Christopherson TEST_ASSERT_EQ(test_reg_vals[idx], observed);
71967730e6cSSean Christopherson }
72067730e6cSSean Christopherson
test_reset_preserves_id_regs(struct kvm_vcpu * vcpu)72167730e6cSSean Christopherson static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
72267730e6cSSean Christopherson {
72367730e6cSSean Christopherson /*
72467730e6cSSean Christopherson * Calls KVM_ARM_VCPU_INIT behind the scenes, which will do an
72567730e6cSSean Christopherson * architectural reset of the vCPU.
72667730e6cSSean Christopherson */
72767730e6cSSean Christopherson aarch64_vcpu_setup(vcpu, NULL);
72867730e6cSSean Christopherson
72967730e6cSSean Christopherson for (int i = 0; i < ARRAY_SIZE(test_regs); i++)
73067730e6cSSean Christopherson test_assert_id_reg_unchanged(vcpu, test_regs[i].reg);
73167730e6cSSean Christopherson
73267730e6cSSean Christopherson test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1);
73367730e6cSSean Christopherson test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1);
73467730e6cSSean Christopherson test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0);
735a88c7c22SSebastian Ott test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
736a88c7c22SSebastian Ott test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
737a88c7c22SSebastian Ott test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
73867730e6cSSean Christopherson
73967730e6cSSean Christopherson ksft_test_result_pass("%s\n", __func__);
74067730e6cSSean Christopherson }
74167730e6cSSean Christopherson
kvm_arch_vm_post_create(struct kvm_vm * vm)742*69018866SBen Horgan void kvm_arch_vm_post_create(struct kvm_vm *vm)
743*69018866SBen Horgan {
744*69018866SBen Horgan if (vm_check_cap(vm, KVM_CAP_ARM_MTE)) {
745*69018866SBen Horgan vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0);
746*69018866SBen Horgan have_cap_arm_mte = true;
747*69018866SBen Horgan }
748*69018866SBen Horgan }
749*69018866SBen Horgan
main(void)75067730e6cSSean Christopherson int main(void)
75167730e6cSSean Christopherson {
75267730e6cSSean Christopherson struct kvm_vcpu *vcpu;
75367730e6cSSean Christopherson struct kvm_vm *vm;
75467730e6cSSean Christopherson bool aarch64_only;
75567730e6cSSean Christopherson uint64_t val, el0;
75667730e6cSSean Christopherson int test_cnt;
75767730e6cSSean Christopherson
75867730e6cSSean Christopherson TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES));
759a88c7c22SSebastian Ott TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_WRITABLE_IMP_ID_REGS));
76067730e6cSSean Christopherson
761a88c7c22SSebastian Ott vm = vm_create(1);
762a88c7c22SSebastian Ott vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0);
763a88c7c22SSebastian Ott vcpu = vm_vcpu_add(vm, 0, guest_code);
76467730e6cSSean Christopherson
76567730e6cSSean Christopherson /* Check for AARCH64 only system */
76667730e6cSSean Christopherson val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));
76767730e6cSSean Christopherson el0 = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0), val);
768e2ee2e9bSLinus Torvalds aarch64_only = (el0 == ID_AA64PFR0_EL1_EL0_IMP);
76967730e6cSSean Christopherson
77067730e6cSSean Christopherson ksft_print_header();
77167730e6cSSean Christopherson
77267730e6cSSean Christopherson test_cnt = ARRAY_SIZE(ftr_id_aa64dfr0_el1) + ARRAY_SIZE(ftr_id_dfr0_el1) +
77367730e6cSSean Christopherson ARRAY_SIZE(ftr_id_aa64isar0_el1) + ARRAY_SIZE(ftr_id_aa64isar1_el1) +
77467730e6cSSean Christopherson ARRAY_SIZE(ftr_id_aa64isar2_el1) + ARRAY_SIZE(ftr_id_aa64pfr0_el1) +
77567730e6cSSean Christopherson ARRAY_SIZE(ftr_id_aa64pfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr0_el1) +
77667730e6cSSean Christopherson ARRAY_SIZE(ftr_id_aa64mmfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr2_el1) +
777a88c7c22SSebastian Ott ARRAY_SIZE(ftr_id_aa64zfr0_el1) - ARRAY_SIZE(test_regs) + 3 +
778*69018866SBen Horgan MPAM_IDREG_TEST + MTE_IDREG_TEST;
77967730e6cSSean Christopherson
78067730e6cSSean Christopherson ksft_set_plan(test_cnt);
78167730e6cSSean Christopherson
78267730e6cSSean Christopherson test_vm_ftr_id_regs(vcpu, aarch64_only);
78367730e6cSSean Christopherson test_vcpu_ftr_id_regs(vcpu);
784a88c7c22SSebastian Ott test_vcpu_non_ftr_id_regs(vcpu);
78567730e6cSSean Christopherson test_user_set_mpam_reg(vcpu);
786*69018866SBen Horgan test_user_set_mte_reg(vcpu);
78767730e6cSSean Christopherson
78867730e6cSSean Christopherson test_guest_reg_read(vcpu);
78967730e6cSSean Christopherson
79067730e6cSSean Christopherson test_reset_preserves_id_regs(vcpu);
79167730e6cSSean Christopherson
79267730e6cSSean Christopherson kvm_vm_free(vm);
79367730e6cSSean Christopherson
79467730e6cSSean Christopherson ksft_finished();
79567730e6cSSean Christopherson }
796