1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include "asm/hvcall.h" |
4 | #include <linux/log2.h> |
5 | #include <asm/pgalloc.h> |
6 | #include <asm/guest-state-buffer.h> |
7 | |
8 | static const u16 kvmppc_gse_iden_len[__KVMPPC_GSE_TYPE_MAX] = { |
9 | [KVMPPC_GSE_BE32] = sizeof(__be32), |
10 | [KVMPPC_GSE_BE64] = sizeof(__be64), |
11 | [KVMPPC_GSE_VEC128] = sizeof(vector128), |
12 | [KVMPPC_GSE_PARTITION_TABLE] = sizeof(struct kvmppc_gs_part_table), |
13 | [KVMPPC_GSE_PROCESS_TABLE] = sizeof(struct kvmppc_gs_proc_table), |
14 | [KVMPPC_GSE_BUFFER] = sizeof(struct kvmppc_gs_buff_info), |
15 | }; |
16 | |
17 | /** |
18 | * kvmppc_gsb_new() - create a new guest state buffer |
19 | * @size: total size of the guest state buffer (includes header) |
20 | * @guest_id: guest_id |
21 | * @vcpu_id: vcpu_id |
22 | * @flags: GFP flags |
23 | * |
24 | * Returns a guest state buffer. |
25 | */ |
26 | struct kvmppc_gs_buff *kvmppc_gsb_new(size_t size, unsigned long guest_id, |
27 | unsigned long vcpu_id, gfp_t flags) |
28 | { |
29 | struct kvmppc_gs_buff *gsb; |
30 | |
31 | gsb = kzalloc(sizeof(*gsb), flags); |
32 | if (!gsb) |
33 | return NULL; |
34 | |
35 | size = roundup_pow_of_two(size); |
36 | gsb->hdr = kzalloc(size, GFP_KERNEL); |
37 | if (!gsb->hdr) |
38 | goto free; |
39 | |
40 | gsb->capacity = size; |
41 | gsb->len = sizeof(struct kvmppc_gs_header); |
42 | gsb->vcpu_id = vcpu_id; |
43 | gsb->guest_id = guest_id; |
44 | |
45 | gsb->hdr->nelems = cpu_to_be32(0); |
46 | |
47 | return gsb; |
48 | |
49 | free: |
50 | kfree(objp: gsb); |
51 | return NULL; |
52 | } |
53 | EXPORT_SYMBOL_GPL(kvmppc_gsb_new); |
54 | |
55 | /** |
56 | * kvmppc_gsb_free() - free a guest state buffer |
57 | * @gsb: guest state buffer |
58 | */ |
59 | void kvmppc_gsb_free(struct kvmppc_gs_buff *gsb) |
60 | { |
61 | kfree(objp: gsb->hdr); |
62 | kfree(objp: gsb); |
63 | } |
64 | EXPORT_SYMBOL_GPL(kvmppc_gsb_free); |
65 | |
66 | /** |
67 | * kvmppc_gsb_put() - allocate space in a guest state buffer |
68 | * @gsb: buffer to allocate in |
69 | * @size: amount of space to allocate |
70 | * |
71 | * Returns a pointer to the amount of space requested within the buffer and |
72 | * increments the count of elements in the buffer. |
73 | * |
74 | * Does not check if there is enough space in the buffer. |
75 | */ |
76 | void *kvmppc_gsb_put(struct kvmppc_gs_buff *gsb, size_t size) |
77 | { |
78 | u32 nelems = kvmppc_gsb_nelems(gsb); |
79 | void *p; |
80 | |
81 | p = (void *)kvmppc_gsb_header(gsb) + kvmppc_gsb_len(gsb); |
82 | gsb->len += size; |
83 | |
84 | kvmppc_gsb_header(gsb)->nelems = cpu_to_be32(nelems + 1); |
85 | return p; |
86 | } |
87 | EXPORT_SYMBOL_GPL(kvmppc_gsb_put); |
88 | |
89 | static int kvmppc_gsid_class(u16 iden) |
90 | { |
91 | if ((iden >= KVMPPC_GSE_GUESTWIDE_START) && |
92 | (iden <= KVMPPC_GSE_GUESTWIDE_END)) |
93 | return KVMPPC_GS_CLASS_GUESTWIDE; |
94 | |
95 | if ((iden >= KVMPPC_GSE_META_START) && (iden <= KVMPPC_GSE_META_END)) |
96 | return KVMPPC_GS_CLASS_META; |
97 | |
98 | if ((iden >= KVMPPC_GSE_DW_REGS_START) && |
99 | (iden <= KVMPPC_GSE_DW_REGS_END)) |
100 | return KVMPPC_GS_CLASS_DWORD_REG; |
101 | |
102 | if ((iden >= KVMPPC_GSE_W_REGS_START) && |
103 | (iden <= KVMPPC_GSE_W_REGS_END)) |
104 | return KVMPPC_GS_CLASS_WORD_REG; |
105 | |
106 | if ((iden >= KVMPPC_GSE_VSRS_START) && (iden <= KVMPPC_GSE_VSRS_END)) |
107 | return KVMPPC_GS_CLASS_VECTOR; |
108 | |
109 | if ((iden >= KVMPPC_GSE_INTR_REGS_START) && |
110 | (iden <= KVMPPC_GSE_INTR_REGS_END)) |
111 | return KVMPPC_GS_CLASS_INTR; |
112 | |
113 | return -1; |
114 | } |
115 | |
116 | static int kvmppc_gsid_type(u16 iden) |
117 | { |
118 | int type = -1; |
119 | |
120 | switch (kvmppc_gsid_class(iden)) { |
121 | case KVMPPC_GS_CLASS_GUESTWIDE: |
122 | switch (iden) { |
123 | case KVMPPC_GSID_HOST_STATE_SIZE: |
124 | case KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE: |
125 | case KVMPPC_GSID_TB_OFFSET: |
126 | type = KVMPPC_GSE_BE64; |
127 | break; |
128 | case KVMPPC_GSID_PARTITION_TABLE: |
129 | type = KVMPPC_GSE_PARTITION_TABLE; |
130 | break; |
131 | case KVMPPC_GSID_PROCESS_TABLE: |
132 | type = KVMPPC_GSE_PROCESS_TABLE; |
133 | break; |
134 | case KVMPPC_GSID_LOGICAL_PVR: |
135 | type = KVMPPC_GSE_BE32; |
136 | break; |
137 | } |
138 | break; |
139 | case KVMPPC_GS_CLASS_META: |
140 | switch (iden) { |
141 | case KVMPPC_GSID_RUN_INPUT: |
142 | case KVMPPC_GSID_RUN_OUTPUT: |
143 | type = KVMPPC_GSE_BUFFER; |
144 | break; |
145 | case KVMPPC_GSID_VPA: |
146 | type = KVMPPC_GSE_BE64; |
147 | break; |
148 | } |
149 | break; |
150 | case KVMPPC_GS_CLASS_DWORD_REG: |
151 | type = KVMPPC_GSE_BE64; |
152 | break; |
153 | case KVMPPC_GS_CLASS_WORD_REG: |
154 | type = KVMPPC_GSE_BE32; |
155 | break; |
156 | case KVMPPC_GS_CLASS_VECTOR: |
157 | type = KVMPPC_GSE_VEC128; |
158 | break; |
159 | case KVMPPC_GS_CLASS_INTR: |
160 | switch (iden) { |
161 | case KVMPPC_GSID_HDAR: |
162 | case KVMPPC_GSID_ASDR: |
163 | case KVMPPC_GSID_HEIR: |
164 | type = KVMPPC_GSE_BE64; |
165 | break; |
166 | case KVMPPC_GSID_HDSISR: |
167 | type = KVMPPC_GSE_BE32; |
168 | break; |
169 | } |
170 | break; |
171 | } |
172 | |
173 | return type; |
174 | } |
175 | |
176 | /** |
177 | * kvmppc_gsid_flags() - the flags for a guest state ID |
178 | * @iden: guest state ID |
179 | * |
180 | * Returns any flags for the guest state ID. |
181 | */ |
182 | unsigned long kvmppc_gsid_flags(u16 iden) |
183 | { |
184 | unsigned long flags = 0; |
185 | |
186 | switch (kvmppc_gsid_class(iden)) { |
187 | case KVMPPC_GS_CLASS_GUESTWIDE: |
188 | flags = KVMPPC_GS_FLAGS_WIDE; |
189 | break; |
190 | case KVMPPC_GS_CLASS_META: |
191 | case KVMPPC_GS_CLASS_DWORD_REG: |
192 | case KVMPPC_GS_CLASS_WORD_REG: |
193 | case KVMPPC_GS_CLASS_VECTOR: |
194 | case KVMPPC_GS_CLASS_INTR: |
195 | break; |
196 | } |
197 | |
198 | return flags; |
199 | } |
200 | EXPORT_SYMBOL_GPL(kvmppc_gsid_flags); |
201 | |
202 | /** |
203 | * kvmppc_gsid_size() - the size of a guest state ID |
204 | * @iden: guest state ID |
205 | * |
206 | * Returns the size of guest state ID. |
207 | */ |
208 | u16 kvmppc_gsid_size(u16 iden) |
209 | { |
210 | int type; |
211 | |
212 | type = kvmppc_gsid_type(iden); |
213 | if (type == -1) |
214 | return 0; |
215 | |
216 | if (type >= __KVMPPC_GSE_TYPE_MAX) |
217 | return 0; |
218 | |
219 | return kvmppc_gse_iden_len[type]; |
220 | } |
221 | EXPORT_SYMBOL_GPL(kvmppc_gsid_size); |
222 | |
223 | /** |
224 | * kvmppc_gsid_mask() - the settable bits of a guest state ID |
225 | * @iden: guest state ID |
226 | * |
227 | * Returns a mask of settable bits for a guest state ID. |
228 | */ |
229 | u64 kvmppc_gsid_mask(u16 iden) |
230 | { |
231 | u64 mask = ~0ull; |
232 | |
233 | switch (iden) { |
234 | case KVMPPC_GSID_LPCR: |
235 | mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER | |
236 | LPCR_GTSE; |
237 | break; |
238 | case KVMPPC_GSID_MSR: |
239 | mask = ~(MSR_HV | MSR_S | MSR_ME); |
240 | break; |
241 | } |
242 | |
243 | return mask; |
244 | } |
245 | EXPORT_SYMBOL_GPL(kvmppc_gsid_mask); |
246 | |
247 | /** |
248 | * __kvmppc_gse_put() - add a guest state element to a buffer |
249 | * @gsb: buffer to the element to |
250 | * @iden: guest state ID |
251 | * @size: length of data |
252 | * @data: pointer to data |
253 | */ |
254 | int __kvmppc_gse_put(struct kvmppc_gs_buff *gsb, u16 iden, u16 size, |
255 | const void *data) |
256 | { |
257 | struct kvmppc_gs_elem *gse; |
258 | u16 total_size; |
259 | |
260 | total_size = sizeof(*gse) + size; |
261 | if (total_size + kvmppc_gsb_len(gsb) > kvmppc_gsb_capacity(gsb)) |
262 | return -ENOMEM; |
263 | |
264 | if (kvmppc_gsid_size(iden) != size) |
265 | return -EINVAL; |
266 | |
267 | gse = kvmppc_gsb_put(gsb, total_size); |
268 | gse->iden = cpu_to_be16(iden); |
269 | gse->len = cpu_to_be16(size); |
270 | memcpy(gse->data, data, size); |
271 | |
272 | return 0; |
273 | } |
274 | EXPORT_SYMBOL_GPL(__kvmppc_gse_put); |
275 | |
276 | /** |
277 | * kvmppc_gse_parse() - create a parse map from a guest state buffer |
278 | * @gsp: guest state parser |
279 | * @gsb: guest state buffer |
280 | */ |
281 | int kvmppc_gse_parse(struct kvmppc_gs_parser *gsp, struct kvmppc_gs_buff *gsb) |
282 | { |
283 | struct kvmppc_gs_elem *curr; |
284 | int rem, i; |
285 | |
286 | kvmppc_gsb_for_each_elem(i, curr, gsb, rem) { |
287 | if (kvmppc_gse_len(curr) != |
288 | kvmppc_gsid_size(kvmppc_gse_iden(curr))) |
289 | return -EINVAL; |
290 | kvmppc_gsp_insert(gsp, kvmppc_gse_iden(curr), curr); |
291 | } |
292 | |
293 | if (kvmppc_gsb_nelems(gsb) != i) |
294 | return -EINVAL; |
295 | return 0; |
296 | } |
297 | EXPORT_SYMBOL_GPL(kvmppc_gse_parse); |
298 | |
299 | static inline int kvmppc_gse_flatten_iden(u16 iden) |
300 | { |
301 | int bit = 0; |
302 | int class; |
303 | |
304 | class = kvmppc_gsid_class(iden); |
305 | |
306 | if (class == KVMPPC_GS_CLASS_GUESTWIDE) { |
307 | bit += iden - KVMPPC_GSE_GUESTWIDE_START; |
308 | return bit; |
309 | } |
310 | |
311 | bit += KVMPPC_GSE_GUESTWIDE_COUNT; |
312 | |
313 | if (class == KVMPPC_GS_CLASS_META) { |
314 | bit += iden - KVMPPC_GSE_META_START; |
315 | return bit; |
316 | } |
317 | |
318 | bit += KVMPPC_GSE_META_COUNT; |
319 | |
320 | if (class == KVMPPC_GS_CLASS_DWORD_REG) { |
321 | bit += iden - KVMPPC_GSE_DW_REGS_START; |
322 | return bit; |
323 | } |
324 | |
325 | bit += KVMPPC_GSE_DW_REGS_COUNT; |
326 | |
327 | if (class == KVMPPC_GS_CLASS_WORD_REG) { |
328 | bit += iden - KVMPPC_GSE_W_REGS_START; |
329 | return bit; |
330 | } |
331 | |
332 | bit += KVMPPC_GSE_W_REGS_COUNT; |
333 | |
334 | if (class == KVMPPC_GS_CLASS_VECTOR) { |
335 | bit += iden - KVMPPC_GSE_VSRS_START; |
336 | return bit; |
337 | } |
338 | |
339 | bit += KVMPPC_GSE_VSRS_COUNT; |
340 | |
341 | if (class == KVMPPC_GS_CLASS_INTR) { |
342 | bit += iden - KVMPPC_GSE_INTR_REGS_START; |
343 | return bit; |
344 | } |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static inline u16 kvmppc_gse_unflatten_iden(int bit) |
350 | { |
351 | u16 iden; |
352 | |
353 | if (bit < KVMPPC_GSE_GUESTWIDE_COUNT) { |
354 | iden = KVMPPC_GSE_GUESTWIDE_START + bit; |
355 | return iden; |
356 | } |
357 | bit -= KVMPPC_GSE_GUESTWIDE_COUNT; |
358 | |
359 | if (bit < KVMPPC_GSE_META_COUNT) { |
360 | iden = KVMPPC_GSE_META_START + bit; |
361 | return iden; |
362 | } |
363 | bit -= KVMPPC_GSE_META_COUNT; |
364 | |
365 | if (bit < KVMPPC_GSE_DW_REGS_COUNT) { |
366 | iden = KVMPPC_GSE_DW_REGS_START + bit; |
367 | return iden; |
368 | } |
369 | bit -= KVMPPC_GSE_DW_REGS_COUNT; |
370 | |
371 | if (bit < KVMPPC_GSE_W_REGS_COUNT) { |
372 | iden = KVMPPC_GSE_W_REGS_START + bit; |
373 | return iden; |
374 | } |
375 | bit -= KVMPPC_GSE_W_REGS_COUNT; |
376 | |
377 | if (bit < KVMPPC_GSE_VSRS_COUNT) { |
378 | iden = KVMPPC_GSE_VSRS_START + bit; |
379 | return iden; |
380 | } |
381 | bit -= KVMPPC_GSE_VSRS_COUNT; |
382 | |
383 | if (bit < KVMPPC_GSE_IDEN_COUNT) { |
384 | iden = KVMPPC_GSE_INTR_REGS_START + bit; |
385 | return iden; |
386 | } |
387 | |
388 | return 0; |
389 | } |
390 | |
391 | /** |
392 | * kvmppc_gsp_insert() - add a mapping from an guest state ID to an element |
393 | * @gsp: guest state parser |
394 | * @iden: guest state id (key) |
395 | * @gse: guest state element (value) |
396 | */ |
397 | void kvmppc_gsp_insert(struct kvmppc_gs_parser *gsp, u16 iden, |
398 | struct kvmppc_gs_elem *gse) |
399 | { |
400 | int i; |
401 | |
402 | i = kvmppc_gse_flatten_iden(iden); |
403 | kvmppc_gsbm_set(&gsp->iterator, iden); |
404 | gsp->gses[i] = gse; |
405 | } |
406 | EXPORT_SYMBOL_GPL(kvmppc_gsp_insert); |
407 | |
408 | /** |
409 | * kvmppc_gsp_lookup() - lookup an element from a guest state ID |
410 | * @gsp: guest state parser |
411 | * @iden: guest state ID (key) |
412 | * |
413 | * Returns the guest state element if present. |
414 | */ |
415 | struct kvmppc_gs_elem *kvmppc_gsp_lookup(struct kvmppc_gs_parser *gsp, u16 iden) |
416 | { |
417 | int i; |
418 | |
419 | i = kvmppc_gse_flatten_iden(iden); |
420 | return gsp->gses[i]; |
421 | } |
422 | EXPORT_SYMBOL_GPL(kvmppc_gsp_lookup); |
423 | |
424 | /** |
425 | * kvmppc_gsbm_set() - set the guest state ID |
426 | * @gsbm: guest state bitmap |
427 | * @iden: guest state ID |
428 | */ |
429 | void kvmppc_gsbm_set(struct kvmppc_gs_bitmap *gsbm, u16 iden) |
430 | { |
431 | set_bit(nr: kvmppc_gse_flatten_iden(iden), addr: gsbm->bitmap); |
432 | } |
433 | EXPORT_SYMBOL_GPL(kvmppc_gsbm_set); |
434 | |
435 | /** |
436 | * kvmppc_gsbm_clear() - clear the guest state ID |
437 | * @gsbm: guest state bitmap |
438 | * @iden: guest state ID |
439 | */ |
440 | void kvmppc_gsbm_clear(struct kvmppc_gs_bitmap *gsbm, u16 iden) |
441 | { |
442 | clear_bit(nr: kvmppc_gse_flatten_iden(iden), addr: gsbm->bitmap); |
443 | } |
444 | EXPORT_SYMBOL_GPL(kvmppc_gsbm_clear); |
445 | |
446 | /** |
447 | * kvmppc_gsbm_test() - test the guest state ID |
448 | * @gsbm: guest state bitmap |
449 | * @iden: guest state ID |
450 | */ |
451 | bool kvmppc_gsbm_test(struct kvmppc_gs_bitmap *gsbm, u16 iden) |
452 | { |
453 | return test_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); |
454 | } |
455 | EXPORT_SYMBOL_GPL(kvmppc_gsbm_test); |
456 | |
457 | /** |
458 | * kvmppc_gsbm_next() - return the next set guest state ID |
459 | * @gsbm: guest state bitmap |
460 | * @prev: last guest state ID |
461 | */ |
462 | u16 kvmppc_gsbm_next(struct kvmppc_gs_bitmap *gsbm, u16 prev) |
463 | { |
464 | int bit, pbit; |
465 | |
466 | pbit = prev ? kvmppc_gse_flatten_iden(iden: prev) + 1 : 0; |
467 | bit = find_next_bit(gsbm->bitmap, KVMPPC_GSE_IDEN_COUNT, pbit); |
468 | |
469 | if (bit < KVMPPC_GSE_IDEN_COUNT) |
470 | return kvmppc_gse_unflatten_iden(bit); |
471 | return 0; |
472 | } |
473 | EXPORT_SYMBOL_GPL(kvmppc_gsbm_next); |
474 | |
475 | /** |
476 | * kvmppc_gsm_init() - initialize a guest state message |
477 | * @gsm: guest state message |
478 | * @ops: callbacks |
479 | * @data: private data |
480 | * @flags: guest wide or thread wide |
481 | */ |
482 | int kvmppc_gsm_init(struct kvmppc_gs_msg *gsm, struct kvmppc_gs_msg_ops *ops, |
483 | void *data, unsigned long flags) |
484 | { |
485 | memset(gsm, 0, sizeof(*gsm)); |
486 | gsm->ops = ops; |
487 | gsm->data = data; |
488 | gsm->flags = flags; |
489 | |
490 | return 0; |
491 | } |
492 | EXPORT_SYMBOL_GPL(kvmppc_gsm_init); |
493 | |
494 | /** |
495 | * kvmppc_gsm_new() - creates a new guest state message |
496 | * @ops: callbacks |
497 | * @data: private data |
498 | * @flags: guest wide or thread wide |
499 | * @gfp_flags: GFP allocation flags |
500 | * |
501 | * Returns an initialized guest state message. |
502 | */ |
503 | struct kvmppc_gs_msg *kvmppc_gsm_new(struct kvmppc_gs_msg_ops *ops, void *data, |
504 | unsigned long flags, gfp_t gfp_flags) |
505 | { |
506 | struct kvmppc_gs_msg *gsm; |
507 | |
508 | gsm = kzalloc(sizeof(*gsm), gfp_flags); |
509 | if (!gsm) |
510 | return NULL; |
511 | |
512 | kvmppc_gsm_init(gsm, ops, data, flags); |
513 | |
514 | return gsm; |
515 | } |
516 | EXPORT_SYMBOL_GPL(kvmppc_gsm_new); |
517 | |
518 | /** |
519 | * kvmppc_gsm_size() - creates a new guest state message |
520 | * @gsm: self |
521 | * |
522 | * Returns the size required for the message. |
523 | */ |
524 | size_t kvmppc_gsm_size(struct kvmppc_gs_msg *gsm) |
525 | { |
526 | if (gsm->ops->get_size) |
527 | return gsm->ops->get_size(gsm); |
528 | return 0; |
529 | } |
530 | EXPORT_SYMBOL_GPL(kvmppc_gsm_size); |
531 | |
532 | /** |
533 | * kvmppc_gsm_free() - free guest state message |
534 | * @gsm: guest state message |
535 | * |
536 | * Returns the size required for the message. |
537 | */ |
538 | void kvmppc_gsm_free(struct kvmppc_gs_msg *gsm) |
539 | { |
540 | kfree(objp: gsm); |
541 | } |
542 | EXPORT_SYMBOL_GPL(kvmppc_gsm_free); |
543 | |
544 | /** |
545 | * kvmppc_gsm_fill_info() - serialises message to guest state buffer format |
546 | * @gsm: self |
547 | * @gsb: buffer to serialise into |
548 | */ |
549 | int kvmppc_gsm_fill_info(struct kvmppc_gs_msg *gsm, struct kvmppc_gs_buff *gsb) |
550 | { |
551 | if (!gsm->ops->fill_info) |
552 | return -EINVAL; |
553 | |
554 | return gsm->ops->fill_info(gsb, gsm); |
555 | } |
556 | EXPORT_SYMBOL_GPL(kvmppc_gsm_fill_info); |
557 | |
558 | /** |
559 | * kvmppc_gsm_refresh_info() - deserialises from guest state buffer |
560 | * @gsm: self |
561 | * @gsb: buffer to serialise from |
562 | */ |
563 | int kvmppc_gsm_refresh_info(struct kvmppc_gs_msg *gsm, |
564 | struct kvmppc_gs_buff *gsb) |
565 | { |
566 | if (!gsm->ops->fill_info) |
567 | return -EINVAL; |
568 | |
569 | return gsm->ops->refresh_info(gsm, gsb); |
570 | } |
571 | EXPORT_SYMBOL_GPL(kvmppc_gsm_refresh_info); |
572 | |
573 | /** |
574 | * kvmppc_gsb_send - send all elements in the buffer to the hypervisor. |
575 | * @gsb: guest state buffer |
576 | * @flags: guest wide or thread wide |
577 | * |
578 | * Performs the H_GUEST_SET_STATE hcall for the guest state buffer. |
579 | */ |
580 | int kvmppc_gsb_send(struct kvmppc_gs_buff *gsb, unsigned long flags) |
581 | { |
582 | unsigned long hflags = 0; |
583 | unsigned long i; |
584 | int rc; |
585 | |
586 | if (kvmppc_gsb_nelems(gsb) == 0) |
587 | return 0; |
588 | |
589 | if (flags & KVMPPC_GS_FLAGS_WIDE) |
590 | hflags |= H_GUEST_FLAGS_WIDE; |
591 | |
592 | rc = plpar_guest_set_state(hflags, gsb->guest_id, gsb->vcpu_id, |
593 | __pa(gsb->hdr), gsb->capacity, &i); |
594 | return rc; |
595 | } |
596 | EXPORT_SYMBOL_GPL(kvmppc_gsb_send); |
597 | |
598 | /** |
599 | * kvmppc_gsb_recv - request all elements in the buffer have their value |
600 | * updated. |
601 | * @gsb: guest state buffer |
602 | * @flags: guest wide or thread wide |
603 | * |
604 | * Performs the H_GUEST_GET_STATE hcall for the guest state buffer. |
605 | * After returning from the hcall the guest state elements that were |
606 | * present in the buffer will have updated values from the hypervisor. |
607 | */ |
608 | int kvmppc_gsb_recv(struct kvmppc_gs_buff *gsb, unsigned long flags) |
609 | { |
610 | unsigned long hflags = 0; |
611 | unsigned long i; |
612 | int rc; |
613 | |
614 | if (flags & KVMPPC_GS_FLAGS_WIDE) |
615 | hflags |= H_GUEST_FLAGS_WIDE; |
616 | |
617 | rc = plpar_guest_get_state(hflags, gsb->guest_id, gsb->vcpu_id, |
618 | __pa(gsb->hdr), gsb->capacity, &i); |
619 | return rc; |
620 | } |
621 | EXPORT_SYMBOL_GPL(kvmppc_gsb_recv); |
622 | |