RTEMS 6.1-rc4
Loading...
Searching...
No Matches
epapr_hcalls.h
1/*
2 * ePAPR hcall interface
3 *
4 * Copyright 2008-2011 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/* A "hypercall" is an "sc 1" instruction. This header file file provides C
41 * wrapper functions for the ePAPR hypervisor interface. It is inteded
42 * for use by Linux device drivers and other operating systems.
43 *
44 * The hypercalls are implemented as inline assembly, rather than assembly
45 * language functions in a .S file, for optimization. It allows
46 * the caller to issue the hypercall instruction directly, improving both
47 * performance and memory footprint.
48 */
49
50#ifndef _EPAPR_HCALLS_H
51#define _EPAPR_HCALLS_H
52
53#include <uapi/asm/epapr_hcalls.h>
54
55#ifndef __ASSEMBLY__
56#include <sys/endian.h>
57
58/*
59 * Hypercall register clobber list
60 *
61 * These macros are used to define the list of clobbered registers during a
62 * hypercall. Technically, registers r0 and r3-r12 are always clobbered,
63 * but the gcc inline assembly syntax does not allow us to specify registers
64 * on the clobber list that are also on the input/output list. Therefore,
65 * the lists of clobbered registers depends on the number of register
66 * parmeters ("+r" and "=r") passed to the hypercall.
67 *
68 * Each assembly block should use one of the HCALL_CLOBBERSx macros. As a
69 * general rule, 'x' is the number of parameters passed to the assembly
70 * block *except* for r11.
71 *
72 * If you're not sure, just use the smallest value of 'x' that does not
73 * generate a compilation error. Because these are static inline functions,
74 * the compiler will only check the clobber list for a function if you
75 * compile code that calls that function.
76 *
77 * r3 and r11 are not included in any clobbers list because they are always
78 * listed as output registers.
79 *
80 * XER, CTR, and LR are currently listed as clobbers because it's uncertain
81 * whether they will be clobbered.
82 *
83 * Note that r11 can be used as an output parameter.
84 *
85 * The "memory" clobber is only necessary for hcalls where the Hypervisor
86 * will read or write guest memory. However, we add it to all hcalls because
87 * the impact is minimal, and we want to ensure that it's present for the
88 * hcalls that need it.
89*/
90
91/* List of common clobbered registers. Do not use this macro. */
92#define EV_HCALL_CLOBBERS "r0", "r12", "xer", "ctr", "lr", "cc", "memory"
93
94#define EV_HCALL_CLOBBERS8 EV_HCALL_CLOBBERS
95#define EV_HCALL_CLOBBERS7 EV_HCALL_CLOBBERS8, "r10"
96#define EV_HCALL_CLOBBERS6 EV_HCALL_CLOBBERS7, "r9"
97#define EV_HCALL_CLOBBERS5 EV_HCALL_CLOBBERS6, "r8"
98#define EV_HCALL_CLOBBERS4 EV_HCALL_CLOBBERS5, "r7"
99#define EV_HCALL_CLOBBERS3 EV_HCALL_CLOBBERS4, "r6"
100#define EV_HCALL_CLOBBERS2 EV_HCALL_CLOBBERS3, "r5"
101#define EV_HCALL_CLOBBERS1 EV_HCALL_CLOBBERS2, "r4"
102
103extern bool epapr_paravirt_enabled;
104extern uint32_t epapr_hypercall_start[];
105
106#ifdef CONFIG_EPAPR_PARAVIRT
107int __init epapr_paravirt_early_init(void);
108#else
109static inline int epapr_paravirt_early_init(void) { return 0; }
110#endif
111
112/*
113 * We use "uintptr_t" to define a register because it's guaranteed to be a
114 * 32-bit integer on a 32-bit platform, and a 64-bit integer on a 64-bit
115 * platform.
116 *
117 * All registers are either input/output or output only. Registers that are
118 * initialized before making the hypercall are input/output. All
119 * input/output registers are represented with "+r". Output-only registers
120 * are represented with "=r". Do not specify any unused registers. The
121 * clobber list will tell the compiler that the hypercall modifies those
122 * registers, which is good enough.
123 */
124
134static inline unsigned int ev_int_set_config(unsigned int interrupt,
135 uint32_t config, unsigned int priority, uint32_t destination)
136{
137 register uintptr_t r11 __asm__("r11");
138 register uintptr_t r3 __asm__("r3");
139 register uintptr_t r4 __asm__("r4");
140 register uintptr_t r5 __asm__("r5");
141 register uintptr_t r6 __asm__("r6");
142
143 r11 = EV_HCALL_TOKEN(EV_INT_SET_CONFIG);
144 r3 = interrupt;
145 r4 = config;
146 r5 = priority;
147 r6 = destination;
148
149 asm volatile("bl epapr_hypercall_start"
150 : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6)
151 : : EV_HCALL_CLOBBERS4
152 );
153
154 return r3;
155}
156
166static inline unsigned int ev_int_get_config(unsigned int interrupt,
167 uint32_t *config, unsigned int *priority, uint32_t *destination)
168{
169 register uintptr_t r11 __asm__("r11");
170 register uintptr_t r3 __asm__("r3");
171 register uintptr_t r4 __asm__("r4");
172 register uintptr_t r5 __asm__("r5");
173 register uintptr_t r6 __asm__("r6");
174
175 r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG);
176 r3 = interrupt;
177
178 asm volatile("bl epapr_hypercall_start"
179 : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6)
180 : : EV_HCALL_CLOBBERS4
181 );
182
183 *config = r4;
184 *priority = r5;
185 *destination = r6;
186
187 return r3;
188}
189
197static inline unsigned int ev_int_set_mask(unsigned int interrupt,
198 unsigned int mask)
199{
200 register uintptr_t r11 __asm__("r11");
201 register uintptr_t r3 __asm__("r3");
202 register uintptr_t r4 __asm__("r4");
203
204 r11 = EV_HCALL_TOKEN(EV_INT_SET_MASK);
205 r3 = interrupt;
206 r4 = mask;
207
208 asm volatile("bl epapr_hypercall_start"
209 : "+r" (r11), "+r" (r3), "+r" (r4)
210 : : EV_HCALL_CLOBBERS2
211 );
212
213 return r3;
214}
215
223static inline unsigned int ev_int_get_mask(unsigned int interrupt,
224 unsigned int *mask)
225{
226 register uintptr_t r11 __asm__("r11");
227 register uintptr_t r3 __asm__("r3");
228 register uintptr_t r4 __asm__("r4");
229
230 r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK);
231 r3 = interrupt;
232
233 asm volatile("bl epapr_hypercall_start"
234 : "+r" (r11), "+r" (r3), "=r" (r4)
235 : : EV_HCALL_CLOBBERS2
236 );
237
238 *mask = r4;
239
240 return r3;
241}
242
253static inline unsigned int ev_int_eoi(unsigned int interrupt)
254{
255 register uintptr_t r11 __asm__("r11");
256 register uintptr_t r3 __asm__("r3");
257
258 r11 = EV_HCALL_TOKEN(EV_INT_EOI);
259 r3 = interrupt;
260
261 asm volatile("bl epapr_hypercall_start"
262 : "+r" (r11), "+r" (r3)
263 : : EV_HCALL_CLOBBERS1
264 );
265
266 return r3;
267}
268
280static inline unsigned int ev_byte_channel_send(unsigned int handle,
281 unsigned int *count, const char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
282{
283 register uintptr_t r11 __asm__("r11");
284 register uintptr_t r3 __asm__("r3");
285 register uintptr_t r4 __asm__("r4");
286 register uintptr_t r5 __asm__("r5");
287 register uintptr_t r6 __asm__("r6");
288 register uintptr_t r7 __asm__("r7");
289 register uintptr_t r8 __asm__("r8");
290 const uint32_t *p = (const uint32_t *) buffer;
291
292 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_SEND);
293 r3 = handle;
294 r4 = *count;
295 r5 = be32toh(p[0]);
296 r6 = be32toh(p[1]);
297 r7 = be32toh(p[2]);
298 r8 = be32toh(p[3]);
299
300 asm volatile("bl epapr_hypercall_start"
301 : "+r" (r11), "+r" (r3),
302 "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
303 : : EV_HCALL_CLOBBERS6
304 );
305
306 *count = r4;
307
308 return r3;
309}
310
323static inline unsigned int ev_byte_channel_receive(unsigned int handle,
324 unsigned int *count, char buffer[EV_BYTE_CHANNEL_MAX_BYTES])
325{
326 register uintptr_t r11 __asm__("r11");
327 register uintptr_t r3 __asm__("r3");
328 register uintptr_t r4 __asm__("r4");
329 register uintptr_t r5 __asm__("r5");
330 register uintptr_t r6 __asm__("r6");
331 register uintptr_t r7 __asm__("r7");
332 register uintptr_t r8 __asm__("r8");
333 uint32_t *p = (uint32_t *) buffer;
334
335 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_RECEIVE);
336 r3 = handle;
337 r4 = *count;
338
339 asm volatile("bl epapr_hypercall_start"
340 : "+r" (r11), "+r" (r3), "+r" (r4),
341 "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8)
342 : : EV_HCALL_CLOBBERS6
343 );
344
345 *count = r4;
346 p[0] = htobe32(r5);
347 p[1] = htobe32(r6);
348 p[2] = htobe32(r7);
349 p[3] = htobe32(r8);
350
351 return r3;
352}
353
366static inline unsigned int ev_byte_channel_poll(unsigned int handle,
367 unsigned int *rx_count, unsigned int *tx_count)
368{
369 register uintptr_t r11 __asm__("r11");
370 register uintptr_t r3 __asm__("r3");
371 register uintptr_t r4 __asm__("r4");
372 register uintptr_t r5 __asm__("r5");
373
374 r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL);
375 r3 = handle;
376
377 asm volatile("bl epapr_hypercall_start"
378 : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5)
379 : : EV_HCALL_CLOBBERS3
380 );
381
382 *rx_count = r4;
383 *tx_count = r5;
384
385 return r3;
386}
387
400static inline unsigned int ev_int_iack(unsigned int handle,
401 unsigned int *vector)
402{
403 register uintptr_t r11 __asm__("r11");
404 register uintptr_t r3 __asm__("r3");
405 register uintptr_t r4 __asm__("r4");
406
407 r11 = EV_HCALL_TOKEN(EV_INT_IACK);
408 r3 = handle;
409
410 asm volatile("bl epapr_hypercall_start"
411 : "+r" (r11), "+r" (r3), "=r" (r4)
412 : : EV_HCALL_CLOBBERS2
413 );
414
415 *vector = r4;
416
417 return r3;
418}
419
426static inline unsigned int ev_doorbell_send(unsigned int handle)
427{
428 register uintptr_t r11 __asm__("r11");
429 register uintptr_t r3 __asm__("r3");
430
431 r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND);
432 r3 = handle;
433
434 asm volatile("bl epapr_hypercall_start"
435 : "+r" (r11), "+r" (r3)
436 : : EV_HCALL_CLOBBERS1
437 );
438
439 return r3;
440}
441
447static inline unsigned int ev_idle(void)
448{
449 register uintptr_t r11 __asm__("r11");
450 register uintptr_t r3 __asm__("r3");
451
452 r11 = EV_HCALL_TOKEN(EV_IDLE);
453
454 asm volatile("bl epapr_hypercall_start"
455 : "+r" (r11), "=r" (r3)
456 : : EV_HCALL_CLOBBERS1
457 );
458
459 return r3;
460}
461
462#ifdef CONFIG_EPAPR_PARAVIRT
463static inline unsigned long epapr_hypercall(unsigned long *in,
464 unsigned long *out,
465 unsigned long nr)
466{
467 unsigned long register r0 asm("r0");
468 unsigned long register r3 asm("r3") = in[0];
469 unsigned long register r4 asm("r4") = in[1];
470 unsigned long register r5 asm("r5") = in[2];
471 unsigned long register r6 asm("r6") = in[3];
472 unsigned long register r7 asm("r7") = in[4];
473 unsigned long register r8 asm("r8") = in[5];
474 unsigned long register r9 asm("r9") = in[6];
475 unsigned long register r10 asm("r10") = in[7];
476 unsigned long register r11 asm("r11") = nr;
477 unsigned long register r12 asm("r12");
478
479 asm volatile("bl epapr_hypercall_start"
480 : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
481 "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
482 "=r"(r12)
483 : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
484 "r"(r9), "r"(r10), "r"(r11)
485 : "memory", "cc", "xer", "ctr", "lr");
486
487 out[0] = r4;
488 out[1] = r5;
489 out[2] = r6;
490 out[3] = r7;
491 out[4] = r8;
492 out[5] = r9;
493 out[6] = r10;
494 out[7] = r11;
495
496 return r3;
497}
498#else
499static unsigned long epapr_hypercall(unsigned long *in,
500 unsigned long *out,
501 unsigned long nr)
502{
503 return EV_UNIMPLEMENTED;
504}
505#endif
506
507static inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2)
508{
509 unsigned long in[8];
510 unsigned long out[8];
511 unsigned long r;
512
513 r = epapr_hypercall(in, out, nr);
514 *r2 = out[0];
515
516 return r;
517}
518
519static inline long epapr_hypercall0(unsigned int nr)
520{
521 unsigned long in[8];
522 unsigned long out[8];
523
524 return epapr_hypercall(in, out, nr);
525}
526
527static inline long epapr_hypercall1(unsigned int nr, unsigned long p1)
528{
529 unsigned long in[8];
530 unsigned long out[8];
531
532 in[0] = p1;
533 return epapr_hypercall(in, out, nr);
534}
535
536static inline long epapr_hypercall2(unsigned int nr, unsigned long p1,
537 unsigned long p2)
538{
539 unsigned long in[8];
540 unsigned long out[8];
541
542 in[0] = p1;
543 in[1] = p2;
544 return epapr_hypercall(in, out, nr);
545}
546
547static inline long epapr_hypercall3(unsigned int nr, unsigned long p1,
548 unsigned long p2, unsigned long p3)
549{
550 unsigned long in[8];
551 unsigned long out[8];
552
553 in[0] = p1;
554 in[1] = p2;
555 in[2] = p3;
556 return epapr_hypercall(in, out, nr);
557}
558
559static inline long epapr_hypercall4(unsigned int nr, unsigned long p1,
560 unsigned long p2, unsigned long p3,
561 unsigned long p4)
562{
563 unsigned long in[8];
564 unsigned long out[8];
565
566 in[0] = p1;
567 in[1] = p2;
568 in[2] = p3;
569 in[3] = p4;
570 return epapr_hypercall(in, out, nr);
571}
572#endif /* !__ASSEMBLY__ */
573#endif /* _EPAPR_HCALLS_H */
Definition: deflate.c:114
unsigned p
Definition: tte.h:17
This header file provides interfaces of the system endianness support.