]>
Commit | Line | Data |
---|---|---|
c3347ed0 JF |
1 | /* |
2 | * Protected Virtualization functions | |
3 | * | |
4 | * Copyright IBM Corp. 2020 | |
5 | * Author(s): | |
6 | * Janosch Frank <frankja@linux.ibm.com> | |
7 | * | |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or (at | |
9 | * your option) any later version. See the COPYING file in the top-level | |
10 | * directory. | |
11 | */ | |
12 | #include "qemu/osdep.h" | |
13 | ||
14 | #include <linux/kvm.h> | |
15 | ||
651615d9 | 16 | #include "qapi/error.h" |
c3347ed0 JF |
17 | #include "qemu/error-report.h" |
18 | #include "sysemu/kvm.h" | |
651615d9 DG |
19 | #include "qom/object_interfaces.h" |
20 | #include "exec/confidential-guest-support.h" | |
fbc1384c | 21 | #include "hw/s390x/ipl.h" |
c3347ed0 | 22 | #include "hw/s390x/pv.h" |
75d7150c | 23 | #include "hw/s390x/sclp.h" |
03d83ecf JF |
24 | #include "target/s390x/kvm/kvm_s390x.h" |
25 | ||
26 | static bool info_valid; | |
27 | static struct kvm_s390_pv_info_vm info_vm; | |
28 | static struct kvm_s390_pv_info_dump info_dump; | |
c3347ed0 JF |
29 | |
30 | static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) | |
31 | { | |
32 | struct kvm_pv_cmd pv_cmd = { | |
33 | .cmd = cmd, | |
34 | .data = (uint64_t)data, | |
35 | }; | |
e8d12a55 CB |
36 | int rc; |
37 | ||
38 | do { | |
39 | rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); | |
40 | } while (rc == -EINTR); | |
c3347ed0 JF |
41 | |
42 | if (rc) { | |
43 | error_report("KVM PV command %d (%s) failed: header rc %x rrc %x " | |
44 | "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc, | |
45 | rc); | |
46 | } | |
47 | return rc; | |
48 | } | |
49 | ||
50 | /* | |
51 | * This macro lets us pass the command as a string to the function so | |
52 | * we can print it on an error. | |
53 | */ | |
36c182bb | 54 | #define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data) |
c3347ed0 JF |
55 | #define s390_pv_cmd_exit(cmd, data) \ |
56 | { \ | |
57 | int rc; \ | |
58 | \ | |
59 | rc = __s390_pv_cmd(cmd, #cmd, data);\ | |
60 | if (rc) { \ | |
61 | exit(1); \ | |
62 | } \ | |
63 | } | |
64 | ||
03d83ecf JF |
65 | int s390_pv_query_info(void) |
66 | { | |
67 | struct kvm_s390_pv_info info = { | |
68 | .header.id = KVM_PV_INFO_VM, | |
69 | .header.len_max = sizeof(info.header) + sizeof(info.vm), | |
70 | }; | |
71 | int rc; | |
72 | ||
73 | /* Info API's first user is dump so they are bundled */ | |
74 | if (!kvm_s390_get_protected_dump()) { | |
75 | return 0; | |
76 | } | |
77 | ||
78 | rc = s390_pv_cmd(KVM_PV_INFO, &info); | |
79 | if (rc) { | |
80 | error_report("KVM PV INFO cmd %x failed: %s", | |
81 | info.header.id, strerror(-rc)); | |
82 | return rc; | |
83 | } | |
84 | memcpy(&info_vm, &info.vm, sizeof(info.vm)); | |
85 | ||
86 | info.header.id = KVM_PV_INFO_DUMP; | |
87 | info.header.len_max = sizeof(info.header) + sizeof(info.dump); | |
88 | rc = s390_pv_cmd(KVM_PV_INFO, &info); | |
89 | if (rc) { | |
90 | error_report("KVM PV INFO cmd %x failed: %s", | |
91 | info.header.id, strerror(-rc)); | |
92 | return rc; | |
93 | } | |
94 | ||
95 | memcpy(&info_dump, &info.dump, sizeof(info.dump)); | |
96 | info_valid = true; | |
97 | ||
98 | return rc; | |
99 | } | |
100 | ||
c3347ed0 JF |
101 | int s390_pv_vm_enable(void) |
102 | { | |
103 | return s390_pv_cmd(KVM_PV_ENABLE, NULL); | |
104 | } | |
105 | ||
106 | void s390_pv_vm_disable(void) | |
107 | { | |
108 | s390_pv_cmd_exit(KVM_PV_DISABLE, NULL); | |
109 | } | |
110 | ||
111 | int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) | |
112 | { | |
113 | struct kvm_s390_pv_sec_parm args = { | |
114 | .origin = origin, | |
115 | .length = length, | |
116 | }; | |
117 | ||
118 | return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args); | |
119 | } | |
120 | ||
121 | /* | |
122 | * Called for each component in the SE type IPL parameter block 0. | |
123 | */ | |
124 | int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) | |
125 | { | |
126 | struct kvm_s390_pv_unp args = { | |
127 | .addr = addr, | |
128 | .size = size, | |
129 | .tweak = tweak, | |
130 | }; | |
131 | ||
132 | return s390_pv_cmd(KVM_PV_UNPACK, &args); | |
133 | } | |
134 | ||
9a432597 | 135 | void s390_pv_prep_reset(void) |
c3347ed0 JF |
136 | { |
137 | s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); | |
138 | } | |
139 | ||
140 | int s390_pv_verify(void) | |
141 | { | |
142 | return s390_pv_cmd(KVM_PV_VERIFY, NULL); | |
143 | } | |
144 | ||
145 | void s390_pv_unshare(void) | |
146 | { | |
147 | s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); | |
148 | } | |
fbc1384c CB |
149 | |
150 | void s390_pv_inject_reset_error(CPUState *cs) | |
151 | { | |
152 | int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; | |
153 | CPUS390XState *env = &S390_CPU(cs)->env; | |
154 | ||
155 | /* Report that we are unable to enter protected mode */ | |
156 | env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; | |
157 | } | |
651615d9 | 158 | |
03d83ecf JF |
159 | uint64_t kvm_s390_pv_dmp_get_size_cpu(void) |
160 | { | |
161 | return info_dump.dump_cpu_buffer_len; | |
162 | } | |
163 | ||
164 | uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) | |
165 | { | |
166 | return info_dump.dump_config_finalize_len; | |
167 | } | |
168 | ||
169 | uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) | |
170 | { | |
171 | return info_dump.dump_config_mem_buffer_per_1m; | |
172 | } | |
173 | ||
174 | bool kvm_s390_pv_info_basic_valid(void) | |
175 | { | |
176 | return info_valid; | |
177 | } | |
178 | ||
753ca06f JF |
179 | static int s390_pv_dump_cmd(uint64_t subcmd, uint64_t uaddr, uint64_t gaddr, |
180 | uint64_t len) | |
181 | { | |
182 | struct kvm_s390_pv_dmp dmp = { | |
183 | .subcmd = subcmd, | |
184 | .buff_addr = uaddr, | |
185 | .buff_len = len, | |
186 | .gaddr = gaddr, | |
187 | }; | |
188 | int ret; | |
189 | ||
190 | ret = s390_pv_cmd(KVM_PV_DUMP, (void *)&dmp); | |
191 | if (ret) { | |
192 | error_report("KVM DUMP command %ld failed", subcmd); | |
193 | } | |
194 | return ret; | |
195 | } | |
196 | ||
197 | int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) | |
198 | { | |
199 | struct kvm_s390_pv_dmp dmp = { | |
200 | .subcmd = KVM_PV_DUMP_CPU, | |
201 | .buff_addr = (uint64_t)buff, | |
202 | .gaddr = 0, | |
203 | .buff_len = info_dump.dump_cpu_buffer_len, | |
204 | }; | |
205 | struct kvm_pv_cmd pv = { | |
206 | .cmd = KVM_PV_DUMP, | |
207 | .data = (uint64_t)&dmp, | |
208 | }; | |
209 | ||
210 | return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_PV_CPU_COMMAND, &pv); | |
211 | } | |
212 | ||
213 | int kvm_s390_dump_init(void) | |
214 | { | |
215 | return s390_pv_dump_cmd(KVM_PV_DUMP_INIT, 0, 0, 0); | |
216 | } | |
217 | ||
218 | int kvm_s390_dump_mem_state(uint64_t gaddr, size_t len, void *dest) | |
219 | { | |
220 | return s390_pv_dump_cmd(KVM_PV_DUMP_CONFIG_STOR_STATE, (uint64_t)dest, | |
221 | gaddr, len); | |
222 | } | |
223 | ||
224 | int kvm_s390_dump_completion_data(void *buff) | |
225 | { | |
226 | return s390_pv_dump_cmd(KVM_PV_DUMP_COMPLETE, (uint64_t)buff, 0, | |
227 | info_dump.dump_config_finalize_len); | |
228 | } | |
229 | ||
651615d9 DG |
230 | #define TYPE_S390_PV_GUEST "s390-pv-guest" |
231 | OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) | |
232 | ||
233 | /** | |
234 | * S390PVGuest: | |
235 | * | |
236 | * The S390PVGuest object is basically a dummy used to tell the | |
237 | * confidential guest support system to use s390's PV mechanism. | |
238 | * | |
239 | * # $QEMU \ | |
240 | * -object s390-pv-guest,id=pv0 \ | |
241 | * -machine ...,confidential-guest-support=pv0 | |
242 | */ | |
243 | struct S390PVGuest { | |
244 | ConfidentialGuestSupport parent_obj; | |
245 | }; | |
246 | ||
247 | typedef struct S390PVGuestClass S390PVGuestClass; | |
248 | ||
249 | struct S390PVGuestClass { | |
250 | ConfidentialGuestSupportClass parent_class; | |
251 | }; | |
252 | ||
75d7150c CLG |
253 | /* |
254 | * If protected virtualization is enabled, the amount of data that the | |
255 | * Read SCP Info Service Call can use is limited to one page. The | |
256 | * available space also depends on the Extended-Length SCCB (ELS) | |
257 | * feature which can take more buffer space to store feature | |
258 | * information. This impacts the maximum number of CPUs supported in | |
259 | * the machine. | |
260 | */ | |
261 | static uint32_t s390_pv_get_max_cpus(void) | |
262 | { | |
263 | int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ? | |
264 | offsetof(ReadInfo, entries) : SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET; | |
265 | ||
266 | return (TARGET_PAGE_SIZE - offset_cpu) / sizeof(CPUEntry); | |
267 | } | |
268 | ||
269 | static bool s390_pv_check_cpus(Error **errp) | |
270 | { | |
271 | MachineState *ms = MACHINE(qdev_get_machine()); | |
272 | uint32_t pv_max_cpus = s390_pv_get_max_cpus(); | |
273 | ||
274 | if (ms->smp.max_cpus > pv_max_cpus) { | |
275 | error_setg(errp, "Protected VMs support a maximum of %d CPUs", | |
276 | pv_max_cpus); | |
277 | return false; | |
278 | } | |
279 | ||
280 | return true; | |
281 | } | |
282 | ||
283 | static bool s390_pv_guest_check(ConfidentialGuestSupport *cgs, Error **errp) | |
284 | { | |
285 | return s390_pv_check_cpus(errp); | |
286 | } | |
287 | ||
651615d9 DG |
288 | int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) |
289 | { | |
290 | if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) { | |
291 | return 0; | |
292 | } | |
293 | ||
294 | if (!s390_has_feat(S390_FEAT_UNPACK)) { | |
295 | error_setg(errp, | |
296 | "CPU model does not support Protected Virtualization"); | |
297 | return -1; | |
298 | } | |
299 | ||
75d7150c CLG |
300 | if (!s390_pv_guest_check(cgs, errp)) { |
301 | return -1; | |
302 | } | |
303 | ||
651615d9 DG |
304 | cgs->ready = true; |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
309 | OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest, | |
310 | s390_pv_guest, | |
311 | S390_PV_GUEST, | |
312 | CONFIDENTIAL_GUEST_SUPPORT, | |
313 | { TYPE_USER_CREATABLE }, | |
314 | { NULL }) | |
315 | ||
316 | static void s390_pv_guest_class_init(ObjectClass *oc, void *data) | |
317 | { | |
318 | } | |
319 | ||
320 | static void s390_pv_guest_init(Object *obj) | |
321 | { | |
322 | } | |
323 | ||
324 | static void s390_pv_guest_finalize(Object *obj) | |
325 | { | |
326 | } |