Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / client.c
1 /*
2  *   Creation Date: <2003/11/25 14:29:08 samuel>
3  *   Time-stamp: <2004/03/27 01:13:53 samuel>
4  *
5  *      <client.c>
6  *
7  *      OpenFirmware client interface
8  *
9  *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "libopenbios/of.h"
20
21 /* Uncomment to enable debug printout of client interface calls */
22 //#define DEBUG_CIF
23 //#define DUMP_IO
24
25 /* OF client interface. r3 points to the argument array. On return,
26  * r3 should contain 0==true or -1==false. r4-r12,cr0,cr1 may
27  * be modified freely.
28  *
29  * -1 should only be returned if the control transfer to OF fails
30  * (it doesn't) or if the function is unimplemented.
31  */
32
33 #define PROM_MAX_ARGS   10
34 typedef struct prom_args {
35     prom_uarg_t service;
36     prom_arg_t  nargs;
37     prom_arg_t  nret;
38     prom_uarg_t args[PROM_MAX_ARGS];
39 } __attribute__((packed)) prom_args_t;
40
41 static inline const char *
42 arg2pointer(prom_uarg_t value)
43 {
44     return (char*)(uintptr_t)value;
45 }
46
47 static inline const char *
48 get_service(prom_args_t *pb)
49 {
50     return arg2pointer(pb->service);
51 }
52
53 #ifdef DEBUG_CIF
54 static void memdump(const char *mem, unsigned long size)
55 {
56         int i;
57         
58         if (size == (unsigned long) -1)
59                 return;
60
61         for (i = 0; i < size; i += 16) {
62                 int j;
63
64                 printk("0x%08lx ", (unsigned long)mem + i);
65
66                 for (j = 0; j < 16 && i + j < size; j++)
67                         printk(" %02x", *(unsigned char*)(mem + i + j));
68
69                 for ( ; j < 16; j++)
70                         printk(" __");
71
72                 printk("  ");
73
74                 for (j = 0; j < 16 && i + j < size; j++) {
75                         unsigned char c = *(mem + i + j);
76                         if (isprint(c))
77                                 printk("%c", c);
78                         else
79                                 printk(".");
80                 }
81                 printk("\n");
82         }
83 }
84
85 static void dump_service(prom_args_t *pb)
86 {
87         int i;
88         const char *service = get_service(pb);
89         if (strcmp(service, "test") == 0) {
90                 printk("test(\"%s\") = ", arg2pointer(pb->args[0]));
91         } else if (strcmp(service, "peer") == 0) {
92                 printk("peer(0x" FMT_prom_uargx ") = ", pb->args[0]);
93         } else if (strcmp(service, "child") == 0) {
94                 printk("child(0x" FMT_prom_uargx ") = ", pb->args[0]);
95         } else if (strcmp(service, "parent") == 0) {
96                 printk("parent(0x" FMT_prom_uargx ") = ", pb->args[0]);
97         } else if (strcmp(service, "instance-to-package") == 0) {
98                 printk("instance-to-package(0x" FMT_prom_uargx ") = ", pb->args[0]);
99         } else if (strcmp(service, "getproplen") == 0) {
100                 printk("getproplen(0x" FMT_prom_uargx ", \"%s\") = ",
101                         pb->args[0], arg2pointer(pb->args[1]));
102         } else if (strcmp(service, "getprop") == 0) {
103                 printk("getprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
104                         pb->args[0], arg2pointer(pb->args[1]),
105                         pb->args[2], pb->args[3]);
106         } else if (strcmp(service, "nextprop") == 0) {
107                 printk("nextprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ") = ",
108                         pb->args[0], arg2pointer(pb->args[1]), pb->args[2]);
109         } else if (strcmp(service, "setprop") == 0) {
110                 printk("setprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
111                         pb->args[0], arg2pointer(pb->args[1]),
112                         pb->args[2], pb->args[3]);
113                 memdump(arg2pointer(pb->args[2]), pb->args[3]);
114                 printk(" = ");
115         } else if (strcmp(service, "canon") == 0) {
116                 printk("canon(\"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
117                         arg2pointer(pb->args[0]), pb->args[1], pb->args[2]);
118         } else if (strcmp(service, "finddevice") == 0) {
119                 printk("finddevice(\"%s\") = ", arg2pointer(pb->args[0]));
120         } else if (strcmp(service, "instance-to-path") == 0) {
121                 printk("instance-to-path(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
122                         pb->args[0], pb->args[1], pb->args[2]);
123         } else if (strcmp(service, "package-to-path") == 0) {
124                 printk("package-to-path(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
125                         pb->args[0], pb->args[1], pb->args[2]);
126         } else if (strcmp(service, "open") == 0) {
127                 printk("open(\"%s\") = ", arg2pointer(pb->args[0]));
128         } else if (strcmp(service, "close") == 0) {
129                 printk("close(0x" FMT_prom_uargx ")\n", pb->args[0]);
130         } else if (strcmp(service, "read") == 0) {
131 #ifdef DUMP_IO
132                 printk("read(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
133                         pb->args[0], pb->args[1], pb->args[2]);
134 #endif
135         } else if (strcmp(service, "write") == 0) {
136 #ifdef DUMP_IO
137                 printk("write(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
138                         pb->args[0], pb->args[1], pb->args[2]);
139                 memdump(arg2pointer(pb->args[1]), pb->args[2]);
140                 printk(" = ");
141 #endif
142         } else if (strcmp(service, "seek") == 0) {
143 #ifdef DUMP_IO
144                 printk("seek(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ") = ",
145                         pb->args[0], pb->args[1], pb->args[2]);
146 #endif
147         } else if (strcmp(service, "claim") == 0) {
148                 printk("claim(0x" FMT_prom_uargx ", " FMT_prom_arg ", " FMT_prom_arg ") = ",
149                         pb->args[0], pb->args[1], pb->args[2]);
150         } else if (strcmp(service, "release") == 0) {
151                 printk("release(0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
152                         pb->args[0], pb->args[1]);
153         } else if (strcmp(service, "boot") == 0) {
154                 printk("boot \"%s\"\n", arg2pointer(pb->args[0]));
155         } else if (strcmp(service, "enter") == 0) {
156                 printk("enter()\n");
157         } else if (strcmp(service, "exit") == 0) {
158                 printk("exit()\n");
159         } else if (strcmp(service, "test-method") == 0) {
160                 printk("test-method(0x" FMT_prom_uargx ", \"%s\") = ",
161                         pb->args[0], arg2pointer(pb->args[1]));
162         } else {
163                 printk("of_client_interface: %s", service);
164                 for( i = 0; i < pb->nargs; i++ )
165                         printk(" " FMT_prom_uargx, pb->args[i]);
166                 printk("\n");
167         }
168 }
169
170 static void dump_return(prom_args_t *pb)
171 {
172         int i;
173         const char *service = get_service(pb);
174         if (strcmp(service, "test") == 0) {
175                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
176         } else if (strcmp(service, "peer") == 0) {
177                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
178         } else if (strcmp(service, "child") == 0) {
179                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
180         } else if (strcmp(service, "parent") == 0) {
181                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
182         } else if (strcmp(service, "instance-to-package") == 0) {
183                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
184         } else if (strcmp(service, "getproplen") == 0) {
185                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
186         } else if (strcmp(service, "getprop") == 0) {
187                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
188                 if ((prom_arg_t)pb->args[pb->nargs] != -1)
189                         memdump(arg2pointer(pb->args[2]), MIN(pb->args[3], pb->args[pb->nargs]));
190         } else if (strcmp(service, "nextprop") == 0) {
191                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
192                 memdump(arg2pointer(pb->args[2]), 32);
193         } else if (strcmp(service, "setprop") == 0) {
194                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
195         } else if (strcmp(service, "canon") == 0) {
196                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
197                 memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
198         } else if (strcmp(service, "finddevice") == 0) {
199                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
200         } else if (strcmp(service, "instance-to-path") == 0) {
201                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
202                 memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
203         } else if (strcmp(service, "package-to-path") == 0) {
204                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
205                 memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
206         } else if (strcmp(service, "open") == 0) {
207                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
208         } else if (strcmp(service, "close") == 0) {
209                 /* do nothing */
210         } else if (strcmp(service, "read") == 0) {
211 #ifdef DUMP_IO
212                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
213                 memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
214 #endif
215         } else if (strcmp(service, "write") == 0) {
216 #ifdef DUMP_IO
217                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
218 #endif
219         } else if (strcmp(service, "seek") == 0) {
220 #ifdef DUMP_IO
221                 printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
222 #endif
223         } else if (strcmp(service, "claim") == 0) {
224                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
225         } else if (strcmp(service, "release") == 0) {
226                 /* do nothing */
227         } else if (strcmp(service, "boot") == 0) {
228                 /* do nothing */
229         } else if (strcmp(service, "enter") == 0) {
230                 /* do nothing */
231         } else if (strcmp(service, "exit") == 0) {
232                 /* do nothing */
233         } else if (strcmp(service, "test-method") == 0) {
234                 printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
235         } else {
236                 printk("of_client_interface return:");
237                 for (i = 0; i < pb->nret; i++) {
238                         printk(" " FMT_prom_uargx, pb->args[pb->nargs + i]);
239                 }
240                 printk("\n");
241         }
242 }
243 #endif
244
245 /* call-method, interpret */
246 static int
247 handle_calls(prom_args_t *pb)
248 {
249         int i, j, dstacksave;
250         ucell val;
251
252 #ifdef DEBUG_CIF
253         printk("%s %s ([" FMT_prom_arg "] -- [" FMT_prom_arg "])\n",
254                 get_service(pb), arg2pointer(pb->args[0]), pb->nargs, pb->nret);
255 #endif
256
257         dstacksave = dstackcnt;
258         for (i = pb->nargs - 1; i >= 0; i--)
259                 PUSH(pb->args[i]);
260
261         push_str(get_service(pb));
262         fword("client-call-iface");
263
264         /* Ignore client-call-iface return */
265         POP();
266
267         /* If the catch result is non-zero, restore stack and exit */
268         val = POP();
269         if (val) {
270                 printk("%s %s failed with error " FMT_ucellx "\n", get_service(pb), arg2pointer(pb->args[0]), val);
271                 dstackcnt = dstacksave;
272                 return 0;
273         }
274
275         /* Store catch result */
276         pb->args[pb->nargs] = val;
277         
278         j = dstackcnt;
279         for (i = 1; i < pb->nret; i++, j--) {
280                 if (dstackcnt > dstacksave) {
281                         pb->args[pb->nargs + i] = POP();
282                 }
283         }
284
285 #ifdef DEBUG_CIF
286         /* useful for debug but not necessarily an error */
287         if (j != dstacksave) {
288                 printk("%s '%s': possible argument error (" FMT_prom_arg "--" FMT_prom_arg ") got %d\n",
289                         get_service(pb), arg2pointer(pb->args[0]),
290                         pb->nargs - 2, pb->nret, j - dstacksave);
291         }
292
293         printk("handle_calls return:");
294         for (i = 0; i < pb->nret; i++) {
295                 printk(" " FMT_prom_uargx, pb->args[pb->nargs + i]);
296         }
297         printk("\n");
298 #endif
299
300         dstackcnt = dstacksave;
301         return 0;
302 }
303
304 int
305 of_client_interface(int *params)
306 {
307         prom_args_t *pb = (prom_args_t*)params;
308         ucell val;
309         int i, j, dstacksave;
310
311         if (pb->nargs < 0 || pb->nret < 0 ||
312             pb->nargs + pb->nret > PROM_MAX_ARGS)
313                 return -1;
314
315 #ifdef DEBUG_CIF
316         dump_service(pb);
317 #endif
318
319         /* call-method exceptions are special */
320         if (!strcmp("call-method", get_service(pb)) || !strcmp("interpret", get_service(pb)))
321                 return handle_calls(pb);
322
323         dstacksave = dstackcnt;
324         for (i = pb->nargs - 1; i >= 0; i--)
325                 PUSH(pb->args[i]);
326
327         push_str(get_service(pb));
328         fword("client-iface");
329
330         val = POP();
331         if (val) {
332                 if (val == -1) {
333                         printk("Unimplemented service %s ([" FMT_prom_arg "] -- [" FMT_prom_arg "])\n",
334                                 get_service(pb), pb->nargs, pb->nret);
335                 } else {
336 #ifdef DEBUG_CIF
337                         printk("Error calling client interface: " FMT_ucellx "\n", val);
338 #endif
339                 }
340
341                 dstackcnt = dstacksave;
342                 return -1;
343         }
344
345         j = dstackcnt;
346         for (i = 0; i < pb->nret; i++, j--) {
347                 if (dstackcnt > dstacksave) {
348                         pb->args[pb->nargs + i] = POP();
349                 }
350         }
351
352 #ifdef DEBUG_CIF
353         if (j != dstacksave) {
354                 printk("service %s: possible argument error (%d %d)\n",
355                        get_service(pb), i, j - dstacksave);
356
357                 /* Some clients request less parameters than the CIF method
358                 returns, e.g. getprop with OpenSolaris. Hence we drop any
359                 stack parameters on exit after issuing a warning above */
360         }
361
362         dump_return(pb);
363 #endif
364
365         dstackcnt = dstacksave;
366         return 0;
367 }