2022-12-18 06:21:08

by Akihiko Odaki

[permalink] [raw]
Subject: [PATCH v3 7/7] KVM: arm64: Normalize cache configuration

Before this change, the cache configuration of the physical CPU was
exposed to vcpus. This is problematic because the cache configuration a
vcpu sees varies when it migrates between vcpus with different cache
configurations.

Fabricate cache configuration from the sanitized value, which holds the
CTR_EL0 value the userspace sees regardless of which physical CPU it
resides on.

CLIDR_EL1 is now writable from the userspace so that the VMM can
restore the values saved with the old kernel.

Suggested-by: Marc Zyngier <[email protected]>
Signed-off-by: Akihiko Odaki <[email protected]>
---
arch/arm64/include/asm/cache.h | 3 +
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/kvm/sys_regs.c | 183 +++++++++++++++---------------
3 files changed, 96 insertions(+), 91 deletions(-)

diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index ab7133654a72..a51e6e8f3171 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -22,6 +22,9 @@
#define CLIDR_CTYPE(clidr, level) \
(((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))

+/* Ttypen, bits [2(n - 1) + 34 : 2(n - 1) + 33], for n = 1 to 7 */
+#define CLIDR_TTYPE_SHIFT(level) (2 * ((level) - 1) + CLIDR_EL1_Ttypen_SHIFT)
+
/*
* Memory returned by kmalloc() may be used for DMA, so we must make
* sure that all such allocations are cache aligned. Otherwise,
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index cfc6930efe1b..27abf81c6910 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -178,6 +178,7 @@ struct kvm_vcpu_fault_info {
enum vcpu_sysreg {
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
MPIDR_EL1, /* MultiProcessor Affinity Register */
+ CLIDR_EL1, /* Cache Level ID Register */
CSSELR_EL1, /* Cache Size Selection Register */
SCTLR_EL1, /* System Control Register */
ACTLR_EL1, /* Auxiliary Control Register */
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a7199f34e321..9fd0b28e29bd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -11,6 +11,7 @@

#include <linux/bitfield.h>
#include <linux/bsearch.h>
+#include <linux/cacheinfo.h>
#include <linux/kvm_host.h>
#include <linux/mm.h>
#include <linux/printk.h>
@@ -81,9 +82,6 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
__vcpu_sys_reg(vcpu, reg) = val;
}

-/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
-static u32 cache_levels;
-
/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
#define CSSELR_MAX 14

@@ -101,47 +99,36 @@ static u8 get_min_cache_line_size(u32 csselr)
/* Which cache CCSIDR represents depends on CSSELR value. */
static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
{
- u32 ccsidr_index = csselr & (CSSELR_EL1_Level | CSSELR_EL1_InD);
- u32 ccsidr;
-
- if (vcpu->arch.ccsidr && is_valid_cache(ccsidr_index) &&
- !(kvm_has_mte(vcpu->kvm) && (csselr & CSSELR_EL1_TnD)))
- return vcpu->arch.ccsidr[ccsidr_index];
-
- /* Make sure noone else changes CSSELR during this! */
- local_irq_disable();
- write_sysreg(csselr, csselr_el1);
- isb();
- ccsidr = read_sysreg(ccsidr_el1);
- local_irq_enable();
-
- return ccsidr;
-}
-
-static bool is_valid_cache(u32 val)
-{
- u32 level, ctype;
+ u64 ctr_el0;
+ int field;

- if (val >= CSSELR_MAX)
- return false;
+ if (vcpu->arch.ccsidr)
+ return vcpu->arch.ccsidr[csselr];

- /* Bottom bit is Instruction or Data bit. Next 3 bits are level. */
- level = (val >> 1);
- ctype = (cache_levels >> (level * 3)) & 7;
+ ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
+ field = csselr & CSSELR_EL1_InD ? CTR_EL0_IminLine_SHIFT : CTR_EL0_DminLine_SHIFT;

- switch (ctype) {
- case 0: /* No cache */
- return false;
- case 1: /* Instruction cache only */
- return (val & 1);
- case 2: /* Data cache only */
- case 4: /* Unified cache */
- return !(val & 1);
- case 3: /* Separate instruction and data caches */
- return true;
- default: /* Reserved: we can't know instruction or data. */
- return false;
- }
+ /*
+ * Fabricate a CCSIDR value as the overriding value does not exist.
+ * The real CCSIDR value will not be used as it can vary by the
+ * physical CPU which the vcpu currently resides in.
+ *
+ * The line size is determined with arm64_ftr_reg_ctrel0.sys_val, which
+ * should be valid for all CPUs even if they have different cache
+ * configuration.
+ *
+ * The associativity bits are cleared, meaning the geometry of all data
+ * and unified caches (which are guaranteed to be PIPT and thus
+ * non-aliasing) are 1 set and 1 way.
+ * Guests should not be doing cache operations by set/way at all, and
+ * for this reason, we trap them and attempt to infer the intent, so
+ * that we can flush the entire guest's address space at the appropriate
+ * time. The exposed geometry minimizes the number of the traps.
+ * [If guests should attempt to infer aliasing properties from the
+ * geometry (which is not permitted by the architecture), they would
+ * only do so for virtually indexed caches.]
+ */
+ return get_min_cache_line_size(csselr) << CCSIDR_EL1_LineSize_SHIFT;
}

static int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val)
@@ -162,8 +149,7 @@ static int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val)
return -ENOMEM;

for (i = 0; i < CSSELR_MAX; i++)
- if (is_valid_cache(i))
- ccsidr[i] = get_ccsidr(vcpu, i);
+ ccsidr[i] = get_ccsidr(vcpu, i);

vcpu->arch.ccsidr = ccsidr;
}
@@ -1352,10 +1338,64 @@ static bool access_clidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
if (p->is_write)
return write_to_read_only(vcpu, p, r);

- p->regval = read_sysreg(clidr_el1);
+ p->regval = __vcpu_sys_reg(vcpu, r->reg);
return true;
}

+/*
+ * Fabricate a CLIDR_EL1 value instead of using the real value, which can vary
+ * by the physical CPU which the vcpu currently resides in.
+ */
+static void reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
+ u64 clidr;
+ u8 loc;
+
+ if ((ctr_el0 & CTR_EL0_IDC) || cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
+ /*
+ * Data cache clean to the PoU is not required so LoUU and LoUIS
+ * will not be set and a unified cache, which will be marked as
+ * LoC, will be added.
+ *
+ * If not DIC, let the unified cache L2 so that an instruction
+ * cache can be added as L1 later.
+ */
+ loc = (ctr_el0 & CTR_EL0_DIC) ? 1 : 2;
+ clidr = CACHE_TYPE_UNIFIED << CLIDR_CTYPE_SHIFT(loc);
+ } else {
+ /*
+ * Data cache clean to the PoU is required so let L1 have a data
+ * cache and mark it as LoUU and LoUIS. As L1 has a data cache,
+ * it can be marked as LoC too.
+ */
+ loc = 1;
+ clidr = 1 << CLIDR_LOUU_SHIFT;
+ clidr |= 1 << CLIDR_LOUIS_SHIFT;
+ clidr |= CACHE_TYPE_DATA << CLIDR_CTYPE_SHIFT(1);
+ }
+
+ /*
+ * Instruction cache invalidation to the PoU is required so let L1 have
+ * an instruction cache. If L1 already has a data cache, it will be
+ * CACHE_TYPE_SEPARATE.
+ */
+ if (!(ctr_el0 & CTR_EL0_DIC))
+ clidr |= CACHE_TYPE_INST << CLIDR_CTYPE_SHIFT(1);
+
+ clidr |= loc << CLIDR_LOC_SHIFT;
+
+ /*
+ * Add tag cache unified to data cache. Allocation tags and data are
+ * unified in a cache line so that it looks valid even if there is only
+ * one cache line.
+ */
+ if (kvm_has_mte(vcpu->kvm))
+ clidr |= 2 << CLIDR_TTYPE_SHIFT(loc);
+
+ __vcpu_sys_reg(vcpu, r->reg) = clidr;
+}
+
static bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
@@ -1377,22 +1417,12 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
return write_to_read_only(vcpu, p, r);

csselr = vcpu_read_sys_reg(vcpu, CSSELR_EL1);
+ csselr &= CSSELR_EL1_Level | CSSELR_EL1_InD;
+ if (csselr >= CSSELR_MAX)
+ return undef_access(vcpu, p, r);
+
p->regval = get_ccsidr(vcpu, csselr);

- /*
- * Guests should not be doing cache operations by set/way at all, and
- * for this reason, we trap them and attempt to infer the intent, so
- * that we can flush the entire guest's address space at the appropriate
- * time.
- * To prevent this trapping from causing performance problems, let's
- * expose the geometry of all data and unified caches (which are
- * guaranteed to be PIPT and thus non-aliasing) as 1 set and 1 way.
- * [If guests should attempt to infer aliasing properties from the
- * geometry (which is not permitted by the architecture), they would
- * only do so for virtually indexed caches.]
- */
- if (!(csselr & 1)) // data or unified cache
- p->regval &= ~GENMASK(27, 3);
return true;
}

@@ -1681,7 +1711,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_CNTKCTL_EL1), NULL, reset_val, CNTKCTL_EL1, 0},

{ SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
- { SYS_DESC(SYS_CLIDR_EL1), access_clidr },
+ { SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1 },
{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
@@ -2693,7 +2723,6 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,

FUNCTION_INVARIANT(midr_el1)
FUNCTION_INVARIANT(revidr_el1)
-FUNCTION_INVARIANT(clidr_el1)
FUNCTION_INVARIANT(aidr_el1)

static void get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r)
@@ -2705,7 +2734,6 @@ static void get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r)
static struct sys_reg_desc invariant_sys_regs[] = {
{ SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 },
{ SYS_DESC(SYS_REVIDR_EL1), NULL, get_revidr_el1 },
- { SYS_DESC(SYS_CLIDR_EL1), NULL, get_clidr_el1 },
{ SYS_DESC(SYS_AIDR_EL1), NULL, get_aidr_el1 },
{ SYS_DESC(SYS_CTR_EL0), NULL, get_ctr_el0 },
};
@@ -2758,7 +2786,7 @@ static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
return -ENOENT;
val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
>> KVM_REG_ARM_DEMUX_VAL_SHIFT;
- if (!is_valid_cache(val))
+ if (val >= CSSELR_MAX)
return -ENOENT;

return put_user(get_ccsidr(vcpu, val), uval);
@@ -2783,7 +2811,7 @@ static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
return -ENOENT;
val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
>> KVM_REG_ARM_DEMUX_VAL_SHIFT;
- if (!is_valid_cache(val))
+ if (val >= CSSELR_MAX)
return -ENOENT;

if (get_user(newval, uval))
@@ -2882,13 +2910,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg

static unsigned int num_demux_regs(void)
{
- unsigned int i, count = 0;
-
- for (i = 0; i < CSSELR_MAX; i++)
- if (is_valid_cache(i))
- count++;
-
- return count;
+ return CSSELR_MAX;
}

static int write_demux_regids(u64 __user *uindices)
@@ -2898,8 +2920,6 @@ static int write_demux_regids(u64 __user *uindices)

val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
for (i = 0; i < CSSELR_MAX; i++) {
- if (!is_valid_cache(i))
- continue;
if (put_user(val | i, uindices))
return -EFAULT;
uindices++;
@@ -3001,7 +3021,6 @@ int kvm_sys_reg_table_init(void)
{
bool valid = true;
unsigned int i;
- struct sys_reg_desc clidr;

/* Make sure tables are unique and in order. */
valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);
@@ -3018,23 +3037,5 @@ int kvm_sys_reg_table_init(void)
for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);

- /*
- * CLIDR format is awkward, so clean it up. See ARM B4.1.20:
- *
- * If software reads the Cache Type fields from Ctype1
- * upwards, once it has seen a value of 0b000, no caches
- * exist at further-out levels of the hierarchy. So, for
- * example, if Ctype3 is the first Cache Type field with a
- * value of 0b000, the values of Ctype4 to Ctype7 must be
- * ignored.
- */
- get_clidr_el1(NULL, &clidr); /* Ugly... */
- cache_levels = clidr.val;
- for (i = 0; i < 7; i++)
- if (((cache_levels >> (i*3)) & 7) == 0)
- break;
- /* Clear all higher bits. */
- cache_levels &= (1 << (i*3))-1;
-
return 0;
}
--
2.38.1


2022-12-18 07:06:39

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v3 7/7] KVM: arm64: Normalize cache configuration

Hi Akihiko,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on v6.1]
[also build test WARNING on linus/master next-20221216]
[cannot apply to kvmarm/next arm64/for-next/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Akihiko-Odaki/KVM-arm64-Normalize-cache-configuration/20221218-131711
patch link: https://lore.kernel.org/r/20221218051412.384657-8-akihiko.odaki%40daynix.com
patch subject: [PATCH v3 7/7] KVM: arm64: Normalize cache configuration
config: arm64-randconfig-r021-20221218
compiler: aarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/bdbdb090163b6fd99fc43959273525c2d0785734
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Akihiko-Odaki/KVM-arm64-Normalize-cache-configuration/20221218-131711
git checkout bdbdb090163b6fd99fc43959273525c2d0785734
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm64 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash arch/arm64/kvm/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

arch/arm64/kvm/sys_regs.c: In function 'get_ccsidr':
>> arch/arm64/kvm/sys_regs.c:103:13: warning: variable 'field' set but not used [-Wunused-but-set-variable]
103 | int field;
| ^~~~~
>> arch/arm64/kvm/sys_regs.c:102:13: warning: variable 'ctr_el0' set but not used [-Wunused-but-set-variable]
102 | u64 ctr_el0;
| ^~~~~~~
arch/arm64/kvm/sys_regs.c: At top level:
arch/arm64/kvm/sys_regs.c:1722:20: warning: initialized field overwritten [-Woverride-init]
1722 | .reset = reset_pmcr, .reg = PMCR_EL0 },
| ^~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1722:20: note: (near initialization for 'sys_reg_descs[221].reset')
In file included from include/uapi/linux/posix_types.h:5,
from include/uapi/linux/types.h:14,
from include/linux/types.h:6,
from include/linux/kasan-checks.h:5,
from include/asm-generic/rwonce.h:26,
from arch/arm64/include/asm/rwonce.h:71,
from include/linux/compiler.h:246,
from include/linux/build_bug.h:5,
from include/linux/bitfield.h:10,
from arch/arm64/kvm/sys_regs.c:12:
include/linux/stddef.h:8:14: warning: initialized field overwritten [-Woverride-init]
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1735:46: note: in expansion of macro 'NULL'
1735 | .access = access_pmswinc, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: note: (near initialization for 'sys_reg_descs[225].reset')
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1735:46: note: in expansion of macro 'NULL'
1735 | .access = access_pmswinc, .reset = NULL },
| ^~~~
arch/arm64/kvm/sys_regs.c:1737:45: warning: initialized field overwritten [-Woverride-init]
1737 | .access = access_pmselr, .reset = reset_pmselr, .reg = PMSELR_EL0 },
| ^~~~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1737:45: note: (near initialization for 'sys_reg_descs[226].reset')
include/linux/stddef.h:8:14: warning: initialized field overwritten [-Woverride-init]
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1739:45: note: in expansion of macro 'NULL'
1739 | .access = access_pmceid, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: note: (near initialization for 'sys_reg_descs[227].reset')
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1739:45: note: in expansion of macro 'NULL'
1739 | .access = access_pmceid, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: warning: initialized field overwritten [-Woverride-init]
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1741:45: note: in expansion of macro 'NULL'
1741 | .access = access_pmceid, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: note: (near initialization for 'sys_reg_descs[228].reset')
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1741:45: note: in expansion of macro 'NULL'
1741 | .access = access_pmceid, .reset = NULL },
| ^~~~
arch/arm64/kvm/sys_regs.c:1743:49: warning: initialized field overwritten [-Woverride-init]
1743 | .access = access_pmu_evcntr, .reset = reset_unknown, .reg = PMCCNTR_EL0 },
| ^~~~~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1743:49: note: (near initialization for 'sys_reg_descs[229].reset')
include/linux/stddef.h:8:14: warning: initialized field overwritten [-Woverride-init]
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1745:50: note: in expansion of macro 'NULL'
1745 | .access = access_pmu_evtyper, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: note: (near initialization for 'sys_reg_descs[230].reset')
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1745:50: note: in expansion of macro 'NULL'
1745 | .access = access_pmu_evtyper, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: warning: initialized field overwritten [-Woverride-init]
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1747:49: note: in expansion of macro 'NULL'
1747 | .access = access_pmu_evcntr, .reset = NULL },
| ^~~~
include/linux/stddef.h:8:14: note: (near initialization for 'sys_reg_descs[231].reset')
8 | #define NULL ((void *)0)
| ^
arch/arm64/kvm/sys_regs.c:1747:49: note: in expansion of macro 'NULL'
1747 | .access = access_pmu_evcntr, .reset = NULL },
| ^~~~
arch/arm64/kvm/sys_regs.c:1753:20: warning: initialized field overwritten [-Woverride-init]
1753 | .reset = reset_val, .reg = PMUSERENR_EL0, .val = 0 },
| ^~~~~~~~~
arch/arm64/kvm/sys_regs.c:1753:20: note: (near initialization for 'sys_reg_descs[232].reset')
arch/arm64/kvm/sys_regs.c:1043:20: warning: initialized field overwritten [-Woverride-init]
1043 | .reset = reset_pmevcntr, \
| ^~~~~~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1841:9: note: in expansion of macro 'PMU_PMEVCNTR_EL0'
1841 | PMU_PMEVCNTR_EL0(0),
| ^~~~~~~~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1043:20: note: (near initialization for 'sys_reg_descs[313].reset')
1043 | .reset = reset_pmevcntr, \
| ^~~~~~~~~~~~~~
arch/arm64/kvm/sys_regs.c:1841:9: note: in expansion of macro 'PMU_PMEVCNTR_EL0'
1841 | PMU_PMEVCNTR_EL0(0),


vim +/field +103 arch/arm64/kvm/sys_regs.c

98
99 /* Which cache CCSIDR represents depends on CSSELR value. */
100 static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
101 {
> 102 u64 ctr_el0;
> 103 int field;
104
105 if (vcpu->arch.ccsidr)
106 return vcpu->arch.ccsidr[csselr];
107
108 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
109 field = csselr & CSSELR_EL1_InD ? CTR_EL0_IminLine_SHIFT : CTR_EL0_DminLine_SHIFT;
110
111 /*
112 * Fabricate a CCSIDR value as the overriding value does not exist.
113 * The real CCSIDR value will not be used as it can vary by the
114 * physical CPU which the vcpu currently resides in.
115 *
116 * The line size is determined with arm64_ftr_reg_ctrel0.sys_val, which
117 * should be valid for all CPUs even if they have different cache
118 * configuration.
119 *
120 * The associativity bits are cleared, meaning the geometry of all data
121 * and unified caches (which are guaranteed to be PIPT and thus
122 * non-aliasing) are 1 set and 1 way.
123 * Guests should not be doing cache operations by set/way at all, and
124 * for this reason, we trap them and attempt to infer the intent, so
125 * that we can flush the entire guest's address space at the appropriate
126 * time. The exposed geometry minimizes the number of the traps.
127 * [If guests should attempt to infer aliasing properties from the
128 * geometry (which is not permitted by the architecture), they would
129 * only do so for virtually indexed caches.]
130 */
131 return get_min_cache_line_size(csselr) << CCSIDR_EL1_LineSize_SHIFT;
132 }
133

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (10.07 kB)
config (170.03 kB)
Download all attachments