File: /usr/src/linux/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
155