162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 - Columbia University and Linaro Ltd. 462306a36Sopenharmony_ci * Author: Jintack Lim <jintack.lim@linaro.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kvm.h> 862306a36Sopenharmony_ci#include <linux/kvm_host.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 1162306a36Sopenharmony_ci#include <asm/kvm_nested.h> 1262306a36Sopenharmony_ci#include <asm/sysreg.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "sys_regs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* Protection against the sysreg repainting madness... */ 1762306a36Sopenharmony_ci#define NV_FTR(r, f) ID_AA64##r##_EL1_##f 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Our emulated CPU doesn't support all the possible features. For the 2162306a36Sopenharmony_ci * sake of simplicity (and probably mental sanity), wipe out a number 2262306a36Sopenharmony_ci * of feature bits we don't intend to support for the time being. 2362306a36Sopenharmony_ci * This list should get updated as new features get added to the NV 2462306a36Sopenharmony_ci * support, and new extension to the architecture. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_civoid access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, 2762306a36Sopenharmony_ci const struct sys_reg_desc *r) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci u32 id = reg_to_encoding(r); 3062306a36Sopenharmony_ci u64 val, tmp; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci val = p->regval; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci switch (id) { 3562306a36Sopenharmony_ci case SYS_ID_AA64ISAR0_EL1: 3662306a36Sopenharmony_ci /* Support everything but TME, O.S. and Range TLBIs */ 3762306a36Sopenharmony_ci val &= ~(NV_FTR(ISAR0, TLB) | 3862306a36Sopenharmony_ci NV_FTR(ISAR0, TME)); 3962306a36Sopenharmony_ci break; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci case SYS_ID_AA64ISAR1_EL1: 4262306a36Sopenharmony_ci /* Support everything but PtrAuth and Spec Invalidation */ 4362306a36Sopenharmony_ci val &= ~(GENMASK_ULL(63, 56) | 4462306a36Sopenharmony_ci NV_FTR(ISAR1, SPECRES) | 4562306a36Sopenharmony_ci NV_FTR(ISAR1, GPI) | 4662306a36Sopenharmony_ci NV_FTR(ISAR1, GPA) | 4762306a36Sopenharmony_ci NV_FTR(ISAR1, API) | 4862306a36Sopenharmony_ci NV_FTR(ISAR1, APA)); 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci case SYS_ID_AA64PFR0_EL1: 5262306a36Sopenharmony_ci /* No AMU, MPAM, S-EL2, RAS or SVE */ 5362306a36Sopenharmony_ci val &= ~(GENMASK_ULL(55, 52) | 5462306a36Sopenharmony_ci NV_FTR(PFR0, AMU) | 5562306a36Sopenharmony_ci NV_FTR(PFR0, MPAM) | 5662306a36Sopenharmony_ci NV_FTR(PFR0, SEL2) | 5762306a36Sopenharmony_ci NV_FTR(PFR0, RAS) | 5862306a36Sopenharmony_ci NV_FTR(PFR0, SVE) | 5962306a36Sopenharmony_ci NV_FTR(PFR0, EL3) | 6062306a36Sopenharmony_ci NV_FTR(PFR0, EL2) | 6162306a36Sopenharmony_ci NV_FTR(PFR0, EL1)); 6262306a36Sopenharmony_ci /* 64bit EL1/EL2/EL3 only */ 6362306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(PFR0, EL1), 0b0001); 6462306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(PFR0, EL2), 0b0001); 6562306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(PFR0, EL3), 0b0001); 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci case SYS_ID_AA64PFR1_EL1: 6962306a36Sopenharmony_ci /* Only support SSBS */ 7062306a36Sopenharmony_ci val &= NV_FTR(PFR1, SSBS); 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci case SYS_ID_AA64MMFR0_EL1: 7462306a36Sopenharmony_ci /* Hide ECV, ExS, Secure Memory */ 7562306a36Sopenharmony_ci val &= ~(NV_FTR(MMFR0, ECV) | 7662306a36Sopenharmony_ci NV_FTR(MMFR0, EXS) | 7762306a36Sopenharmony_ci NV_FTR(MMFR0, TGRAN4_2) | 7862306a36Sopenharmony_ci NV_FTR(MMFR0, TGRAN16_2) | 7962306a36Sopenharmony_ci NV_FTR(MMFR0, TGRAN64_2) | 8062306a36Sopenharmony_ci NV_FTR(MMFR0, SNSMEM)); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Disallow unsupported S2 page sizes */ 8362306a36Sopenharmony_ci switch (PAGE_SIZE) { 8462306a36Sopenharmony_ci case SZ_64K: 8562306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0001); 8662306a36Sopenharmony_ci fallthrough; 8762306a36Sopenharmony_ci case SZ_16K: 8862306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0001); 8962306a36Sopenharmony_ci fallthrough; 9062306a36Sopenharmony_ci case SZ_4K: 9162306a36Sopenharmony_ci /* Support everything */ 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Since we can't support a guest S2 page size smaller than 9662306a36Sopenharmony_ci * the host's own page size (due to KVM only populating its 9762306a36Sopenharmony_ci * own S2 using the kernel's page size), advertise the 9862306a36Sopenharmony_ci * limitation using FEAT_GTG. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci switch (PAGE_SIZE) { 10162306a36Sopenharmony_ci case SZ_4K: 10262306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN4_2), 0b0010); 10362306a36Sopenharmony_ci fallthrough; 10462306a36Sopenharmony_ci case SZ_16K: 10562306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN16_2), 0b0010); 10662306a36Sopenharmony_ci fallthrough; 10762306a36Sopenharmony_ci case SZ_64K: 10862306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, TGRAN64_2), 0b0010); 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci /* Cap PARange to 48bits */ 11262306a36Sopenharmony_ci tmp = FIELD_GET(NV_FTR(MMFR0, PARANGE), val); 11362306a36Sopenharmony_ci if (tmp > 0b0101) { 11462306a36Sopenharmony_ci val &= ~NV_FTR(MMFR0, PARANGE); 11562306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR0, PARANGE), 0b0101); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci case SYS_ID_AA64MMFR1_EL1: 12062306a36Sopenharmony_ci val &= (NV_FTR(MMFR1, HCX) | 12162306a36Sopenharmony_ci NV_FTR(MMFR1, PAN) | 12262306a36Sopenharmony_ci NV_FTR(MMFR1, LO) | 12362306a36Sopenharmony_ci NV_FTR(MMFR1, HPDS) | 12462306a36Sopenharmony_ci NV_FTR(MMFR1, VH) | 12562306a36Sopenharmony_ci NV_FTR(MMFR1, VMIDBits)); 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci case SYS_ID_AA64MMFR2_EL1: 12962306a36Sopenharmony_ci val &= ~(NV_FTR(MMFR2, BBM) | 13062306a36Sopenharmony_ci NV_FTR(MMFR2, TTL) | 13162306a36Sopenharmony_ci GENMASK_ULL(47, 44) | 13262306a36Sopenharmony_ci NV_FTR(MMFR2, ST) | 13362306a36Sopenharmony_ci NV_FTR(MMFR2, CCIDX) | 13462306a36Sopenharmony_ci NV_FTR(MMFR2, VARange)); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Force TTL support */ 13762306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(MMFR2, TTL), 0b0001); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci case SYS_ID_AA64DFR0_EL1: 14162306a36Sopenharmony_ci /* Only limited support for PMU, Debug, BPs and WPs */ 14262306a36Sopenharmony_ci val &= (NV_FTR(DFR0, PMUVer) | 14362306a36Sopenharmony_ci NV_FTR(DFR0, WRPs) | 14462306a36Sopenharmony_ci NV_FTR(DFR0, BRPs) | 14562306a36Sopenharmony_ci NV_FTR(DFR0, DebugVer)); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Cap Debug to ARMv8.1 */ 14862306a36Sopenharmony_ci tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val); 14962306a36Sopenharmony_ci if (tmp > 0b0111) { 15062306a36Sopenharmony_ci val &= ~NV_FTR(DFR0, DebugVer); 15162306a36Sopenharmony_ci val |= FIELD_PREP(NV_FTR(DFR0, DebugVer), 0b0111); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci /* Unknown register, just wipe it clean */ 15762306a36Sopenharmony_ci val = 0; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci p->regval = val; 16262306a36Sopenharmony_ci} 163