Import changeset
[linux-flexiantxendom0-3.2.10.git] / arch / parisc / kernel / real1.c
1 /*
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
8  *
9  * most of these calls might reasonably be moved to ../kernel -PB
10  *
11  * The basic principle is to construct a stack frame in C then call
12  * some assembly which adopts that stack, does some rfi magic, may
13  * switch wide/narrow mode, and calls the routine described by the
14  * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!!
15  */
16 #include <linux/spinlock.h>
17 #include <asm/system.h>
18 #include <stdarg.h>
19 #include <asm/pgtable.h>                /* for __pa() */
20 #include <asm/pdc.h>
21
22 static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
23
24 /***************** 32-bit real-mode calls ***********/
25 /* The struct below is used
26  * to overlay real_stack (real2.S), preparing a 32-bit call frame.
27  * real32_call_asm() then uses this stack in narrow real mode
28  */
29
30 struct narrow_stack {
31     /* use int, not long which is 64 bits */
32     unsigned int arg13;
33     unsigned int arg12;
34     unsigned int arg11;
35     unsigned int arg10;
36     unsigned int arg9;
37     unsigned int arg8;
38     unsigned int arg7;
39     unsigned int arg6;
40     unsigned int arg5;
41     unsigned int arg4;
42     unsigned int arg3;
43     unsigned int arg2;
44     unsigned int arg1;
45     unsigned int arg0;
46     unsigned int frame_marker[8];
47     unsigned int sp;
48     /* in reality, there's nearly 8k of stack after this */
49 };
50
51 long
52 real32_call(unsigned long fn, ...)
53 {
54     unsigned long r;
55     va_list args;
56     unsigned long flags;
57     extern struct narrow_stack real_stack;
58     extern unsigned long real32_call_asm(unsigned int *,
59                                 unsigned int *, unsigned int);
60     
61     va_start(args, fn);
62     real_stack.arg0 = va_arg(args, unsigned int);
63     real_stack.arg1 = va_arg(args, unsigned int);
64     real_stack.arg2 = va_arg(args, unsigned int);
65     real_stack.arg3 = va_arg(args, unsigned int);
66     real_stack.arg4 = va_arg(args, unsigned int);
67     real_stack.arg5 = va_arg(args, unsigned int);
68     real_stack.arg6 = va_arg(args, unsigned int);
69     real_stack.arg7 = va_arg(args, unsigned int);
70     real_stack.arg8 = va_arg(args, unsigned int);
71     real_stack.arg9 = va_arg(args, unsigned int);
72     real_stack.arg10 = va_arg(args, unsigned int);
73     real_stack.arg11 = va_arg(args, unsigned int);
74     real_stack.arg12 = va_arg(args, unsigned int);
75     real_stack.arg13 = va_arg(args, unsigned int);
76     va_end(args);
77
78     if (fn == 0) {
79             /* mem_pdc call */
80             fn = PAGE0->mem_pdc;
81     }
82
83     spin_lock_irqsave(&pdc_lock, flags);
84     r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
85     spin_unlock_irqrestore(&pdc_lock, flags);
86
87     return r;
88 }
89
90 #ifdef __LP64__
91 /***************** 64-bit real-mode calls ***********/
92
93 struct wide_stack {
94     unsigned long arg0;
95     unsigned long arg1;
96     unsigned long arg2;
97     unsigned long arg3;
98     unsigned long arg4;
99     unsigned long arg5;
100     unsigned long arg6;
101     unsigned long arg7;
102     unsigned long arg8;
103     unsigned long arg9;
104     unsigned long arg10;
105     unsigned long arg11;
106     unsigned long arg12;
107     unsigned long arg13;
108     unsigned long frame_marker[2];      /* rp, previous sp */
109     unsigned long sp;
110     /* in reality, there's nearly 8k of stack after this */
111 };
112
113 long
114 real64_call(unsigned long fn, ...)
115 {
116     unsigned long r;
117     va_list args;
118     unsigned long flags;
119     extern struct wide_stack real_stack;
120     extern unsigned long real64_call_asm(unsigned long *,
121                                 unsigned long *, unsigned long);
122     
123     va_start(args, fn);
124     real_stack.arg0 = va_arg(args, unsigned long);
125     real_stack.arg1 = va_arg(args, unsigned long);
126     real_stack.arg2 = va_arg(args, unsigned long);
127     real_stack.arg3 = va_arg(args, unsigned long);
128     real_stack.arg4 = va_arg(args, unsigned long);
129     real_stack.arg5 = va_arg(args, unsigned long);
130     real_stack.arg6 = va_arg(args, unsigned long);
131     real_stack.arg7 = va_arg(args, unsigned long);
132     real_stack.arg8 = va_arg(args, unsigned long);
133     real_stack.arg9 = va_arg(args, unsigned long);
134     real_stack.arg10 = va_arg(args, unsigned long);
135     real_stack.arg11 = va_arg(args, unsigned long);
136     real_stack.arg12 = va_arg(args, unsigned long);
137     real_stack.arg13 = va_arg(args, unsigned long);
138     va_end(args);
139
140     if (fn == 0) {
141             /* mem_pdc call */
142             fn = PAGE0->mem_pdc_hi;
143             fn <<= 32;
144             fn |= PAGE0->mem_pdc;
145     }
146
147     spin_lock_irqsave(&pdc_lock, flags);
148     r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
149     spin_unlock_irqrestore(&pdc_lock, flags);
150
151     return r;
152 }
153
154 #endif