Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc32 / romvec.c
1 /*
2  * PROM interface support
3  * Copyright 1996 The Australian National University.
4  * Copyright 1996 Fujitsu Laboratories Limited
5  * Copyright 1999 Pete A. Zaitcev
6  * This software may be distributed under the terms of the Gnu
7  * Public License version 2 or later
8  */
9
10 #include <stdarg.h>
11
12 #include "openprom.h"
13 #include "config.h"
14 #include "libopenbios/bindings.h"
15 #include "drivers/drivers.h"
16 #include "libopenbios/sys_info.h"
17 #include "boot.h"
18 #include "romvec.h"
19
20 #ifdef CONFIG_DEBUG_OBP
21 #define DPRINTF(fmt, args...)                   \
22     do { printk(fmt , ##args); } while (0)
23 #else
24 #define DPRINTF(fmt, args...)
25 #endif
26
27 char obp_stdin, obp_stdout;
28 const char *obp_stdin_path, *obp_stdout_path;
29
30 struct linux_arguments_v0 obp_arg;
31 const char *bootpath;
32 static const struct linux_arguments_v0 * const obp_argp = &obp_arg;
33
34 static void (*sync_hook)(void);
35
36 static struct linux_romvec romvec0;
37
38 static void doublewalk(__attribute__((unused)) unsigned int ptab1,
39                        __attribute__((unused)) unsigned int va)
40 {
41 }
42
43 int obp_nextnode(int node)
44 {
45     int peer;
46
47     PUSH(node);
48     fword("peer");
49     peer = POP();
50     DPRINTF("obp_nextnode(0x%x) = 0x%x\n", node, peer);
51
52     return peer;
53 }
54
55 int obp_child(int node)
56 {
57     int child;
58
59     PUSH(node);
60     fword("child");
61     child = POP();
62     DPRINTF("obp_child(0x%x) = 0x%x\n", node, child);
63
64     return child;
65 }
66
67 int obp_proplen(int node, const char *name)
68 {
69     int notfound;
70
71     if (!node) {
72         DPRINTF("obp_proplen(0x0, %s) = -1\n", name);
73         return -1;
74     }
75
76     push_str(name);
77     PUSH(node);
78     fword("get-package-property");
79     notfound = POP();
80
81     if (notfound) {
82         DPRINTF("obp_proplen(0x%x, %s) (not found)\n", node, name);
83
84         return -1;
85     } else {
86         int len;
87
88         len = POP();
89         (void) POP();
90         DPRINTF("obp_proplen(0x%x, %s) = %d\n", node, name, len);
91
92         return len;
93     }
94 }
95
96 #ifdef CONFIG_DEBUG_OBP
97 static int looks_like_string(const char *str, int len)
98 {
99     int i;
100     int ret = (str[len-1] == '\0');
101     for (i = 0; i < len-1 && ret; i++)
102     {
103         int ch = str[i] & 0xFF;
104         if (ch < 0x20 || ch > 0x7F)
105             ret = 0;
106     }
107     return ret;
108 }
109 #endif
110
111 int obp_getprop(int node, const char *name, char *value)
112 {
113     int notfound, found;
114     int len;
115     const char *str;
116
117     if (!node) {
118         DPRINTF("obp_getprop(0x0, %s) = -1\n", name);
119         return -1;
120     }
121
122     if (!name) {
123         // NULL name means get first property
124         push_str("");
125         PUSH(node);
126         fword("next-property");
127         found = POP();
128         if (found) {
129             len = POP();
130             str = (char *) POP();
131             DPRINTF("obp_getprop(0x%x, NULL) = %s\n", node, str);
132
133             return (int)str;
134         }
135         DPRINTF("obp_getprop(0x%x, NULL) (not found)\n", node);
136
137         return -1;
138     } else {
139         push_str(name);
140         PUSH(node);
141         fword("get-package-property");
142         notfound = POP();
143     }
144     if (notfound) {
145         DPRINTF("obp_getprop(0x%x, %s) (not found)\n", node, name);
146
147         return -1;
148     } else {
149         len = POP();
150         str = (char *) POP();
151         if (len > 0)
152             memcpy(value, str, len);
153         else
154             str = "NULL";
155
156 #ifdef CONFIG_DEBUG_OBP
157         if (looks_like_string(str, len)) {
158             DPRINTF("obp_getprop(0x%x, %s) = %s\n", node, name, str);
159         } else {
160             int i;
161             DPRINTF("obp_getprop(0x%x, %s) = ", node, name);
162             for (i = 0; i < len; i++) {
163                 DPRINTF("%02x%s", str[i] & 0xFF,
164                         (len == 4 || i == len-1) ? "" : " ");
165             }
166             DPRINTF("\n");
167         }
168 #endif
169
170         return len;
171     }
172 }
173
174 const char *obp_nextprop(int node, const char *name)
175 {
176     int found;
177
178     if (!name || *name == '\0') {
179         // NULL name means get first property
180         push_str("");
181         name = "NULL";
182     } else {
183         push_str(name);
184     }
185     PUSH(node);
186     fword("next-property");
187     found = POP();
188     if (!found) {
189         DPRINTF("obp_nextprop(0x%x, %s) (not found)\n", node, name);
190
191         return "";
192     } else {
193         char *str;
194
195         POP(); /* len */
196         str = (char *) POP();
197
198         DPRINTF("obp_nextprop(0x%x, %s) = %s\n", node, name, str);
199
200         return str;
201     }
202 }
203
204 int obp_setprop(__attribute__((unused)) int node,
205                        __attribute__((unused)) const char *name,
206                        __attribute__((unused)) char *value,
207                        __attribute__((unused)) int len)
208 {
209     DPRINTF("obp_setprop(0x%x, %s) = %s (%d)\n", node, name, value, len);
210
211     return -1;
212 }
213
214 static const struct linux_nodeops nodeops0 = {
215     obp_nextnode_handler,       /* int (*no_nextnode)(int node); */
216     obp_child_handler,          /* int (*no_child)(int node); */
217     obp_proplen_handler,        /* int (*no_proplen)(int node, char *name); */
218     obp_getprop_handler,        /* int (*no_getprop)(int node,char *name,char *val); */
219     obp_setprop_handler,        /* int (*no_setprop)(int node, char *name,
220                                 char *val, int len); */
221     obp_nextprop_handler        /* char * (*no_nextprop)(int node, char *name); */
222 };
223
224 int obp_nbgetchar(void)
225 {
226     return getchar();
227 }
228
229 int obp_nbputchar(int ch)
230 {
231     putchar(ch);
232
233     return 0;
234 }
235
236 void obp_putstr(char *str, int len)
237 {
238     PUSH(pointer2cell(str));
239     PUSH(len);
240     fword("type");
241 }
242
243 void obp_printf(const char *fmt, ...)
244 {
245     va_list ap;
246
247     va_start(ap, fmt);
248     printk(fmt, ap);
249     va_end(ap);
250 }
251
252 void obp_reboot(char *str)
253 {
254     printk("rebooting (%s)\n", str);
255     *reset_reg = 1;
256     printk("reboot failed\n");
257     for (;;) {}
258 }
259
260 void obp_abort(void)
261 {
262     printk("abort, power off\n");
263     *power_reg = 1;
264     printk("power off failed\n");
265     for (;;) {}
266 }
267
268 void obp_halt(void)
269 {
270     printk("halt, power off\n");
271     *power_reg = 1;
272     printk("power off failed\n");
273     for (;;) {}
274 }
275
276 int obp_devopen(char *str)
277 {
278     int ret;
279
280     push_str(str);
281     fword("open-dev");
282     ret = POP();
283     DPRINTF("obp_devopen(%s) = 0x%x\n", str, ret);
284
285     return ret;
286 }
287
288 int obp_devclose(int dev_desc)
289 {
290     int ret = 1;
291
292     PUSH(dev_desc);
293     fword("close-dev");
294
295     DPRINTF("obp_devclose(0x%x) = %d\n", dev_desc, ret);
296
297     return ret;
298 }
299
300 int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
301 {
302     int ret, hi, lo, bs;
303
304     bs = 512;
305     hi = ((uint64_t)offset * bs) >> 32;
306     lo = ((uint64_t)offset * bs) & 0xffffffff;
307
308     ret = obp_devseek(dev_desc, hi, lo);
309
310     ret = obp_devread(dev_desc, buf, num_blks * bs) / bs;
311
312     DPRINTF("obp_rdblkdev(fd 0x%x, num_blks %d, offset %d (hi %d lo %d), buf 0x%x) = %d\n", dev_desc, num_blks, offset, hi, lo, (int)buf, ret);
313
314     return ret;
315 }
316
317 int obp_devread(int dev_desc, char *buf, int nbytes)
318 {
319     int ret;
320
321     PUSH((int)buf);
322     PUSH(nbytes);
323     push_str("read");
324     PUSH(dev_desc);
325     fword("$call-method");
326     ret = POP();
327
328     DPRINTF("obp_devread(fd 0x%x, buf 0x%x, nbytes %d) = %d\n", dev_desc, (int)buf, nbytes, ret);
329
330     return ret;
331 }
332
333 int obp_devwrite(int dev_desc, char *buf, int nbytes)
334 {
335 #ifdef CONFIG_DEBUG_OBP_DEVWRITE /* disabled, makes too much noise */
336     int ret;
337 #endif
338
339     PUSH((int)buf);
340     PUSH(nbytes);
341     push_str("write");
342     PUSH(dev_desc);
343     fword("$call-method");
344 #ifdef CONFIG_DEBUG_OBP_DEVWRITE
345     ret = POP();
346     DPRINTF("obp_devwrite(fd 0x%x, buf %s, nbytes %d) = %d\n", dev_desc, buf, nbytes, ret);
347 #else
348     POP();
349 #endif
350
351     return nbytes;
352 }
353
354 int obp_devseek(int dev_desc, int hi, int lo)
355 {
356     int ret;
357
358     PUSH(lo);
359     PUSH(hi);
360     push_str("seek");
361     PUSH(dev_desc);
362     fword("$call-method");
363     ret = POP();
364
365     DPRINTF("obp_devseek(fd 0x%x, hi %d, lo %d) = %d\n", dev_desc, hi, lo, ret);
366
367     return ret;
368 }
369
370 int obp_inst2pkg(int dev_desc)
371 {
372     int ret;
373
374     PUSH(dev_desc);
375     fword("ihandle>non-interposed-phandle");
376     ret = POP();
377
378     DPRINTF("obp_inst2pkg(fd 0x%x) = 0x%x\n", dev_desc, ret);
379
380     return ret;
381 }
382
383 int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
384                         __attribute__((unused))int ctxtbl_ptr,
385                         __attribute__((unused))int thiscontext,
386                         __attribute__((unused))char *prog_counter)
387 {
388     int cpu, found;
389     struct linux_prom_registers *smp_ctable = (void *)ctxtbl_ptr;
390
391     DPRINTF("obp_cpustart: cpu %d, ctxptr 0x%x, ctx %d, pc 0x%x\n", whichcpu,
392             smp_ctable->phys_addr, thiscontext, (unsigned int)prog_counter);
393
394     found = obp_getprop(whichcpu, "mid", (char *)&cpu);
395     if (found == -1)
396         return -1;
397     DPRINTF("cpu found, id %d -> cpu %d\n", whichcpu, cpu);
398
399     return start_cpu((unsigned int)prog_counter, ((unsigned int)smp_ctable->phys_addr) >> 4,
400               thiscontext, cpu);
401 }
402
403 int obp_cpustop(__attribute__((unused)) unsigned int whichcpu)
404 {
405     DPRINTF("obp_cpustop: cpu %d\n", whichcpu);
406
407     return 0;
408 }
409
410 int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu)
411 {
412     DPRINTF("obp_cpuidle: cpu %d\n", whichcpu);
413
414     return 0;
415 }
416
417 int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu)
418 {
419     DPRINTF("obp_cpuresume: cpu %d\n", whichcpu);
420
421     return 0;
422 }
423
424 void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4)
425 {
426   int dstacktmp = 0;
427
428   // It seems Solaris passes up to 5 arguments which should be pushed onto the Forth
429   // stack for execution. However the API doesn't provide for a way to specify the number
430   // of arguments actually being passed. Hence we preserve the state of the Forth stack 
431   // before, push all the arguments, execute the Forth, then restore the stack to its 
432   // previous state. This enables us to have a variable number of arguments and still 
433   // preserve stack state between subsequent calls.
434
435   // Preserve stack state
436   dstacktmp = dstackcnt;
437
438   PUSH(arg4);
439   PUSH(arg3);
440   PUSH(arg2);
441   PUSH(arg1);
442   PUSH(arg0);
443
444   DPRINTF("obp_fortheval_v2(%x %x %x %x %x %s)\n", arg4, arg3, arg2, arg1, arg0, str);
445   push_str(str);
446   fword("eval");
447
448   // Restore stack state
449   dstackcnt = dstacktmp;
450 }
451
452 volatile uint32_t *obp_ticks;
453
454 void *
455 init_openprom(void)
456 {
457     /* Setup the openprom vector. Note that all functions should be invoked
458        via their handler (see call-romvec.S) which acts as a proxy to save
459        the globals and setup the stack correctly */
460
461     // Linux wants a R/W romvec table
462     romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC;
463     romvec0.pv_romvers = 3;
464     romvec0.pv_plugin_revision = 2;
465     romvec0.pv_printrev = 0x20019;
466     romvec0.pv_v0mem.v0_totphys = NULL;
467     romvec0.pv_v0mem.v0_prommap = NULL;
468     romvec0.pv_v0mem.v0_available = NULL;
469     romvec0.pv_nodeops = &nodeops0;
470     romvec0.pv_bootstr = (void *)doublewalk;
471     romvec0.pv_v0devops.v0_devopen = &obp_devopen_handler;
472     romvec0.pv_v0devops.v0_devclose = &obp_devclose_handler;
473     romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev_handler;
474     romvec0.pv_stdin = &obp_stdin;
475     romvec0.pv_stdout = &obp_stdout;
476     romvec0.pv_getchar = obp_nbgetchar_handler;
477     romvec0.pv_putchar = (void (*)(int))obp_nbputchar_handler;
478     romvec0.pv_nbgetchar = obp_nbgetchar_handler;
479     romvec0.pv_nbputchar = obp_nbputchar_handler;
480     romvec0.pv_putstr = obp_putstr_handler;
481     romvec0.pv_reboot = obp_reboot_handler;
482     romvec0.pv_printf = obp_printf_handler;
483     romvec0.pv_abort = obp_abort_handler;
484     
485     /* Point to the Forth obp-ticks variable and reset */
486     fword("obp-ticks");
487     obp_ticks = cell2pointer(POP());
488     *obp_ticks = 0;
489     romvec0.pv_ticks = obp_ticks;
490     
491     romvec0.pv_halt = obp_halt_handler;
492     romvec0.pv_synchook = &sync_hook;
493     romvec0.pv_v0bootargs = &obp_argp;
494     romvec0.pv_fortheval.v2_eval = obp_fortheval_v2_handler;
495     romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg_handler;
496     romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc_handler;
497     romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree_handler;
498     romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap_handler;
499     romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap_handler;
500     romvec0.pv_v2devops.v2_dev_open = obp_devopen_handler;
501     romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose_handler;
502     romvec0.pv_v2devops.v2_dev_read = obp_devread_handler;
503     romvec0.pv_v2devops.v2_dev_write = obp_devwrite_handler;
504     romvec0.pv_v2devops.v2_dev_seek = obp_devseek_handler;
505
506     romvec0.pv_v2bootargs.bootpath = &bootpath;
507
508     romvec0.pv_v2bootargs.bootargs = &obp_arg.argv[1];
509
510     /* Point fd_stdin/fd_stdout to the Forth stdin/stdout variables */
511     fword("stdin");
512     romvec0.pv_v2bootargs.fd_stdin = cell2pointer(POP());
513     fword("stdout");
514     romvec0.pv_v2bootargs.fd_stdout = cell2pointer(POP());
515
516     romvec0.v3_memalloc = obp_memalloc_handler;
517
518     romvec0.v3_cpustart = obp_cpustart_handler;
519     romvec0.v3_cpustop = obp_cpustop_handler;
520     romvec0.v3_cpuidle = obp_cpuidle_handler;
521     romvec0.v3_cpuresume = obp_cpuresume_handler;
522
523     return &romvec0;
524 }