RTEMS  5.1
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 
103 extern bool epapr_paravirt_enabled;
104 extern uint32_t epapr_hypercall_start[];
105 
106 #ifdef CONFIG_EPAPR_PARAVIRT
107 int __init epapr_paravirt_early_init(void);
108 #else
109 static 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 
134 static 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 
166 static 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 
197 static 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 
223 static 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 
253 static 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 
280 static 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 
323 static 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 
366 static 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 
400 static 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 
426 static 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 
447 static 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
463 static 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
499 static unsigned long epapr_hypercall(unsigned long *in,
500  unsigned long *out,
501  unsigned long nr)
502 {
503  return EV_UNIMPLEMENTED;
504 }
505 #endif
506 
507 static 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 
519 static 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 
527 static 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 
536 static 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 
547 static 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 
559 static 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:115
unsigned p
Definition: tte.h:90
register struct Per_CPU_Control *_SPARC_Per_CPU_current __asm__("g6")
The pointer to the current per-CPU control is available via register g6.