Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/riscv/kvm/main.c
50372 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
4
*
5
* Authors:
6
* Anup Patel <[email protected]>
7
*/
8
9
#include <linux/errno.h>
10
#include <linux/err.h>
11
#include <linux/module.h>
12
#include <linux/kvm_host.h>
13
#include <asm/cpufeature.h>
14
#include <asm/kvm_mmu.h>
15
#include <asm/kvm_nacl.h>
16
#include <asm/sbi.h>
17
18
DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
19
20
static void kvm_riscv_setup_vendor_features(void)
21
{
22
/* Andes AX66: split two-stage TLBs */
23
if (riscv_cached_mvendorid(0) == ANDES_VENDOR_ID &&
24
(riscv_cached_marchid(0) & 0xFFFF) == 0x8A66) {
25
static_branch_enable(&kvm_riscv_vsstage_tlb_no_gpa);
26
kvm_info("VS-stage TLB does not cache guest physical address and VMID\n");
27
}
28
}
29
30
long kvm_arch_dev_ioctl(struct file *filp,
31
unsigned int ioctl, unsigned long arg)
32
{
33
return -EINVAL;
34
}
35
36
int kvm_arch_enable_virtualization_cpu(void)
37
{
38
int rc;
39
40
rc = kvm_riscv_nacl_enable();
41
if (rc)
42
return rc;
43
44
csr_write(CSR_HEDELEG, KVM_HEDELEG_DEFAULT);
45
csr_write(CSR_HIDELEG, KVM_HIDELEG_DEFAULT);
46
47
/* VS should access only the time counter directly. Everything else should trap */
48
csr_write(CSR_HCOUNTEREN, 0x02);
49
50
csr_write(CSR_HVIP, 0);
51
52
kvm_riscv_aia_enable();
53
54
return 0;
55
}
56
57
void kvm_arch_disable_virtualization_cpu(void)
58
{
59
kvm_riscv_aia_disable();
60
61
/*
62
* After clearing the hideleg CSR, the host kernel will receive
63
* spurious interrupts if hvip CSR has pending interrupts and the
64
* corresponding enable bits in vsie CSR are asserted. To avoid it,
65
* hvip CSR and vsie CSR must be cleared before clearing hideleg CSR.
66
*/
67
csr_write(CSR_VSIE, 0);
68
csr_write(CSR_HVIP, 0);
69
csr_write(CSR_HEDELEG, 0);
70
csr_write(CSR_HIDELEG, 0);
71
72
kvm_riscv_nacl_disable();
73
}
74
75
static void kvm_riscv_teardown(void)
76
{
77
kvm_riscv_aia_exit();
78
kvm_riscv_nacl_exit();
79
kvm_unregister_perf_callbacks();
80
}
81
82
static int __init riscv_kvm_init(void)
83
{
84
int rc;
85
char slist[64];
86
const char *str;
87
88
if (!riscv_isa_extension_available(NULL, h)) {
89
kvm_info("hypervisor extension not available\n");
90
return -ENODEV;
91
}
92
93
if (sbi_spec_is_0_1()) {
94
kvm_info("require SBI v0.2 or higher\n");
95
return -ENODEV;
96
}
97
98
if (!sbi_probe_extension(SBI_EXT_RFENCE)) {
99
kvm_info("require SBI RFENCE extension\n");
100
return -ENODEV;
101
}
102
103
rc = kvm_riscv_nacl_init();
104
if (rc && rc != -ENODEV)
105
return rc;
106
107
kvm_riscv_gstage_mode_detect();
108
switch (kvm_riscv_gstage_mode) {
109
case HGATP_MODE_SV32X4:
110
str = "Sv32x4";
111
break;
112
case HGATP_MODE_SV39X4:
113
str = "Sv39x4";
114
break;
115
case HGATP_MODE_SV48X4:
116
str = "Sv48x4";
117
break;
118
case HGATP_MODE_SV57X4:
119
str = "Sv57x4";
120
break;
121
default:
122
kvm_riscv_nacl_exit();
123
return -ENODEV;
124
}
125
126
kvm_riscv_gstage_vmid_detect();
127
128
rc = kvm_riscv_aia_init();
129
if (rc && rc != -ENODEV) {
130
kvm_riscv_nacl_exit();
131
return rc;
132
}
133
134
kvm_info("hypervisor extension available\n");
135
136
if (kvm_riscv_nacl_available()) {
137
rc = 0;
138
slist[0] = '\0';
139
if (kvm_riscv_nacl_sync_csr_available()) {
140
if (rc)
141
strcat(slist, ", ");
142
strcat(slist, "sync_csr");
143
rc++;
144
}
145
if (kvm_riscv_nacl_sync_hfence_available()) {
146
if (rc)
147
strcat(slist, ", ");
148
strcat(slist, "sync_hfence");
149
rc++;
150
}
151
if (kvm_riscv_nacl_sync_sret_available()) {
152
if (rc)
153
strcat(slist, ", ");
154
strcat(slist, "sync_sret");
155
rc++;
156
}
157
if (kvm_riscv_nacl_autoswap_csr_available()) {
158
if (rc)
159
strcat(slist, ", ");
160
strcat(slist, "autoswap_csr");
161
rc++;
162
}
163
kvm_info("using SBI nested acceleration with %s\n",
164
(rc) ? slist : "no features");
165
}
166
167
kvm_info("using %s G-stage page table format\n", str);
168
169
kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits());
170
171
if (kvm_riscv_aia_available())
172
kvm_info("AIA available with %d guest external interrupts\n",
173
kvm_riscv_aia_nr_hgei);
174
175
kvm_riscv_setup_vendor_features();
176
177
kvm_register_perf_callbacks(NULL);
178
179
rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
180
if (rc) {
181
kvm_riscv_teardown();
182
return rc;
183
}
184
185
return 0;
186
}
187
module_init(riscv_kvm_init);
188
189
static void __exit riscv_kvm_exit(void)
190
{
191
kvm_exit();
192
193
kvm_riscv_teardown();
194
}
195
module_exit(riscv_kvm_exit);
196
197