1 /* 2 * Freescale hypervisor call interface 3 * 4 * Copyright 2008-2010 Freescale Semiconductor, Inc. 5 * 6 * Author: Timur Tabi <timur@freescale.com> 7 * 8 * This file is provided under a dual BSD/GPL license. When using or 9 * redistributing this file, you may do so under either license. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions are met: 13 * * Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * * Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * * Neither the name of Freescale Semiconductor nor the 19 * names of its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * 23 * ALTERNATIVELY, this software may be distributed under the terms of the 24 * GNU General Public License ("GPL") as published by the Free Software 25 * Foundation, either version 2 of that License or (at your option) any 26 * later version. 27 * 28 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #ifndef _FSL_HCALLS_H 41 #define _FSL_HCALLS_H 42 43 #include <linux/types.h> 44 #include <linux/errno.h> 45 #include <asm/byteorder.h> 46 #include <asm/epapr_hcalls.h> 47 48 #define FH_API_VERSION 1 49 50 #define FH_ERR_GET_INFO 1 51 #define FH_PARTITION_GET_DTPROP 2 52 #define FH_PARTITION_SET_DTPROP 3 53 #define FH_PARTITION_RESTART 4 54 #define FH_PARTITION_GET_STATUS 5 55 #define FH_PARTITION_START 6 56 #define FH_PARTITION_STOP 7 57 #define FH_PARTITION_MEMCPY 8 58 #define FH_DMA_ENABLE 9 59 #define FH_DMA_DISABLE 10 60 #define FH_SEND_NMI 11 61 #define FH_VMPIC_GET_MSIR 12 62 #define FH_SYSTEM_RESET 13 63 #define FH_GET_CORE_STATE 14 64 #define FH_ENTER_NAP 15 65 #define FH_EXIT_NAP 16 66 #define FH_CLAIM_DEVICE 17 67 #define FH_PARTITION_STOP_DMA 18 68 69 /* vendor ID: Freescale Semiconductor */ 70 #define FH_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_FSL_VENDOR_ID, num) 71 72 /* 73 * We use "uintptr_t" to define a register because it's guaranteed to be a 74 * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit 75 * platform. 76 * 77 * All registers are either input/output or output only. Registers that are 78 * initialized before making the hypercall are input/output. All 79 * input/output registers are represented with "+r". Output-only registers 80 * are represented with "=r". Do not specify any unused registers. The 81 * clobber list will tell the compiler that the hypercall modifies those 82 * registers, which is good enough. 83 */ 84 85 /** 86 * fh_send_nmi - send NMI to virtual cpu(s). 87 * @vcpu_mask: send NMI to virtual cpu(s) specified by this mask. 88 * 89 * Returns 0 for success, or EINVAL for invalid vcpu_mask. 90 */ 91 static inline unsigned int fh_send_nmi(unsigned int vcpu_mask) 92 { 93 register uintptr_t r11 __asm__("r11"); 94 register uintptr_t r3 __asm__("r3"); 95 96 r11 = FH_HCALL_TOKEN(FH_SEND_NMI); 97 r3 = vcpu_mask; 98 99 __asm__ __volatile__ ("sc 1" 100 : "+r" (r11), "+r" (r3) 101 : : EV_HCALL_CLOBBERS1 102 ); 103 104 return r3; 105 } 106 107 /* Arbitrary limits to avoid excessive memory allocation in hypervisor */ 108 #define FH_DTPROP_MAX_PATHLEN 4096 109 #define FH_DTPROP_MAX_PROPLEN 32768 110 111 /** 112 * fh_partiton_get_dtprop - get a property from a guest device tree. 113 * @handle: handle of partition whose device tree is to be accessed 114 * @dtpath_addr: physical address of device tree path to access 115 * @propname_addr: physical address of name of property 116 * @propvalue_addr: physical address of property value buffer 117 * @propvalue_len: length of buffer on entry, length of property on return 118 * 119 * Returns zero on success, non-zero on error. 120 */ 121 static inline unsigned int fh_partition_get_dtprop(int handle, 122 uint64_t dtpath_addr, 123 uint64_t propname_addr, 124 uint64_t propvalue_addr, 125 uint32_t *propvalue_len) 126 { 127 register uintptr_t r11 __asm__("r11"); 128 register uintptr_t r3 __asm__("r3"); 129 register uintptr_t r4 __asm__("r4"); 130 register uintptr_t r5 __asm__("r5"); 131 register uintptr_t r6 __asm__("r6"); 132 register uintptr_t r7 __asm__("r7"); 133 register uintptr_t r8 __asm__("r8"); 134 register uintptr_t r9 __asm__("r9"); 135 register uintptr_t r10 __asm__("r10"); 136 137 r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_DTPROP); 138 r3 = handle; 139 140 #ifdef CONFIG_PHYS_64BIT 141 r4 = dtpath_addr >> 32; 142 r6 = propname_addr >> 32; 143 r8 = propvalue_addr >> 32; 144 #else 145 r4 = 0; 146 r6 = 0; 147 r8 = 0; 148 #endif 149 r5 = (uint32_t)dtpath_addr; 150 r7 = (uint32_t)propname_addr; 151 r9 = (uint32_t)propvalue_addr; 152 r10 = *propvalue_len; 153 154 __asm__ __volatile__ ("sc 1" 155 : "+r" (r11), 156 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), 157 "+r" (r8), "+r" (r9), "+r" (r10) 158 : : EV_HCALL_CLOBBERS8 159 ); 160 161 *propvalue_len = r4; 162 return r3; 163 } 164 165 /** 166 * Set a property in a guest device tree. 167 * @handle: handle of partition whose device tree is to be accessed 168 * @dtpath_addr: physical address of device tree path to access 169 * @propname_addr: physical address of name of property 170 * @propvalue_addr: physical address of property value 171 * @propvalue_len: length of property 172 * 173 * Returns zero on success, non-zero on error. 174 */ 175 static inline unsigned int fh_partition_set_dtprop(int handle, 176 uint64_t dtpath_addr, 177 uint64_t propname_addr, 178 uint64_t propvalue_addr, 179 uint32_t propvalue_len) 180 { 181 register uintptr_t r11 __asm__("r11"); 182 register uintptr_t r3 __asm__("r3"); 183 register uintptr_t r4 __asm__("r4"); 184 register uintptr_t r6 __asm__("r6"); 185 register uintptr_t r8 __asm__("r8"); 186 register uintptr_t r5 __asm__("r5"); 187 register uintptr_t r7 __asm__("r7"); 188 register uintptr_t r9 __asm__("r9"); 189 register uintptr_t r10 __asm__("r10"); 190 191 r11 = FH_HCALL_TOKEN(FH_PARTITION_SET_DTPROP); 192 r3 = handle; 193 194 #ifdef CONFIG_PHYS_64BIT 195 r4 = dtpath_addr >> 32; 196 r6 = propname_addr >> 32; 197 r8 = propvalue_addr >> 32; 198 #else 199 r4 = 0; 200 r6 = 0; 201 r8 = 0; 202 #endif 203 r5 = (uint32_t)dtpath_addr; 204 r7 = (uint32_t)propname_addr; 205 r9 = (uint32_t)propvalue_addr; 206 r10 = propvalue_len; 207 208 __asm__ __volatile__ ("sc 1" 209 : "+r" (r11), 210 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), 211 "+r" (r8), "+r" (r9), "+r" (r10) 212 : : EV_HCALL_CLOBBERS8 213 ); 214 215 return r3; 216 } 217 218 /** 219 * fh_partition_restart - reboot the current partition 220 * @partition: partition ID 221 * 222 * Returns an error code if reboot failed. Does not return if it succeeds. 223 */ 224 static inline unsigned int fh_partition_restart(unsigned int partition) 225 { 226 register uintptr_t r11 __asm__("r11"); 227 register uintptr_t r3 __asm__("r3"); 228 229 r11 = FH_HCALL_TOKEN(FH_PARTITION_RESTART); 230 r3 = partition; 231 232 __asm__ __volatile__ ("sc 1" 233 : "+r" (r11), "+r" (r3) 234 : : EV_HCALL_CLOBBERS1 235 ); 236 237 return r3; 238 } 239 240 #define FH_PARTITION_STOPPED 0 241 #define FH_PARTITION_RUNNING 1 242 #define FH_PARTITION_STARTING 2 243 #define FH_PARTITION_STOPPING 3 244 #define FH_PARTITION_PAUSING 4 245 #define FH_PARTITION_PAUSED 5 246 #define FH_PARTITION_RESUMING 6 247 248 /** 249 * fh_partition_get_status - gets the status of a partition 250 * @partition: partition ID 251 * @status: returned status code 252 * 253 * Returns 0 for success, or an error code. 254 */ 255 static inline unsigned int fh_partition_get_status(unsigned int partition, 256 unsigned int *status) 257 { 258 register uintptr_t r11 __asm__("r11"); 259 register uintptr_t r3 __asm__("r3"); 260 register uintptr_t r4 __asm__("r4"); 261 262 r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_STATUS); 263 r3 = partition; 264 265 __asm__ __volatile__ ("sc 1" 266 : "+r" (r11), "+r" (r3), "=r" (r4) 267 : : EV_HCALL_CLOBBERS2 268 ); 269 270 *status = r4; 271 272 return r3; 273 } 274 275 /** 276 * fh_partition_start - boots and starts execution of the specified partition 277 * @partition: partition ID 278 * @entry_point: guest physical address to start execution 279 * 280 * The hypervisor creates a 1-to-1 virtual/physical IMA mapping, so at boot 281 * time, guest physical address are the same as guest virtual addresses. 282 * 283 * Returns 0 for success, or an error code. 284 */ 285 static inline unsigned int fh_partition_start(unsigned int partition, 286 uint32_t entry_point, int load) 287 { 288 register uintptr_t r11 __asm__("r11"); 289 register uintptr_t r3 __asm__("r3"); 290 register uintptr_t r4 __asm__("r4"); 291 register uintptr_t r5 __asm__("r5"); 292 293 r11 = FH_HCALL_TOKEN(FH_PARTITION_START); 294 r3 = partition; 295 r4 = entry_point; 296 r5 = load; 297 298 __asm__ __volatile__ ("sc 1" 299 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5) 300 : : EV_HCALL_CLOBBERS3 301 ); 302 303 return r3; 304 } 305 306 /** 307 * fh_partition_stop - stops another partition 308 * @partition: partition ID 309 * 310 * Returns 0 for success, or an error code. 311 */ 312 static inline unsigned int fh_partition_stop(unsigned int partition) 313 { 314 register uintptr_t r11 __asm__("r11"); 315 register uintptr_t r3 __asm__("r3"); 316 317 r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP); 318 r3 = partition; 319 320 __asm__ __volatile__ ("sc 1" 321 : "+r" (r11), "+r" (r3) 322 : : EV_HCALL_CLOBBERS1 323 ); 324 325 return r3; 326 } 327 328 /** 329 * struct fh_sg_list: definition of the fh_partition_memcpy S/G list 330 * @source: guest physical address to copy from 331 * @target: guest physical address to copy to 332 * @size: number of bytes to copy 333 * @reserved: reserved, must be zero 334 * 335 * The scatter/gather list for fh_partition_memcpy() is an array of these 336 * structures. The array must be guest physically contiguous. 337 * 338 * This structure must be aligned on 32-byte boundary, so that no single 339 * strucuture can span two pages. 340 */ 341 struct fh_sg_list { 342 uint64_t source; /**< guest physical address to copy from */ 343 uint64_t target; /**< guest physical address to copy to */ 344 uint64_t size; /**< number of bytes to copy */ 345 uint64_t reserved; /**< reserved, must be zero */ 346 } __attribute__ ((aligned(32))); 347 348 /** 349 * fh_partition_memcpy - copies data from one guest to another 350 * @source: the ID of the partition to copy from 351 * @target: the ID of the partition to copy to 352 * @sg_list: guest physical address of an array of &fh_sg_list structures 353 * @count: the number of entries in @sg_list 354 * 355 * Returns 0 for success, or an error code. 356 */ 357 static inline unsigned int fh_partition_memcpy(unsigned int source, 358 unsigned int target, phys_addr_t sg_list, unsigned int count) 359 { 360 register uintptr_t r11 __asm__("r11"); 361 register uintptr_t r3 __asm__("r3"); 362 register uintptr_t r4 __asm__("r4"); 363 register uintptr_t r5 __asm__("r5"); 364 register uintptr_t r6 __asm__("r6"); 365 register uintptr_t r7 __asm__("r7"); 366 367 r11 = FH_HCALL_TOKEN(FH_PARTITION_MEMCPY); 368 r3 = source; 369 r4 = target; 370 r5 = (uint32_t) sg_list; 371 372 #ifdef CONFIG_PHYS_64BIT 373 r6 = sg_list >> 32; 374 #else 375 r6 = 0; 376 #endif 377 r7 = count; 378 379 __asm__ __volatile__ ("sc 1" 380 : "+r" (r11), 381 "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7) 382 : : EV_HCALL_CLOBBERS5 383 ); 384 385 return r3; 386 } 387 388 /** 389 * fh_dma_enable - enable DMA for the specified device 390 * @liodn: the LIODN of the I/O device for which to enable DMA 391 * 392 * Returns 0 for success, or an error code. 393 */ 394 static inline unsigned int fh_dma_enable(unsigned int liodn) 395 { 396 register uintptr_t r11 __asm__("r11"); 397 register uintptr_t r3 __asm__("r3"); 398 399 r11 = FH_HCALL_TOKEN(FH_DMA_ENABLE); 400 r3 = liodn; 401 402 __asm__ __volatile__ ("sc 1" 403 : "+r" (r11), "+r" (r3) 404 : : EV_HCALL_CLOBBERS1 405 ); 406 407 return r3; 408 } 409 410 /** 411 * fh_dma_disable - disable DMA for the specified device 412 * @liodn: the LIODN of the I/O device for which to disable DMA 413 * 414 * Returns 0 for success, or an error code. 415 */ 416 static inline unsigned int fh_dma_disable(unsigned int liodn) 417 { 418 register uintptr_t r11 __asm__("r11"); 419 register uintptr_t r3 __asm__("r3"); 420 421 r11 = FH_HCALL_TOKEN(FH_DMA_DISABLE); 422 r3 = liodn; 423 424 __asm__ __volatile__ ("sc 1" 425 : "+r" (r11), "+r" (r3) 426 : : EV_HCALL_CLOBBERS1 427 ); 428 429 return r3; 430 } 431 432 433 /** 434 * fh_vmpic_get_msir - returns the MPIC-MSI register value 435 * @interrupt: the interrupt number 436 * @msir_val: returned MPIC-MSI register value 437 * 438 * Returns 0 for success, or an error code. 439 */ 440 static inline unsigned int fh_vmpic_get_msir(unsigned int interrupt, 441 unsigned int *msir_val) 442 { 443 register uintptr_t r11 __asm__("r11"); 444 register uintptr_t r3 __asm__("r3"); 445 register uintptr_t r4 __asm__("r4"); 446 447 r11 = FH_HCALL_TOKEN(FH_VMPIC_GET_MSIR); 448 r3 = interrupt; 449 450 __asm__ __volatile__ ("sc 1" 451 : "+r" (r11), "+r" (r3), "=r" (r4) 452 : : EV_HCALL_CLOBBERS2 453 ); 454 455 *msir_val = r4; 456 457 return r3; 458 } 459 460 /** 461 * fh_system_reset - reset the system 462 * 463 * Returns 0 for success, or an error code. 464 */ 465 static inline unsigned int fh_system_reset(void) 466 { 467 register uintptr_t r11 __asm__("r11"); 468 register uintptr_t r3 __asm__("r3"); 469 470 r11 = FH_HCALL_TOKEN(FH_SYSTEM_RESET); 471 472 __asm__ __volatile__ ("sc 1" 473 : "+r" (r11), "=r" (r3) 474 : : EV_HCALL_CLOBBERS1 475 ); 476 477 return r3; 478 } 479 480 481 /** 482 * fh_err_get_info - get platform error information 483 * @queue id: 484 * 0 for guest error event queue 485 * 1 for global error event queue 486 * 487 * @pointer to store the platform error data: 488 * platform error data is returned in registers r4 - r11 489 * 490 * Returns 0 for success, or an error code. 491 */ 492 static inline unsigned int fh_err_get_info(int queue, uint32_t *bufsize, 493 uint32_t addr_hi, uint32_t addr_lo, int peek) 494 { 495 register uintptr_t r11 __asm__("r11"); 496 register uintptr_t r3 __asm__("r3"); 497 register uintptr_t r4 __asm__("r4"); 498 register uintptr_t r5 __asm__("r5"); 499 register uintptr_t r6 __asm__("r6"); 500 register uintptr_t r7 __asm__("r7"); 501 502 r11 = FH_HCALL_TOKEN(FH_ERR_GET_INFO); 503 r3 = queue; 504 r4 = *bufsize; 505 r5 = addr_hi; 506 r6 = addr_lo; 507 r7 = peek; 508 509 __asm__ __volatile__ ("sc 1" 510 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), 511 "+r" (r7) 512 : : EV_HCALL_CLOBBERS5 513 ); 514 515 *bufsize = r4; 516 517 return r3; 518 } 519 520 521 #define FH_VCPU_RUN 0 522 #define FH_VCPU_IDLE 1 523 #define FH_VCPU_NAP 2 524 525 /** 526 * fh_get_core_state - get the state of a vcpu 527 * 528 * @handle: handle of partition containing the vcpu 529 * @vcpu: vcpu number within the partition 530 * @state:the current state of the vcpu, see FH_VCPU_* 531 * 532 * Returns 0 for success, or an error code. 533 */ 534 static inline unsigned int fh_get_core_state(unsigned int handle, 535 unsigned int vcpu, unsigned int *state) 536 { 537 register uintptr_t r11 __asm__("r11"); 538 register uintptr_t r3 __asm__("r3"); 539 register uintptr_t r4 __asm__("r4"); 540 541 r11 = FH_HCALL_TOKEN(FH_GET_CORE_STATE); 542 r3 = handle; 543 r4 = vcpu; 544 545 __asm__ __volatile__ ("sc 1" 546 : "+r" (r11), "+r" (r3), "+r" (r4) 547 : : EV_HCALL_CLOBBERS2 548 ); 549 550 *state = r4; 551 return r3; 552 } 553 554 /** 555 * fh_enter_nap - enter nap on a vcpu 556 * 557 * Note that though the API supports entering nap on a vcpu other 558 * than the caller, this may not be implmented and may return EINVAL. 559 * 560 * @handle: handle of partition containing the vcpu 561 * @vcpu: vcpu number within the partition 562 * 563 * Returns 0 for success, or an error code. 564 */ 565 static inline unsigned int fh_enter_nap(unsigned int handle, unsigned int vcpu) 566 { 567 register uintptr_t r11 __asm__("r11"); 568 register uintptr_t r3 __asm__("r3"); 569 register uintptr_t r4 __asm__("r4"); 570 571 r11 = FH_HCALL_TOKEN(FH_ENTER_NAP); 572 r3 = handle; 573 r4 = vcpu; 574 575 __asm__ __volatile__ ("sc 1" 576 : "+r" (r11), "+r" (r3), "+r" (r4) 577 : : EV_HCALL_CLOBBERS2 578 ); 579 580 return r3; 581 } 582 583 /** 584 * fh_exit_nap - exit nap on a vcpu 585 * @handle: handle of partition containing the vcpu 586 * @vcpu: vcpu number within the partition 587 * 588 * Returns 0 for success, or an error code. 589 */ 590 static inline unsigned int fh_exit_nap(unsigned int handle, unsigned int vcpu) 591 { 592 register uintptr_t r11 __asm__("r11"); 593 register uintptr_t r3 __asm__("r3"); 594 register uintptr_t r4 __asm__("r4"); 595 596 r11 = FH_HCALL_TOKEN(FH_EXIT_NAP); 597 r3 = handle; 598 r4 = vcpu; 599 600 __asm__ __volatile__ ("sc 1" 601 : "+r" (r11), "+r" (r3), "+r" (r4) 602 : : EV_HCALL_CLOBBERS2 603 ); 604 605 return r3; 606 } 607 /** 608 * fh_claim_device - claim a "claimable" shared device 609 * @handle: fsl,hv-device-handle of node to claim 610 * 611 * Returns 0 for success, or an error code. 612 */ 613 static inline unsigned int fh_claim_device(unsigned int handle) 614 { 615 register uintptr_t r11 __asm__("r11"); 616 register uintptr_t r3 __asm__("r3"); 617 618 r11 = FH_HCALL_TOKEN(FH_CLAIM_DEVICE); 619 r3 = handle; 620 621 __asm__ __volatile__ ("sc 1" 622 : "+r" (r11), "+r" (r3) 623 : : EV_HCALL_CLOBBERS1 624 ); 625 626 return r3; 627 } 628 629 /** 630 * Run deferred DMA disabling on a partition's private devices 631 * 632 * This applies to devices which a partition owns either privately, 633 * or which are claimable and still actively owned by that partition, 634 * and which do not have the no-dma-disable property. 635 * 636 * @handle: partition (must be stopped) whose DMA is to be disabled 637 * 638 * Returns 0 for success, or an error code. 639 */ 640 static inline unsigned int fh_partition_stop_dma(unsigned int handle) 641 { 642 register uintptr_t r11 __asm__("r11"); 643 register uintptr_t r3 __asm__("r3"); 644 645 r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP_DMA); 646 r3 = handle; 647 648 __asm__ __volatile__ ("sc 1" 649 : "+r" (r11), "+r" (r3) 650 : : EV_HCALL_CLOBBERS1 651 ); 652 653 return r3; 654 } 655 #endif 656