cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tlb.c (11079B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2022 Ventana Micro Systems Inc.
      4 */
      5
      6#include <linux/bitmap.h>
      7#include <linux/cpumask.h>
      8#include <linux/errno.h>
      9#include <linux/err.h>
     10#include <linux/module.h>
     11#include <linux/smp.h>
     12#include <linux/kvm_host.h>
     13#include <asm/cacheflush.h>
     14#include <asm/csr.h>
     15
     16/*
     17 * Instruction encoding of hfence.gvma is:
     18 * HFENCE.GVMA rs1, rs2
     19 * HFENCE.GVMA zero, rs2
     20 * HFENCE.GVMA rs1
     21 * HFENCE.GVMA
     22 *
     23 * rs1!=zero and rs2!=zero ==> HFENCE.GVMA rs1, rs2
     24 * rs1==zero and rs2!=zero ==> HFENCE.GVMA zero, rs2
     25 * rs1!=zero and rs2==zero ==> HFENCE.GVMA rs1
     26 * rs1==zero and rs2==zero ==> HFENCE.GVMA
     27 *
     28 * Instruction encoding of HFENCE.GVMA is:
     29 * 0110001 rs2(5) rs1(5) 000 00000 1110011
     30 */
     31
     32void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid,
     33					  gpa_t gpa, gpa_t gpsz,
     34					  unsigned long order)
     35{
     36	gpa_t pos;
     37
     38	if (PTRS_PER_PTE < (gpsz >> order)) {
     39		kvm_riscv_local_hfence_gvma_vmid_all(vmid);
     40		return;
     41	}
     42
     43	for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order)) {
     44		/*
     45		 * rs1 = a0 (GPA >> 2)
     46		 * rs2 = a1 (VMID)
     47		 * HFENCE.GVMA a0, a1
     48		 * 0110001 01011 01010 000 00000 1110011
     49		 */
     50		asm volatile ("srli a0, %0, 2\n"
     51			      "add a1, %1, zero\n"
     52			      ".word 0x62b50073\n"
     53			      :: "r" (pos), "r" (vmid)
     54			      : "a0", "a1", "memory");
     55	}
     56}
     57
     58void kvm_riscv_local_hfence_gvma_vmid_all(unsigned long vmid)
     59{
     60	/*
     61	 * rs1 = zero
     62	 * rs2 = a0 (VMID)
     63	 * HFENCE.GVMA zero, a0
     64	 * 0110001 01010 00000 000 00000 1110011
     65	 */
     66	asm volatile ("add a0, %0, zero\n"
     67		      ".word 0x62a00073\n"
     68		      :: "r" (vmid) : "a0", "memory");
     69}
     70
     71void kvm_riscv_local_hfence_gvma_gpa(gpa_t gpa, gpa_t gpsz,
     72				     unsigned long order)
     73{
     74	gpa_t pos;
     75
     76	if (PTRS_PER_PTE < (gpsz >> order)) {
     77		kvm_riscv_local_hfence_gvma_all();
     78		return;
     79	}
     80
     81	for (pos = gpa; pos < (gpa + gpsz); pos += BIT(order)) {
     82		/*
     83		 * rs1 = a0 (GPA >> 2)
     84		 * rs2 = zero
     85		 * HFENCE.GVMA a0
     86		 * 0110001 00000 01010 000 00000 1110011
     87		 */
     88		asm volatile ("srli a0, %0, 2\n"
     89			      ".word 0x62050073\n"
     90			      :: "r" (pos) : "a0", "memory");
     91	}
     92}
     93
     94void kvm_riscv_local_hfence_gvma_all(void)
     95{
     96	/*
     97	 * rs1 = zero
     98	 * rs2 = zero
     99	 * HFENCE.GVMA
    100	 * 0110001 00000 00000 000 00000 1110011
    101	 */
    102	asm volatile (".word 0x62000073" ::: "memory");
    103}
    104
    105/*
    106 * Instruction encoding of hfence.gvma is:
    107 * HFENCE.VVMA rs1, rs2
    108 * HFENCE.VVMA zero, rs2
    109 * HFENCE.VVMA rs1
    110 * HFENCE.VVMA
    111 *
    112 * rs1!=zero and rs2!=zero ==> HFENCE.VVMA rs1, rs2
    113 * rs1==zero and rs2!=zero ==> HFENCE.VVMA zero, rs2
    114 * rs1!=zero and rs2==zero ==> HFENCE.VVMA rs1
    115 * rs1==zero and rs2==zero ==> HFENCE.VVMA
    116 *
    117 * Instruction encoding of HFENCE.VVMA is:
    118 * 0010001 rs2(5) rs1(5) 000 00000 1110011
    119 */
    120
    121void kvm_riscv_local_hfence_vvma_asid_gva(unsigned long vmid,
    122					  unsigned long asid,
    123					  unsigned long gva,
    124					  unsigned long gvsz,
    125					  unsigned long order)
    126{
    127	unsigned long pos, hgatp;
    128
    129	if (PTRS_PER_PTE < (gvsz >> order)) {
    130		kvm_riscv_local_hfence_vvma_asid_all(vmid, asid);
    131		return;
    132	}
    133
    134	hgatp = csr_swap(CSR_HGATP, vmid << HGATP_VMID_SHIFT);
    135
    136	for (pos = gva; pos < (gva + gvsz); pos += BIT(order)) {
    137		/*
    138		 * rs1 = a0 (GVA)
    139		 * rs2 = a1 (ASID)
    140		 * HFENCE.VVMA a0, a1
    141		 * 0010001 01011 01010 000 00000 1110011
    142		 */
    143		asm volatile ("add a0, %0, zero\n"
    144			      "add a1, %1, zero\n"
    145			      ".word 0x22b50073\n"
    146			      :: "r" (pos), "r" (asid)
    147			      : "a0", "a1", "memory");
    148	}
    149
    150	csr_write(CSR_HGATP, hgatp);
    151}
    152
    153void kvm_riscv_local_hfence_vvma_asid_all(unsigned long vmid,
    154					  unsigned long asid)
    155{
    156	unsigned long hgatp;
    157
    158	hgatp = csr_swap(CSR_HGATP, vmid << HGATP_VMID_SHIFT);
    159
    160	/*
    161	 * rs1 = zero
    162	 * rs2 = a0 (ASID)
    163	 * HFENCE.VVMA zero, a0
    164	 * 0010001 01010 00000 000 00000 1110011
    165	 */
    166	asm volatile ("add a0, %0, zero\n"
    167		      ".word 0x22a00073\n"
    168		      :: "r" (asid) : "a0", "memory");
    169
    170	csr_write(CSR_HGATP, hgatp);
    171}
    172
    173void kvm_riscv_local_hfence_vvma_gva(unsigned long vmid,
    174				     unsigned long gva, unsigned long gvsz,
    175				     unsigned long order)
    176{
    177	unsigned long pos, hgatp;
    178
    179	if (PTRS_PER_PTE < (gvsz >> order)) {
    180		kvm_riscv_local_hfence_vvma_all(vmid);
    181		return;
    182	}
    183
    184	hgatp = csr_swap(CSR_HGATP, vmid << HGATP_VMID_SHIFT);
    185
    186	for (pos = gva; pos < (gva + gvsz); pos += BIT(order)) {
    187		/*
    188		 * rs1 = a0 (GVA)
    189		 * rs2 = zero
    190		 * HFENCE.VVMA a0
    191		 * 0010001 00000 01010 000 00000 1110011
    192		 */
    193		asm volatile ("add a0, %0, zero\n"
    194			      ".word 0x22050073\n"
    195			      :: "r" (pos) : "a0", "memory");
    196	}
    197
    198	csr_write(CSR_HGATP, hgatp);
    199}
    200
    201void kvm_riscv_local_hfence_vvma_all(unsigned long vmid)
    202{
    203	unsigned long hgatp;
    204
    205	hgatp = csr_swap(CSR_HGATP, vmid << HGATP_VMID_SHIFT);
    206
    207	/*
    208	 * rs1 = zero
    209	 * rs2 = zero
    210	 * HFENCE.VVMA
    211	 * 0010001 00000 00000 000 00000 1110011
    212	 */
    213	asm volatile (".word 0x22000073" ::: "memory");
    214
    215	csr_write(CSR_HGATP, hgatp);
    216}
    217
    218void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)
    219{
    220	unsigned long vmid;
    221
    222	if (!kvm_riscv_gstage_vmid_bits() ||
    223	    vcpu->arch.last_exit_cpu == vcpu->cpu)
    224		return;
    225
    226	/*
    227	 * On RISC-V platforms with hardware VMID support, we share same
    228	 * VMID for all VCPUs of a particular Guest/VM. This means we might
    229	 * have stale G-stage TLB entries on the current Host CPU due to
    230	 * some other VCPU of the same Guest which ran previously on the
    231	 * current Host CPU.
    232	 *
    233	 * To cleanup stale TLB entries, we simply flush all G-stage TLB
    234	 * entries by VMID whenever underlying Host CPU changes for a VCPU.
    235	 */
    236
    237	vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
    238	kvm_riscv_local_hfence_gvma_vmid_all(vmid);
    239}
    240
    241void kvm_riscv_fence_i_process(struct kvm_vcpu *vcpu)
    242{
    243	local_flush_icache_all();
    244}
    245
    246void kvm_riscv_hfence_gvma_vmid_all_process(struct kvm_vcpu *vcpu)
    247{
    248	struct kvm_vmid *vmid;
    249
    250	vmid = &vcpu->kvm->arch.vmid;
    251	kvm_riscv_local_hfence_gvma_vmid_all(READ_ONCE(vmid->vmid));
    252}
    253
    254void kvm_riscv_hfence_vvma_all_process(struct kvm_vcpu *vcpu)
    255{
    256	struct kvm_vmid *vmid;
    257
    258	vmid = &vcpu->kvm->arch.vmid;
    259	kvm_riscv_local_hfence_vvma_all(READ_ONCE(vmid->vmid));
    260}
    261
    262static bool vcpu_hfence_dequeue(struct kvm_vcpu *vcpu,
    263				struct kvm_riscv_hfence *out_data)
    264{
    265	bool ret = false;
    266	struct kvm_vcpu_arch *varch = &vcpu->arch;
    267
    268	spin_lock(&varch->hfence_lock);
    269
    270	if (varch->hfence_queue[varch->hfence_head].type) {
    271		memcpy(out_data, &varch->hfence_queue[varch->hfence_head],
    272		       sizeof(*out_data));
    273		varch->hfence_queue[varch->hfence_head].type = 0;
    274
    275		varch->hfence_head++;
    276		if (varch->hfence_head == KVM_RISCV_VCPU_MAX_HFENCE)
    277			varch->hfence_head = 0;
    278
    279		ret = true;
    280	}
    281
    282	spin_unlock(&varch->hfence_lock);
    283
    284	return ret;
    285}
    286
    287static bool vcpu_hfence_enqueue(struct kvm_vcpu *vcpu,
    288				const struct kvm_riscv_hfence *data)
    289{
    290	bool ret = false;
    291	struct kvm_vcpu_arch *varch = &vcpu->arch;
    292
    293	spin_lock(&varch->hfence_lock);
    294
    295	if (!varch->hfence_queue[varch->hfence_tail].type) {
    296		memcpy(&varch->hfence_queue[varch->hfence_tail],
    297		       data, sizeof(*data));
    298
    299		varch->hfence_tail++;
    300		if (varch->hfence_tail == KVM_RISCV_VCPU_MAX_HFENCE)
    301			varch->hfence_tail = 0;
    302
    303		ret = true;
    304	}
    305
    306	spin_unlock(&varch->hfence_lock);
    307
    308	return ret;
    309}
    310
    311void kvm_riscv_hfence_process(struct kvm_vcpu *vcpu)
    312{
    313	struct kvm_riscv_hfence d = { 0 };
    314	struct kvm_vmid *v = &vcpu->kvm->arch.vmid;
    315
    316	while (vcpu_hfence_dequeue(vcpu, &d)) {
    317		switch (d.type) {
    318		case KVM_RISCV_HFENCE_UNKNOWN:
    319			break;
    320		case KVM_RISCV_HFENCE_GVMA_VMID_GPA:
    321			kvm_riscv_local_hfence_gvma_vmid_gpa(
    322						READ_ONCE(v->vmid),
    323						d.addr, d.size, d.order);
    324			break;
    325		case KVM_RISCV_HFENCE_VVMA_ASID_GVA:
    326			kvm_riscv_local_hfence_vvma_asid_gva(
    327						READ_ONCE(v->vmid), d.asid,
    328						d.addr, d.size, d.order);
    329			break;
    330		case KVM_RISCV_HFENCE_VVMA_ASID_ALL:
    331			kvm_riscv_local_hfence_vvma_asid_all(
    332						READ_ONCE(v->vmid), d.asid);
    333			break;
    334		case KVM_RISCV_HFENCE_VVMA_GVA:
    335			kvm_riscv_local_hfence_vvma_gva(
    336						READ_ONCE(v->vmid),
    337						d.addr, d.size, d.order);
    338			break;
    339		default:
    340			break;
    341		}
    342	}
    343}
    344
    345static void make_xfence_request(struct kvm *kvm,
    346				unsigned long hbase, unsigned long hmask,
    347				unsigned int req, unsigned int fallback_req,
    348				const struct kvm_riscv_hfence *data)
    349{
    350	unsigned long i;
    351	struct kvm_vcpu *vcpu;
    352	unsigned int actual_req = req;
    353	DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
    354
    355	bitmap_clear(vcpu_mask, 0, KVM_MAX_VCPUS);
    356	kvm_for_each_vcpu(i, vcpu, kvm) {
    357		if (hbase != -1UL) {
    358			if (vcpu->vcpu_id < hbase)
    359				continue;
    360			if (!(hmask & (1UL << (vcpu->vcpu_id - hbase))))
    361				continue;
    362		}
    363
    364		bitmap_set(vcpu_mask, i, 1);
    365
    366		if (!data || !data->type)
    367			continue;
    368
    369		/*
    370		 * Enqueue hfence data to VCPU hfence queue. If we don't
    371		 * have space in the VCPU hfence queue then fallback to
    372		 * a more conservative hfence request.
    373		 */
    374		if (!vcpu_hfence_enqueue(vcpu, data))
    375			actual_req = fallback_req;
    376	}
    377
    378	kvm_make_vcpus_request_mask(kvm, actual_req, vcpu_mask);
    379}
    380
    381void kvm_riscv_fence_i(struct kvm *kvm,
    382		       unsigned long hbase, unsigned long hmask)
    383{
    384	make_xfence_request(kvm, hbase, hmask, KVM_REQ_FENCE_I,
    385			    KVM_REQ_FENCE_I, NULL);
    386}
    387
    388void kvm_riscv_hfence_gvma_vmid_gpa(struct kvm *kvm,
    389				    unsigned long hbase, unsigned long hmask,
    390				    gpa_t gpa, gpa_t gpsz,
    391				    unsigned long order)
    392{
    393	struct kvm_riscv_hfence data;
    394
    395	data.type = KVM_RISCV_HFENCE_GVMA_VMID_GPA;
    396	data.asid = 0;
    397	data.addr = gpa;
    398	data.size = gpsz;
    399	data.order = order;
    400	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE,
    401			    KVM_REQ_HFENCE_GVMA_VMID_ALL, &data);
    402}
    403
    404void kvm_riscv_hfence_gvma_vmid_all(struct kvm *kvm,
    405				    unsigned long hbase, unsigned long hmask)
    406{
    407	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE_GVMA_VMID_ALL,
    408			    KVM_REQ_HFENCE_GVMA_VMID_ALL, NULL);
    409}
    410
    411void kvm_riscv_hfence_vvma_asid_gva(struct kvm *kvm,
    412				    unsigned long hbase, unsigned long hmask,
    413				    unsigned long gva, unsigned long gvsz,
    414				    unsigned long order, unsigned long asid)
    415{
    416	struct kvm_riscv_hfence data;
    417
    418	data.type = KVM_RISCV_HFENCE_VVMA_ASID_GVA;
    419	data.asid = asid;
    420	data.addr = gva;
    421	data.size = gvsz;
    422	data.order = order;
    423	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE,
    424			    KVM_REQ_HFENCE_VVMA_ALL, &data);
    425}
    426
    427void kvm_riscv_hfence_vvma_asid_all(struct kvm *kvm,
    428				    unsigned long hbase, unsigned long hmask,
    429				    unsigned long asid)
    430{
    431	struct kvm_riscv_hfence data;
    432
    433	data.type = KVM_RISCV_HFENCE_VVMA_ASID_ALL;
    434	data.asid = asid;
    435	data.addr = data.size = data.order = 0;
    436	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE,
    437			    KVM_REQ_HFENCE_VVMA_ALL, &data);
    438}
    439
    440void kvm_riscv_hfence_vvma_gva(struct kvm *kvm,
    441			       unsigned long hbase, unsigned long hmask,
    442			       unsigned long gva, unsigned long gvsz,
    443			       unsigned long order)
    444{
    445	struct kvm_riscv_hfence data;
    446
    447	data.type = KVM_RISCV_HFENCE_VVMA_GVA;
    448	data.asid = 0;
    449	data.addr = gva;
    450	data.size = gvsz;
    451	data.order = order;
    452	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE,
    453			    KVM_REQ_HFENCE_VVMA_ALL, &data);
    454}
    455
    456void kvm_riscv_hfence_vvma_all(struct kvm *kvm,
    457			       unsigned long hbase, unsigned long hmask)
    458{
    459	make_xfence_request(kvm, hbase, hmask, KVM_REQ_HFENCE_VVMA_ALL,
    460			    KVM_REQ_HFENCE_VVMA_ALL, NULL);
    461}