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 8static 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 */ 26struct 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 49free: 50 kfree(gsb); 51 return NULL; 52} 53EXPORT_SYMBOL_GPL(kvmppc_gsb_new); 54 55/** 56 * kvmppc_gsb_free() - free a guest state buffer 57 * @gsb: guest state buffer 58 */ 59void kvmppc_gsb_free(struct kvmppc_gs_buff *gsb) 60{ 61 kfree(gsb->hdr); 62 kfree(gsb); 63} 64EXPORT_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 */ 76void *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} 87EXPORT_SYMBOL_GPL(kvmppc_gsb_put); 88 89static 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 116static 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 */ 182unsigned 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} 200EXPORT_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 */ 208u16 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} 221EXPORT_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 */ 229u64 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} 245EXPORT_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 */ 254int __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} 274EXPORT_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 */ 281int 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} 297EXPORT_SYMBOL_GPL(kvmppc_gse_parse); 298 299static 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 349static 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 */ 397void 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} 406EXPORT_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 */ 415struct 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} 422EXPORT_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 */ 429void kvmppc_gsbm_set(struct kvmppc_gs_bitmap *gsbm, u16 iden) 430{ 431 set_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); 432} 433EXPORT_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 */ 440void kvmppc_gsbm_clear(struct kvmppc_gs_bitmap *gsbm, u16 iden) 441{ 442 clear_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); 443} 444EXPORT_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 */ 451bool kvmppc_gsbm_test(struct kvmppc_gs_bitmap *gsbm, u16 iden) 452{ 453 return test_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); 454} 455EXPORT_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 */ 462u16 kvmppc_gsbm_next(struct kvmppc_gs_bitmap *gsbm, u16 prev) 463{ 464 int bit, pbit; 465 466 pbit = prev ? kvmppc_gse_flatten_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} 473EXPORT_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 */ 482int 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} 492EXPORT_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 */ 503struct 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} 516EXPORT_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 */ 524size_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} 530EXPORT_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 */ 538void kvmppc_gsm_free(struct kvmppc_gs_msg *gsm) 539{ 540 kfree(gsm); 541} 542EXPORT_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 */ 549int 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} 556EXPORT_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 */ 563int 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} 571EXPORT_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 */ 580int 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} 596EXPORT_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 */ 608int 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} 621EXPORT_SYMBOL_GPL(kvmppc_gsb_recv); 622