1*67730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0-only 2*67730e6cSSean Christopherson 3*67730e6cSSean Christopherson /* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface. 4*67730e6cSSean Christopherson * 5*67730e6cSSean Christopherson * The test validates the basic hypercall functionalities that are exposed 6*67730e6cSSean Christopherson * via the psuedo-firmware bitmap register. This includes the registers' 7*67730e6cSSean Christopherson * read/write behavior before and after the VM has started, and if the 8*67730e6cSSean Christopherson * hypercalls are properly masked or unmasked to the guest when disabled or 9*67730e6cSSean Christopherson * enabled from the KVM userspace, respectively. 10*67730e6cSSean Christopherson */ 11*67730e6cSSean Christopherson #include <errno.h> 12*67730e6cSSean Christopherson #include <linux/arm-smccc.h> 13*67730e6cSSean Christopherson #include <asm/kvm.h> 14*67730e6cSSean Christopherson #include <kvm_util.h> 15*67730e6cSSean Christopherson 16*67730e6cSSean Christopherson #include "processor.h" 17*67730e6cSSean Christopherson 18*67730e6cSSean Christopherson #define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0)) 19*67730e6cSSean Christopherson 20*67730e6cSSean Christopherson /* Last valid bits of the bitmapped firmware registers */ 21*67730e6cSSean Christopherson #define KVM_REG_ARM_STD_BMAP_BIT_MAX 0 22*67730e6cSSean Christopherson #define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX 0 23*67730e6cSSean Christopherson #define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX 1 24*67730e6cSSean Christopherson 25*67730e6cSSean Christopherson struct kvm_fw_reg_info { 26*67730e6cSSean Christopherson uint64_t reg; /* Register definition */ 27*67730e6cSSean Christopherson uint64_t max_feat_bit; /* Bit that represents the upper limit of the feature-map */ 28*67730e6cSSean Christopherson }; 29*67730e6cSSean Christopherson 30*67730e6cSSean Christopherson #define FW_REG_INFO(r) \ 31*67730e6cSSean Christopherson { \ 32*67730e6cSSean Christopherson .reg = r, \ 33*67730e6cSSean Christopherson .max_feat_bit = r##_BIT_MAX, \ 34*67730e6cSSean Christopherson } 35*67730e6cSSean Christopherson 36*67730e6cSSean Christopherson static const struct kvm_fw_reg_info fw_reg_info[] = { 37*67730e6cSSean Christopherson FW_REG_INFO(KVM_REG_ARM_STD_BMAP), 38*67730e6cSSean Christopherson FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP), 39*67730e6cSSean Christopherson FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP), 40*67730e6cSSean Christopherson }; 41*67730e6cSSean Christopherson 42*67730e6cSSean Christopherson enum test_stage { 43*67730e6cSSean Christopherson TEST_STAGE_REG_IFACE, 44*67730e6cSSean Christopherson TEST_STAGE_HVC_IFACE_FEAT_DISABLED, 45*67730e6cSSean Christopherson TEST_STAGE_HVC_IFACE_FEAT_ENABLED, 46*67730e6cSSean Christopherson TEST_STAGE_HVC_IFACE_FALSE_INFO, 47*67730e6cSSean Christopherson TEST_STAGE_END, 48*67730e6cSSean Christopherson }; 49*67730e6cSSean Christopherson 50*67730e6cSSean Christopherson static int stage = TEST_STAGE_REG_IFACE; 51*67730e6cSSean Christopherson 52*67730e6cSSean Christopherson struct test_hvc_info { 53*67730e6cSSean Christopherson uint32_t func_id; 54*67730e6cSSean Christopherson uint64_t arg1; 55*67730e6cSSean Christopherson }; 56*67730e6cSSean Christopherson 57*67730e6cSSean Christopherson #define TEST_HVC_INFO(f, a1) \ 58*67730e6cSSean Christopherson { \ 59*67730e6cSSean Christopherson .func_id = f, \ 60*67730e6cSSean Christopherson .arg1 = a1, \ 61*67730e6cSSean Christopherson } 62*67730e6cSSean Christopherson 63*67730e6cSSean Christopherson static const struct test_hvc_info hvc_info[] = { 64*67730e6cSSean Christopherson /* KVM_REG_ARM_STD_BMAP */ 65*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0), 66*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64), 67*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0), 68*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0), 69*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0), 70*67730e6cSSean Christopherson 71*67730e6cSSean Christopherson /* KVM_REG_ARM_STD_HYP_BMAP */ 72*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES), 73*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST), 74*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0), 75*67730e6cSSean Christopherson 76*67730e6cSSean Christopherson /* KVM_REG_ARM_VENDOR_HYP_BMAP */ 77*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID, 78*67730e6cSSean Christopherson ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID), 79*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0), 80*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER), 81*67730e6cSSean Christopherson }; 82*67730e6cSSean Christopherson 83*67730e6cSSean Christopherson /* Feed false hypercall info to test the KVM behavior */ 84*67730e6cSSean Christopherson static const struct test_hvc_info false_hvc_info[] = { 85*67730e6cSSean Christopherson /* Feature support check against a different family of hypercalls */ 86*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID), 87*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64), 88*67730e6cSSean Christopherson TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64), 89*67730e6cSSean Christopherson }; 90*67730e6cSSean Christopherson 91*67730e6cSSean Christopherson static void guest_test_hvc(const struct test_hvc_info *hc_info) 92*67730e6cSSean Christopherson { 93*67730e6cSSean Christopherson unsigned int i; 94*67730e6cSSean Christopherson struct arm_smccc_res res; 95*67730e6cSSean Christopherson unsigned int hvc_info_arr_sz; 96*67730e6cSSean Christopherson 97*67730e6cSSean Christopherson hvc_info_arr_sz = 98*67730e6cSSean Christopherson hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info); 99*67730e6cSSean Christopherson 100*67730e6cSSean Christopherson for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) { 101*67730e6cSSean Christopherson memset(&res, 0, sizeof(res)); 102*67730e6cSSean Christopherson smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res); 103*67730e6cSSean Christopherson 104*67730e6cSSean Christopherson switch (stage) { 105*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: 106*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FALSE_INFO: 107*67730e6cSSean Christopherson __GUEST_ASSERT(res.a0 == SMCCC_RET_NOT_SUPPORTED, 108*67730e6cSSean Christopherson "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%lx, stage = %u", 109*67730e6cSSean Christopherson res.a0, hc_info->func_id, hc_info->arg1, stage); 110*67730e6cSSean Christopherson break; 111*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: 112*67730e6cSSean Christopherson __GUEST_ASSERT(res.a0 != SMCCC_RET_NOT_SUPPORTED, 113*67730e6cSSean Christopherson "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%lx, stage = %u", 114*67730e6cSSean Christopherson res.a0, hc_info->func_id, hc_info->arg1, stage); 115*67730e6cSSean Christopherson break; 116*67730e6cSSean Christopherson default: 117*67730e6cSSean Christopherson GUEST_FAIL("Unexpected stage = %u", stage); 118*67730e6cSSean Christopherson } 119*67730e6cSSean Christopherson } 120*67730e6cSSean Christopherson } 121*67730e6cSSean Christopherson 122*67730e6cSSean Christopherson static void guest_code(void) 123*67730e6cSSean Christopherson { 124*67730e6cSSean Christopherson while (stage != TEST_STAGE_END) { 125*67730e6cSSean Christopherson switch (stage) { 126*67730e6cSSean Christopherson case TEST_STAGE_REG_IFACE: 127*67730e6cSSean Christopherson break; 128*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: 129*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: 130*67730e6cSSean Christopherson guest_test_hvc(hvc_info); 131*67730e6cSSean Christopherson break; 132*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FALSE_INFO: 133*67730e6cSSean Christopherson guest_test_hvc(false_hvc_info); 134*67730e6cSSean Christopherson break; 135*67730e6cSSean Christopherson default: 136*67730e6cSSean Christopherson GUEST_FAIL("Unexpected stage = %u", stage); 137*67730e6cSSean Christopherson } 138*67730e6cSSean Christopherson 139*67730e6cSSean Christopherson GUEST_SYNC(stage); 140*67730e6cSSean Christopherson } 141*67730e6cSSean Christopherson 142*67730e6cSSean Christopherson GUEST_DONE(); 143*67730e6cSSean Christopherson } 144*67730e6cSSean Christopherson 145*67730e6cSSean Christopherson struct st_time { 146*67730e6cSSean Christopherson uint32_t rev; 147*67730e6cSSean Christopherson uint32_t attr; 148*67730e6cSSean Christopherson uint64_t st_time; 149*67730e6cSSean Christopherson }; 150*67730e6cSSean Christopherson 151*67730e6cSSean Christopherson #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) 152*67730e6cSSean Christopherson #define ST_GPA_BASE (1 << 30) 153*67730e6cSSean Christopherson 154*67730e6cSSean Christopherson static void steal_time_init(struct kvm_vcpu *vcpu) 155*67730e6cSSean Christopherson { 156*67730e6cSSean Christopherson uint64_t st_ipa = (ulong)ST_GPA_BASE; 157*67730e6cSSean Christopherson unsigned int gpages; 158*67730e6cSSean Christopherson 159*67730e6cSSean Christopherson gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); 160*67730e6cSSean Christopherson vm_userspace_mem_region_add(vcpu->vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); 161*67730e6cSSean Christopherson 162*67730e6cSSean Christopherson vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PVTIME_CTRL, 163*67730e6cSSean Christopherson KVM_ARM_VCPU_PVTIME_IPA, &st_ipa); 164*67730e6cSSean Christopherson } 165*67730e6cSSean Christopherson 166*67730e6cSSean Christopherson static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) 167*67730e6cSSean Christopherson { 168*67730e6cSSean Christopherson uint64_t val; 169*67730e6cSSean Christopherson unsigned int i; 170*67730e6cSSean Christopherson int ret; 171*67730e6cSSean Christopherson 172*67730e6cSSean Christopherson for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { 173*67730e6cSSean Christopherson const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; 174*67730e6cSSean Christopherson 175*67730e6cSSean Christopherson /* First 'read' should be an upper limit of the features supported */ 176*67730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg_info->reg); 177*67730e6cSSean Christopherson TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), 178*67730e6cSSean Christopherson "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx", 179*67730e6cSSean Christopherson reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); 180*67730e6cSSean Christopherson 181*67730e6cSSean Christopherson /* Test a 'write' by disabling all the features of the register map */ 182*67730e6cSSean Christopherson ret = __vcpu_set_reg(vcpu, reg_info->reg, 0); 183*67730e6cSSean Christopherson TEST_ASSERT(ret == 0, 184*67730e6cSSean Christopherson "Failed to clear all the features of reg: 0x%lx; ret: %d", 185*67730e6cSSean Christopherson reg_info->reg, errno); 186*67730e6cSSean Christopherson 187*67730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg_info->reg); 188*67730e6cSSean Christopherson TEST_ASSERT(val == 0, 189*67730e6cSSean Christopherson "Expected all the features to be cleared for reg: 0x%lx", reg_info->reg); 190*67730e6cSSean Christopherson 191*67730e6cSSean Christopherson /* 192*67730e6cSSean Christopherson * Test enabling a feature that's not supported. 193*67730e6cSSean Christopherson * Avoid this check if all the bits are occupied. 194*67730e6cSSean Christopherson */ 195*67730e6cSSean Christopherson if (reg_info->max_feat_bit < 63) { 196*67730e6cSSean Christopherson ret = __vcpu_set_reg(vcpu, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); 197*67730e6cSSean Christopherson TEST_ASSERT(ret != 0 && errno == EINVAL, 198*67730e6cSSean Christopherson "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx", 199*67730e6cSSean Christopherson errno, reg_info->reg); 200*67730e6cSSean Christopherson } 201*67730e6cSSean Christopherson } 202*67730e6cSSean Christopherson } 203*67730e6cSSean Christopherson 204*67730e6cSSean Christopherson static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) 205*67730e6cSSean Christopherson { 206*67730e6cSSean Christopherson uint64_t val; 207*67730e6cSSean Christopherson unsigned int i; 208*67730e6cSSean Christopherson int ret; 209*67730e6cSSean Christopherson 210*67730e6cSSean Christopherson for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { 211*67730e6cSSean Christopherson const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; 212*67730e6cSSean Christopherson 213*67730e6cSSean Christopherson /* 214*67730e6cSSean Christopherson * Before starting the VM, the test clears all the bits. 215*67730e6cSSean Christopherson * Check if that's still the case. 216*67730e6cSSean Christopherson */ 217*67730e6cSSean Christopherson val = vcpu_get_reg(vcpu, reg_info->reg); 218*67730e6cSSean Christopherson TEST_ASSERT(val == 0, 219*67730e6cSSean Christopherson "Expected all the features to be cleared for reg: 0x%lx", 220*67730e6cSSean Christopherson reg_info->reg); 221*67730e6cSSean Christopherson 222*67730e6cSSean Christopherson /* 223*67730e6cSSean Christopherson * Since the VM has run at least once, KVM shouldn't allow modification of 224*67730e6cSSean Christopherson * the registers and should return EBUSY. Set the registers and check for 225*67730e6cSSean Christopherson * the expected errno. 226*67730e6cSSean Christopherson */ 227*67730e6cSSean Christopherson ret = __vcpu_set_reg(vcpu, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); 228*67730e6cSSean Christopherson TEST_ASSERT(ret != 0 && errno == EBUSY, 229*67730e6cSSean Christopherson "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx", 230*67730e6cSSean Christopherson errno, reg_info->reg); 231*67730e6cSSean Christopherson } 232*67730e6cSSean Christopherson } 233*67730e6cSSean Christopherson 234*67730e6cSSean Christopherson static struct kvm_vm *test_vm_create(struct kvm_vcpu **vcpu) 235*67730e6cSSean Christopherson { 236*67730e6cSSean Christopherson struct kvm_vm *vm; 237*67730e6cSSean Christopherson 238*67730e6cSSean Christopherson vm = vm_create_with_one_vcpu(vcpu, guest_code); 239*67730e6cSSean Christopherson 240*67730e6cSSean Christopherson steal_time_init(*vcpu); 241*67730e6cSSean Christopherson 242*67730e6cSSean Christopherson return vm; 243*67730e6cSSean Christopherson } 244*67730e6cSSean Christopherson 245*67730e6cSSean Christopherson static void test_guest_stage(struct kvm_vm **vm, struct kvm_vcpu **vcpu) 246*67730e6cSSean Christopherson { 247*67730e6cSSean Christopherson int prev_stage = stage; 248*67730e6cSSean Christopherson 249*67730e6cSSean Christopherson pr_debug("Stage: %d\n", prev_stage); 250*67730e6cSSean Christopherson 251*67730e6cSSean Christopherson /* Sync the stage early, the VM might be freed below. */ 252*67730e6cSSean Christopherson stage++; 253*67730e6cSSean Christopherson sync_global_to_guest(*vm, stage); 254*67730e6cSSean Christopherson 255*67730e6cSSean Christopherson switch (prev_stage) { 256*67730e6cSSean Christopherson case TEST_STAGE_REG_IFACE: 257*67730e6cSSean Christopherson test_fw_regs_after_vm_start(*vcpu); 258*67730e6cSSean Christopherson break; 259*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: 260*67730e6cSSean Christopherson /* Start a new VM so that all the features are now enabled by default */ 261*67730e6cSSean Christopherson kvm_vm_free(*vm); 262*67730e6cSSean Christopherson *vm = test_vm_create(vcpu); 263*67730e6cSSean Christopherson break; 264*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: 265*67730e6cSSean Christopherson case TEST_STAGE_HVC_IFACE_FALSE_INFO: 266*67730e6cSSean Christopherson break; 267*67730e6cSSean Christopherson default: 268*67730e6cSSean Christopherson TEST_FAIL("Unknown test stage: %d", prev_stage); 269*67730e6cSSean Christopherson } 270*67730e6cSSean Christopherson } 271*67730e6cSSean Christopherson 272*67730e6cSSean Christopherson static void test_run(void) 273*67730e6cSSean Christopherson { 274*67730e6cSSean Christopherson struct kvm_vcpu *vcpu; 275*67730e6cSSean Christopherson struct kvm_vm *vm; 276*67730e6cSSean Christopherson struct ucall uc; 277*67730e6cSSean Christopherson bool guest_done = false; 278*67730e6cSSean Christopherson 279*67730e6cSSean Christopherson vm = test_vm_create(&vcpu); 280*67730e6cSSean Christopherson 281*67730e6cSSean Christopherson test_fw_regs_before_vm_start(vcpu); 282*67730e6cSSean Christopherson 283*67730e6cSSean Christopherson while (!guest_done) { 284*67730e6cSSean Christopherson vcpu_run(vcpu); 285*67730e6cSSean Christopherson 286*67730e6cSSean Christopherson switch (get_ucall(vcpu, &uc)) { 287*67730e6cSSean Christopherson case UCALL_SYNC: 288*67730e6cSSean Christopherson test_guest_stage(&vm, &vcpu); 289*67730e6cSSean Christopherson break; 290*67730e6cSSean Christopherson case UCALL_DONE: 291*67730e6cSSean Christopherson guest_done = true; 292*67730e6cSSean Christopherson break; 293*67730e6cSSean Christopherson case UCALL_ABORT: 294*67730e6cSSean Christopherson REPORT_GUEST_ASSERT(uc); 295*67730e6cSSean Christopherson break; 296*67730e6cSSean Christopherson default: 297*67730e6cSSean Christopherson TEST_FAIL("Unexpected guest exit"); 298*67730e6cSSean Christopherson } 299*67730e6cSSean Christopherson } 300*67730e6cSSean Christopherson 301*67730e6cSSean Christopherson kvm_vm_free(vm); 302*67730e6cSSean Christopherson } 303*67730e6cSSean Christopherson 304*67730e6cSSean Christopherson int main(void) 305*67730e6cSSean Christopherson { 306*67730e6cSSean Christopherson test_run(); 307*67730e6cSSean Christopherson return 0; 308*67730e6cSSean Christopherson } 309