gdb/configure.ac: remove elf_hp.h check
[binutils-gdb.git] / sim / ppc / emul_chirp.c
blobc064a28a7c621256d4f173c7983c619d04f7bce0
1 /* This file is part of the program psim.
3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #ifndef _EMUL_CHIRP_C_
22 #define _EMUL_CHIRP_C_
24 /* Note: this module is called via a table. There is no benefit in
25 making it inline */
27 #include "emul_generic.h"
28 #include "emul_chirp.h"
30 #include <string.h>
31 #include <unistd.h>
33 #ifndef STATIC_INLINE_EMUL_CHIRP
34 #define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
35 #endif
38 /* EMULATION
41 OpenFirmware - IEEE Standard for Boot (Initialization
42 Configuration) Firmware.
45 DESCRIPTION
48 BUGS
51 This code assumes that the memory node has #address-cells and
52 #size-cells set to one. For future implementations, this may not
53 be the case.
60 /* Descriptor of the open boot services being emulated */
62 typedef int (chirp_handler)
63 (os_emul_data *data,
64 cpu *processor,
65 unsigned_word cia);
67 typedef struct _chirp_services {
68 const char *name;
69 chirp_handler *handler;
70 } chirp_services;
73 /* The OpenBoot emulation is, at any time either waiting for a client
74 request or waiting on a client callback */
75 typedef enum {
76 serving,
77 emulating,
78 faulting,
79 } chirp_emul_state;
81 struct _os_emul_data {
82 chirp_emul_state state;
83 unsigned_word return_address;
84 unsigned_word arguments;
85 unsigned_word n_args;
86 unsigned_word n_returns;
87 chirp_services *service;
88 device *root;
89 chirp_services *services;
90 /* configuration */
91 unsigned_word memory_size;
92 unsigned_word real_base;
93 unsigned_word real_size;
94 unsigned_word virt_base;
95 unsigned_word virt_size;
96 int real_mode;
97 int little_endian;
98 int floating_point_available;
99 int interrupt_prefix;
100 unsigned_word load_base;
101 /* hash table */
102 unsigned_word nr_page_table_entry_groups;
103 unsigned_word htab_offset;
104 unsigned_word htab_ra;
105 unsigned_word htab_va;
106 unsigned_word sizeof_htab;
107 /* virtual address of htab */
108 unsigned_word stack_offset;
109 unsigned_word stack_ra;
110 unsigned_word stack_va;
111 unsigned_word sizeof_stack;
112 /* addresses of emulation instructions virtual/real */
113 unsigned_word code_offset;
114 unsigned_word code_va;
115 unsigned_word code_ra;
116 unsigned_word sizeof_code;
117 unsigned_word code_client_va;
118 unsigned_word code_client_ra;
119 unsigned_word code_callback_va;
120 unsigned_word code_callback_ra;
121 unsigned_word code_loop_va;
122 unsigned_word code_loop_ra;
126 /* returns the name of the corresponding Ihandle */
127 static const char *
128 ihandle_name(device_instance *ihandle)
130 if (ihandle == NULL)
131 return "";
132 else
133 return device_name(device_instance_device(ihandle));
138 /* Read/write the argument list making certain that all values are
139 converted to/from host byte order.
141 In the below only n_args+n_returns is read/written */
143 static int
144 chirp_read_t2h_args(void *args,
145 int sizeof_args,
146 int n_args,
147 int n_returns,
148 os_emul_data *data,
149 cpu *processor,
150 unsigned_word cia)
152 unsigned_cell *words;
153 int i;
154 /* check against the number of arguments specified by the client
155 program */
156 if ((n_args >= 0 && data->n_args != n_args)
157 || (n_returns >= 0 && data->n_returns != n_returns)) {
158 TRACE(trace_os_emul, ("%s - invalid nr of args - n_args=%ld, n_returns=%ld\n",
159 data->service->name,
160 (long)data->n_args,
161 (long)data->n_returns));
162 return -1;
164 /* check that there is enough space */
165 if (sizeof(unsigned_cell) * (data->n_args + data->n_returns) > sizeof_args)
166 return -1;
167 /* bring in the data */
168 memset(args, 0, sizeof_args);
169 emul_read_buffer(args, data->arguments + 3 * sizeof(unsigned_cell),
170 sizeof(unsigned_cell) * (data->n_args + data->n_returns),
171 processor, cia);
172 /* convert all words to host format */
173 words = args;
174 for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++)
175 words[i] = T2H_cell(words[i]);
176 return 0;
179 static void
180 chirp_write_h2t_args(void *args,
181 int sizeof_args,
182 os_emul_data *data,
183 cpu *processor,
184 unsigned_word cia)
186 int i;
187 unsigned_cell *words;
188 /* convert to target everything */
189 words = args;
190 for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++)
191 words[i] = H2T_cell(words[i]);
192 /* bring in the data */
193 emul_write_buffer(args, data->arguments + 3 * sizeof(unsigned_cell),
194 sizeof(unsigned_cell) * (data->n_args + data->n_returns),
195 processor, cia);
199 /* OpenBoot emulation functions */
201 /* client interface */
203 static int
204 chirp_emul_test(os_emul_data *data,
205 cpu *processor,
206 unsigned_word cia)
208 struct test_args {
209 /*in*/
210 unsigned_cell name; /*string*/
211 /*out*/
212 unsigned_cell missing;
213 } args;
214 char name[32];
215 chirp_services *service = NULL;
216 /* read in the arguments */
217 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
218 return -1;
219 emul_read_string(name, args.name, sizeof(name),
220 processor, cia);
221 TRACE(trace_os_emul, ("test - in - name=`%s'\n", name));
222 /* see if we know about the service */
223 service = data->services;
224 while (service->name != NULL && strcmp(service->name, name) != 0) {
225 service++;
227 if (service->name == NULL)
228 args.missing = -1;
229 else
230 args.missing = 0;
231 /* write the arguments back out */
232 TRACE(trace_os_emul, ("test - out - missing=%ld\n",
233 (long)args.missing));
234 chirp_write_h2t_args(&args,
235 sizeof(args),
236 data,
237 processor, cia);
238 return 0;
242 /* Device tree */
244 static int
245 chirp_emul_peer(os_emul_data *data,
246 cpu *processor,
247 unsigned_word cia)
249 struct peer_args {
250 /*in*/
251 unsigned_cell phandle;
252 /*out*/
253 unsigned_cell sibling_phandle;
254 } args;
255 device *phandle;
256 device *sibling_phandle = NULL;
257 /* read in the arguments */
258 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
259 return -1;
260 phandle = external_to_device(data->root, args.phandle);
261 TRACE(trace_os_emul, ("peer - in - phandle=0x%lx(%p`%s')\n",
262 (unsigned long)args.phandle,
263 phandle,
264 (phandle == NULL ? "" : device_name(phandle))));
265 /* find the peer */
266 if (args.phandle == 0) {
267 sibling_phandle = data->root;
268 args.sibling_phandle = device_to_external(sibling_phandle);
270 else if (phandle == NULL) {
271 sibling_phandle = NULL;
272 args.sibling_phandle = -1;
274 else {
275 sibling_phandle = device_sibling(phandle);
276 if (sibling_phandle == NULL)
277 args.sibling_phandle = 0;
278 else
279 args.sibling_phandle = device_to_external(sibling_phandle);
281 /* write the arguments back out */
282 TRACE(trace_os_emul, ("peer - out - sibling_phandle=0x%lx(%p`%s')\n",
283 (unsigned long)args.sibling_phandle,
284 sibling_phandle,
285 (sibling_phandle == NULL ? "" : device_name(sibling_phandle))));
286 chirp_write_h2t_args(&args,
287 sizeof(args),
288 data,
289 processor, cia);
290 return 0;
293 static int
294 chirp_emul_child(os_emul_data *data,
295 cpu *processor,
296 unsigned_word cia)
298 struct child_args {
299 /*in*/
300 unsigned_cell phandle;
301 /*out*/
302 unsigned_cell child_phandle;
303 } args;
304 device *phandle;
305 device *child_phandle;
306 /* read the arguments in */
307 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
308 return -1;
309 phandle = external_to_device(data->root, args.phandle);
310 TRACE(trace_os_emul, ("child - in - phandle=0x%lx(%p`%s')\n",
311 (unsigned long)args.phandle,
312 phandle,
313 (phandle == NULL ? "" : device_name(phandle))));
314 /* find a child */
315 if (args.phandle == 0
316 || phandle == NULL) {
317 child_phandle = NULL;
318 args.child_phandle = -1;
320 else {
321 child_phandle = device_child(phandle);
322 if (child_phandle == NULL)
323 args.child_phandle = 0;
324 else
325 args.child_phandle = device_to_external(child_phandle);
327 /* write the result out */
328 TRACE(trace_os_emul, ("child - out - child_phandle=0x%lx(%p`%s')\n",
329 (unsigned long)args.child_phandle,
330 child_phandle,
331 (child_phandle == NULL ? "" : device_name(child_phandle))));
332 chirp_write_h2t_args(&args,
333 sizeof(args),
334 data,
335 processor, cia);
336 return 0;
339 static int
340 chirp_emul_parent(os_emul_data *data,
341 cpu *processor,
342 unsigned_word cia)
344 struct parent_args {
345 /*in*/
346 unsigned_cell phandle;
347 /*out*/
348 unsigned_cell parent_phandle;
349 } args;
350 device *phandle;
351 device *parent_phandle;
352 /* read the args in */
353 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
354 return -1;
355 phandle = external_to_device(data->root, args.phandle);
356 TRACE(trace_os_emul, ("parent - in - phandle=0x%lx(%p`%s')\n",
357 (unsigned long)args.phandle,
358 phandle,
359 (phandle == NULL ? "" : device_name(phandle))));
360 /* find a parent */
361 if (args.phandle == 0
362 || phandle == NULL) {
363 parent_phandle = NULL;
364 args.parent_phandle = -1;
366 else {
367 parent_phandle = device_parent(phandle);
368 if (parent_phandle == NULL)
369 args.parent_phandle = 0;
370 else
371 args.parent_phandle = device_to_external(parent_phandle);
373 /* return the result */
374 TRACE(trace_os_emul, ("parent - out - parent_phandle=0x%lx(%p`%s')\n",
375 (unsigned long)args.parent_phandle,
376 parent_phandle,
377 (parent_phandle == NULL ? "" : device_name(parent_phandle))));
378 chirp_write_h2t_args(&args,
379 sizeof(args),
380 data,
381 processor, cia);
382 return 0;
385 static int
386 chirp_emul_instance_to_package(os_emul_data *data,
387 cpu *processor,
388 unsigned_word cia)
390 struct instance_to_package_args {
391 /*in*/
392 unsigned_cell ihandle;
393 /*out*/
394 unsigned_cell phandle;
395 } args;
396 device_instance *ihandle;
397 device *phandle = NULL;
398 /* read the args in */
399 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
400 return -1;
401 ihandle = external_to_device_instance(data->root, args.ihandle);
402 TRACE(trace_os_emul, ("instance-to-package - in - ihandle=0x%lx(%p`%s')\n",
403 (unsigned long)args.ihandle,
404 ihandle,
405 ihandle_name(ihandle)));
406 /* find the corresponding phandle */
407 if (ihandle == NULL) {
408 phandle = NULL;
409 args.phandle = -1;
411 else {
412 phandle = device_instance_device(ihandle);
413 args.phandle = device_to_external(phandle);
415 /* return the result */
416 TRACE(trace_os_emul, ("instance-to-package - out - phandle=0x%lx(%p`%s')\n",
417 (unsigned long)args.phandle,
418 phandle,
419 (phandle == NULL ? "" : device_name(phandle))));
420 chirp_write_h2t_args(&args,
421 sizeof(args),
422 data,
423 processor, cia);
424 return 0;
427 static int
428 chirp_emul_getproplen(os_emul_data *data,
429 cpu *processor,
430 unsigned_word cia)
432 struct getproplen_args {
433 /*in*/
434 unsigned_cell phandle;
435 unsigned_cell name;
436 /*out*/
437 unsigned_cell proplen;
438 } args;
439 char name[32];
440 device *phandle;
441 /* read the args in */
442 if (chirp_read_t2h_args(&args, sizeof(args), 2, 1, data, processor, cia))
443 return -1;
444 phandle = external_to_device(data->root, args.phandle);
445 emul_read_string(name,
446 args.name,
447 sizeof(name),
448 processor, cia);
449 TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(%p`%s') name=`%s'\n",
450 (unsigned long)args.phandle,
451 phandle,
452 (phandle == NULL ? "" : device_name(phandle)),
453 name));
454 /* find our prop and get its length */
455 if (args.phandle == 0
456 || phandle == NULL) {
457 args.proplen = -1;
459 else {
460 const device_property *prop = device_find_property(phandle, name);
461 if (prop == (device_property*)0) {
462 args.proplen = -1;
464 else {
465 args.proplen = prop->sizeof_array;
468 /* return the result */
469 TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n",
470 (unsigned long)args.proplen));
471 chirp_write_h2t_args(&args,
472 sizeof(args),
473 data,
474 processor, cia);
475 return 0;
478 static int
479 chirp_emul_getprop(os_emul_data *data,
480 cpu *processor,
481 unsigned_word cia)
483 struct getprop_args {
484 /*in*/
485 unsigned_cell phandle;
486 unsigned_cell name;
487 unsigned_cell buf;
488 unsigned_cell buflen;
489 /*out*/
490 unsigned_cell size;
491 } args;
492 char name[32];
493 device *phandle;
494 /* read in the args, the return is optional */
495 if (chirp_read_t2h_args(&args, sizeof(args), 4, -1, data, processor, cia))
496 return -1;
497 phandle = external_to_device(data->root, args.phandle);
498 emul_read_string(name,
499 args.name,
500 sizeof(name),
501 processor, cia);
502 TRACE(trace_os_emul, ("getprop - in - phandle=0x%lx(%p`%s') name=`%s' buf=0x%lx buflen=%ld\n",
503 (unsigned long)args.phandle,
504 phandle,
505 (phandle == NULL ? "" : device_name(phandle)),
506 name,
507 (unsigned long)args.buf,
508 (unsigned long)args.buflen));
509 /* get the property */
510 if (args.phandle == 0
511 || phandle == NULL) {
512 args.size = -1;
514 else {
515 const device_property *prop = device_find_property(phandle, name);
516 if (prop == NULL) {
517 args.size = -1;
519 else {
520 int size = args.buflen;
521 if (size > prop->sizeof_array)
522 size = prop->sizeof_array;
523 emul_write_buffer(prop->array, args.buf,
524 size,
525 processor, cia);
526 args.size = size;
527 switch (prop->type) {
528 case string_property:
529 TRACE(trace_os_emul, ("getprop - string `%s'\n",
530 device_find_string_property(phandle, name)));
531 break;
532 case ihandle_property:
533 TRACE(trace_os_emul, ("getprop - ihandle=0x%lx(%p`%s')\n",
534 (unsigned long)BE2H_cell(*(unsigned_cell*)prop->array),
535 device_find_ihandle_property(phandle, name),
536 ihandle_name(device_find_ihandle_property(phandle, name))));
537 break;
538 default:
539 break;
543 /* write back the result */
544 if (data->n_returns == 0)
545 TRACE(trace_os_emul, ("getprop - out - size=%ld (not returned)\n",
546 (unsigned long)args.size));
547 else {
548 TRACE(trace_os_emul, ("getprop - out - size=%ld\n",
549 (unsigned long)args.size));
550 chirp_write_h2t_args(&args,
551 sizeof(args),
552 data,
553 processor, cia);
555 return 0;
558 static int
559 chirp_emul_nextprop(os_emul_data *data,
560 cpu *processor,
561 unsigned_word cia)
563 struct nextprop_args {
564 /*in*/
565 unsigned_cell phandle;
566 unsigned_cell previous;
567 unsigned_cell buf;
568 /*out*/
569 unsigned_cell flag;
570 } args;
571 char previous[32];
572 device *phandle;
573 /* read in the args */
574 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
575 return -1;
576 phandle = external_to_device(data->root, args.phandle);
577 if (args.previous != 0)
578 emul_read_string(previous,
579 args.previous,
580 sizeof(previous),
581 processor, cia);
582 else
583 /* If previous is NULL, make it look like the empty string. The
584 next property after the empty string is the first property. */
585 strcpy (previous, "");
586 TRACE(trace_os_emul, ("nextprop - in - phandle=0x%lx(%p`%s') previous=`%s' buf=0x%lx\n",
587 (unsigned long)args.phandle,
588 phandle,
589 (phandle == NULL ? "" : device_name(phandle)),
590 previous,
591 (unsigned long)args.buf));
592 /* find the next property */
593 if (args.phandle == 0
594 || phandle == NULL) {
595 args.flag = -1;
597 else {
598 const device_property *prev_prop = device_find_property(phandle, previous);
599 if (prev_prop == NULL) {
600 if (strcmp (previous, "") == 0)
601 args.flag = 0; /* No properties */
602 else
603 args.flag = -1; /* name invalid */
605 else {
606 const device_property *next_prop;
607 if (strcmp (previous, "") == 0) {
608 next_prop = prev_prop; /* The first property. */
610 else {
611 next_prop = device_next_property(prev_prop);
613 if (next_prop == NULL) {
614 args.flag = 0; /* last property */
616 else {
617 emul_write_buffer(next_prop->name, args.buf, strlen(next_prop->name),
618 processor, cia);
619 TRACE(trace_os_emul, ("nextprop - name=`%s'\n", next_prop->name));
620 args.flag = 1; /* worked ok */
624 /* write back the result */
625 TRACE(trace_os_emul, ("nextprop - out - flag=%ld\n",
626 (unsigned long)args.flag));
627 chirp_write_h2t_args(&args,
628 sizeof(args),
629 data,
630 processor, cia);
631 return 0;
634 #if 0
635 static int
636 chirp_emul_setprop(os_emul_data *data,
637 cpu *processor,
638 unsigned_word cia)
640 error("chirp: setprop method not implemented\n");
641 return 0;
643 #endif
645 static int
646 chirp_emul_canon(os_emul_data *data,
647 cpu *processor,
648 unsigned_word cia)
650 struct canon_args {
651 /*in*/
652 unsigned_cell device_specifier;
653 unsigned_cell buf;
654 unsigned_cell buflen;
655 /*out*/
656 unsigned_cell length;
657 } args;
658 char device_specifier[1024];
659 device *phandle;
660 const char *path;
661 int length;
662 /* read in the args */
663 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
664 return -1;
665 emul_read_string(device_specifier,
666 args.device_specifier,
667 sizeof(device_specifier),
668 processor, cia);
669 TRACE(trace_os_emul, ("canon - in - device_specifier=`%s' buf=0x%lx buflen=%lx\n",
670 device_specifier,
671 (unsigned long)args.buf,
672 (unsigned long)args.buflen));
673 /* canon the name */
674 phandle = tree_find_device(data->root, device_specifier);
675 if (phandle == NULL) {
676 length = -1;
677 path = "";
678 args.length = -1;
680 else {
681 path = device_path(phandle);
682 length = strlen(path);
683 if (length >= args.buflen)
684 length = args.buflen - 1;
685 emul_write_buffer(path, args.buf, length,
686 processor, cia);
687 args.length = length;
689 /* write back the result */
690 TRACE(trace_os_emul, ("canon - out - length=%ld buf=`%s'\n",
691 (unsigned long)args.length,
692 path));
693 chirp_write_h2t_args(&args,
694 sizeof(args),
695 data,
696 processor, cia);
697 return 0;
700 static int
701 chirp_emul_finddevice(os_emul_data *data,
702 cpu *processor,
703 unsigned_word cia)
705 struct finddevice_args {
706 /*in*/
707 unsigned_cell device_specifier;
708 /*out*/
709 unsigned_cell phandle;
710 } args;
711 char device_specifier[1024];
712 device *phandle;
713 /* get the args */
714 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
715 return -1;
716 emul_read_string(device_specifier,
717 args.device_specifier,
718 sizeof(device_specifier),
719 processor, cia);
720 TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n",
721 device_specifier));
722 /* find the device */
723 phandle = tree_find_device(data->root, device_specifier);
724 if (phandle == NULL)
725 args.phandle = -1;
726 else
727 args.phandle = device_to_external(phandle);
728 /* return its phandle */
729 TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(%p`%s')\n",
730 (unsigned long)args.phandle,
731 phandle,
732 (phandle == NULL ? "" : device_name(phandle))));
733 chirp_write_h2t_args(&args,
734 sizeof(args),
735 data,
736 processor, cia);
737 return 0;
740 static int
741 chirp_emul_instance_to_path(os_emul_data *data,
742 cpu *processor,
743 unsigned_word cia)
745 struct instance_to_path_args {
746 /*in*/
747 unsigned_cell ihandle;
748 unsigned_cell buf;
749 unsigned_cell buflen;
750 /*out*/
751 unsigned_cell length;
752 } args;
753 device_instance *ihandle;
754 const char *path;
755 int length;
756 /* get the args */
757 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
758 return -1;
759 ihandle = external_to_device_instance(data->root, args.ihandle);
760 TRACE(trace_os_emul, ("instance-to-path - in - ihandle=0x%lx(%p`%s') buf=0x%lx buflen=%ld\n",
761 (unsigned long)args.ihandle,
762 ihandle,
763 ihandle_name(ihandle),
764 (unsigned long)args.buf,
765 (unsigned long)args.buflen));
766 /* get the devices name */
767 if (ihandle == NULL) {
768 args.length = -1;
769 path = "(null)";
771 else {
772 path = device_instance_path(ihandle);
773 length = strlen(path);
774 if (length >= args.buflen)
775 length = args.buflen - 1;
776 emul_write_buffer(path, args.buf, length,
777 processor, cia);
778 args.length = length;
780 /* return its phandle */
781 TRACE(trace_os_emul, ("instance-to-path - out - length=%ld buf=`%s')\n",
782 (unsigned long)args.length,
783 path));
784 chirp_write_h2t_args(&args,
785 sizeof(args),
786 data,
787 processor, cia);
788 return 0;
791 static int
792 chirp_emul_package_to_path(os_emul_data *data,
793 cpu *processor,
794 unsigned_word cia)
796 struct package_to_path_args {
797 /*in*/
798 unsigned_cell phandle;
799 unsigned_cell buf;
800 unsigned_cell buflen;
801 /*out*/
802 unsigned_cell length;
803 } args;
804 device *phandle;
805 const char *path;
806 /* get the args */
807 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
808 return -1;
809 phandle = external_to_device(data->root, args.phandle);
810 TRACE(trace_os_emul, ("package-to-path - in - phandle=0x%lx(%p`%s') buf=0x%lx buflen=%ld\n",
811 (unsigned long)args.phandle,
812 phandle,
813 (phandle == NULL ? "" : device_name(phandle)),
814 (unsigned long)args.buf,
815 (unsigned long)args.buflen));
816 /* get the devices name */
817 if (phandle == NULL) {
818 args.length = -1;
819 path = "(null)";
821 else {
822 int length;
823 path = device_path(phandle);
824 length = strlen(path);
825 if (length >= args.buflen)
826 length = args.buflen - 1;
827 emul_write_buffer(path, args.buf, length,
828 processor, cia);
829 args.length = length;
831 /* return its phandle */
832 TRACE(trace_os_emul, ("package-to-path - out - length=%ld buf=`%s')\n",
833 (unsigned long)args.length,
834 path));
835 chirp_write_h2t_args(&args,
836 sizeof(args),
837 data,
838 processor, cia);
839 return 0;
842 static int
843 chirp_emul_call_method(os_emul_data *data,
844 cpu *processor,
845 unsigned_word cia)
847 struct call_method_args {
848 /*in*/
849 unsigned_cell method;
850 unsigned_cell ihandle;
851 /*in/out*/
852 unsigned_cell stack[13]; /*6in + 6out + catch */
853 } args;
854 char method[32];
855 device_instance *ihandle;
856 /* some useful info about our mini stack */
857 int n_stack_args;
858 int n_stack_returns;
859 int stack_catch_result;
860 int stack_returns;
861 /* read the args */
862 if (chirp_read_t2h_args(&args, sizeof(args), -1, -1, data, processor, cia))
863 return -1;
864 emul_read_string(method,
865 args.method,
866 sizeof(method),
867 processor, cia);
868 ihandle = external_to_device_instance(data->root, args.ihandle);
869 n_stack_args = data->n_args - 2;
870 n_stack_returns = data->n_returns - 1;
871 stack_catch_result = n_stack_args;
872 stack_returns = stack_catch_result + 1;
873 TRACE(trace_os_emul, ("call-method - in - n_args=%ld n_returns=%ld method=`%s' ihandle=0x%lx(%p`%s')\n",
874 (unsigned long)data->n_args,
875 (unsigned long)data->n_returns,
876 method,
877 (unsigned long)args.ihandle,
878 ihandle,
879 ihandle_name(ihandle)));
880 /* see if we can emulate this method */
881 if (ihandle == NULL) {
882 /* OpenFirmware doesn't define this error */
883 error("chirp: invalid ihandle passed to call-method method");
885 else {
886 args.stack[stack_catch_result] =
887 device_instance_call_method(ihandle,
888 method,
889 n_stack_args,
890 &args.stack[0],
891 n_stack_returns,
892 &args.stack[stack_returns]);
894 /* finished */
895 TRACE(trace_os_emul, ("call-method - out - catch-result=%ld\n",
896 (unsigned long)args.stack[stack_catch_result]));
897 chirp_write_h2t_args(&args,
898 sizeof(args),
899 data,
900 processor, cia);
901 return 0;
905 /* Device I/O */
907 static int
908 chirp_emul_open(os_emul_data *data,
909 cpu *processor,
910 unsigned_word cia)
912 struct open_args {
913 /*in*/
914 unsigned_cell device_specifier;
915 /*out*/
916 unsigned_cell ihandle;
917 } args;
918 char device_specifier[1024];
919 device_instance *ihandle;
920 /* read the args */
921 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
922 return -1;
923 emul_read_string(device_specifier,
924 args.device_specifier,
925 sizeof(device_specifier),
926 processor, cia);
927 TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n",
928 device_specifier));
929 /* open the device */
930 ihandle = tree_instance(data->root, device_specifier);
931 if (ihandle == NULL)
932 args.ihandle = -1;
933 else
934 args.ihandle = device_instance_to_external(ihandle);
935 /* return the ihandle result */
936 TRACE(trace_os_emul, ("open - out - ihandle=0x%lx(%p`%s')\n",
937 (unsigned long)args.ihandle,
938 ihandle,
939 ihandle_name(ihandle)));
940 chirp_write_h2t_args(&args,
941 sizeof(args),
942 data,
943 processor, cia);
944 return 0;
947 static int
948 chirp_emul_close(os_emul_data *data,
949 cpu *processor,
950 unsigned_word cia)
952 struct close_args {
953 /*in*/
954 unsigned_cell ihandle;
955 /*out*/
956 } args;
957 device_instance *ihandle;
958 /* read the args */
959 if (chirp_read_t2h_args(&args, sizeof(args), 1, 0, data, processor, cia))
960 return -1;
961 ihandle = external_to_device_instance(data->root, args.ihandle);
962 TRACE(trace_os_emul, ("close - in - ihandle=0x%lx(%p`%s')\n",
963 (unsigned long)args.ihandle,
964 ihandle,
965 ihandle_name(ihandle)));
966 /* close the device */
967 if (ihandle == NULL) {
968 /* OpenFirmware doesn't define this error */
969 error("chirp: invalid ihandle passed to close method");
971 else {
972 device_instance_delete(ihandle);
974 /* return the ihandle result */
975 TRACE(trace_os_emul, ("close - out\n"));
976 chirp_write_h2t_args(&args,
977 sizeof(args),
978 data,
979 processor, cia);
980 return 0;
983 static int
984 chirp_emul_read(os_emul_data *data,
985 cpu *processor,
986 unsigned_word cia)
988 struct read_args {
989 /*in*/
990 unsigned_cell ihandle;
991 unsigned_cell addr;
992 unsigned_cell len;
993 /*out*/
994 unsigned_cell actual;
995 } args;
996 char buf[1024];
997 device_instance *ihandle;
998 /* read the args */
999 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
1000 return -1;
1001 ihandle = external_to_device_instance(data->root, args.ihandle);
1002 TRACE(trace_os_emul, ("read - in - ihandle=0x%lx(%p`%s') addr=0x%lx len=%ld\n",
1003 (unsigned long)args.ihandle,
1004 ihandle,
1005 ihandle_name(ihandle),
1006 (unsigned long)args.addr,
1007 (unsigned long)args.len));
1008 if (ihandle == NULL) {
1009 /* OpenFirmware doesn't define this error */
1010 error("chirp: invalid ihandle passed to read method");
1012 else {
1013 /* do the reads */
1014 int actual = 0;
1015 while (actual < args.len) {
1016 int remaining = args.len - actual;
1017 int to_read = (remaining <= sizeof(buf) ? remaining : sizeof(buf));
1018 int nr_read = device_instance_read(ihandle, buf, to_read);
1019 if (nr_read < 0) {
1020 actual = nr_read; /* the error */
1021 break;
1023 else if (nr_read == 0) {
1024 break;
1026 emul_write_buffer(buf,
1027 args.addr + actual,
1028 nr_read,
1029 processor, cia);
1030 actual += nr_read;
1032 if (actual >= 0) {
1033 args.actual = actual;
1034 if (actual < sizeof(buf))
1035 buf[actual] = '\0';
1036 else
1037 buf[sizeof(buf) - 1] = '\0';
1039 else {
1040 switch (actual) {
1041 case sim_io_eof:
1042 args.actual = 0;
1043 break;
1044 case sim_io_not_ready:
1045 ASSERT(sim_io_not_ready == -2);
1046 args.actual = sim_io_not_ready;
1047 break;
1048 default:
1049 error("Bad error value %ld", (long)actual);
1050 break;
1054 /* return the result */
1055 TRACE(trace_os_emul, ("read - out - actual=%ld `%s'\n",
1056 (long)args.actual,
1057 ((args.actual > 0 && args.actual < sizeof(buf)) ? buf : "")
1059 chirp_write_h2t_args(&args,
1060 sizeof(args),
1061 data,
1062 processor, cia);
1063 return 0;
1066 static int
1067 chirp_emul_write(os_emul_data *data,
1068 cpu *processor,
1069 unsigned_word cia)
1071 struct write_args {
1072 /*in*/
1073 unsigned_cell ihandle;
1074 unsigned_cell addr;
1075 unsigned_cell len;
1076 /*out*/
1077 unsigned_cell actual;
1078 } args;
1079 char buf[1024];
1080 device_instance *ihandle;
1081 int actual;
1082 /* get the args */
1083 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
1084 return -1;
1085 actual = args.len;
1086 if (actual >= sizeof(buf))
1087 actual = sizeof(buf) - 1;
1088 emul_read_buffer(buf,
1089 args.addr,
1090 actual,
1091 processor, cia);
1092 buf[actual] = '\0';
1093 ihandle = external_to_device_instance(data->root, args.ihandle);
1094 TRACE(trace_os_emul, ("write - in - ihandle=0x%lx(%p`%s') `%s' (%ld)\n",
1095 (unsigned long)args.ihandle,
1096 ihandle,
1097 ihandle_name(ihandle),
1098 buf, (long)actual));
1099 if (ihandle == NULL) {
1100 /* OpenFirmware doesn't define this error */
1101 error("chirp: invalid ihandle passed to write method");
1103 else {
1104 /* write it out */
1105 actual = device_instance_write(ihandle, buf, actual);
1106 if (actual < 0)
1107 args.actual = 0;
1108 else
1109 args.actual = actual;
1111 /* return the result */
1112 TRACE(trace_os_emul, ("write - out - actual=%ld\n",
1113 (long)args.actual));
1114 chirp_write_h2t_args(&args,
1115 sizeof(args),
1116 data,
1117 processor, cia);
1118 return 0;
1121 static int
1122 chirp_emul_seek(os_emul_data *data,
1123 cpu *processor,
1124 unsigned_word cia)
1126 struct seek_args {
1127 /*in*/
1128 unsigned_cell ihandle;
1129 unsigned_cell pos_hi;
1130 unsigned_cell pos_lo;
1131 /*out*/
1132 unsigned_cell status;
1133 } args;
1134 int status;
1135 device_instance *ihandle;
1136 /* get the args */
1137 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
1138 return -1;
1139 ihandle = external_to_device_instance(data->root, args.ihandle);
1140 TRACE(trace_os_emul, ("seek - in - ihandle=0x%lx(%p`%s') pos.hi=0x%lx pos.lo=0x%lx\n",
1141 (unsigned long)args.ihandle,
1142 ihandle,
1143 ihandle_name(ihandle),
1144 (unsigned long)args.pos_hi,
1145 (unsigned long)args.pos_lo));
1146 if (ihandle == NULL) {
1147 /* OpenFirmware doesn't define this error */
1148 error("chirp: invalid ihandle passed to seek method");
1150 else {
1151 /* seek it out */
1152 status = device_instance_seek(ihandle, args.pos_hi, args.pos_lo);
1153 args.status = status;
1155 /* return the result */
1156 TRACE(trace_os_emul, ("seek - out - status=%ld\n",
1157 (long)args.status));
1158 chirp_write_h2t_args(&args,
1159 sizeof(args),
1160 data,
1161 processor, cia);
1162 return 0;
1166 /* memory */
1168 static int
1169 chirp_emul_claim(os_emul_data *data,
1170 cpu *processor,
1171 unsigned_word cia)
1173 /* NOTE: the client interface claim routine is *very* different to
1174 the "claim" method described in IEEE-1275 appendix A. The latter
1175 uses real addresses while this uses virtual (effective)
1176 addresses. */
1177 struct claim_args {
1178 /* in */
1179 unsigned_cell virt;
1180 unsigned_cell size;
1181 unsigned_cell align;
1182 /* out */
1183 unsigned_cell baseaddr;
1184 } args;
1185 /* read the args */
1186 if (chirp_read_t2h_args(&args, sizeof(args),
1187 3 /*n_args*/, 1 /*n_returns*/,
1188 data, processor, cia))
1189 return -1;
1190 TRACE(trace_os_emul, ("claim - in - virt=0x%lx size=%ld align=%d\n",
1191 (unsigned long)args.virt,
1192 (long int)args.size,
1193 (int)args.align));
1194 /* use the memory device to allocate (real) memory at the requested
1195 address */
1197 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
1198 unsigned_cell mem_in[3];
1199 unsigned_cell mem_out[1];
1200 mem_in[0] = args.align; /*top-of-stack*/
1201 mem_in[1] = args.size;
1202 mem_in[2] = args.virt;
1203 if (device_instance_call_method(memory, "claim",
1204 3, mem_in, 1, mem_out) < 0)
1205 error("chirp: claim failed to allocate memory virt=0x%lx size=%ld align=%d",
1206 (unsigned long)args.virt,
1207 (long int)args.size,
1208 (int)args.align);
1209 args.baseaddr = mem_out[0];
1211 /* if using virtual addresses, create a 1-1 map of this address space */
1212 if (!data->real_mode) {
1213 error("chirp: claim method does not support virtual mode");
1215 /* return the base address */
1216 TRACE(trace_os_emul, ("claim - out - baseaddr=0x%lx\n",
1217 (unsigned long)args.baseaddr));
1218 chirp_write_h2t_args(&args,
1219 sizeof(args),
1220 data,
1221 processor, cia);
1222 return 0;
1225 static int
1226 chirp_emul_release(os_emul_data *data,
1227 cpu *processor,
1228 unsigned_word cia)
1230 /* NOTE: the client interface release routine is *very* different to
1231 the "claim" method described in IEEE-1275 appendix A. The latter
1232 uses real addresses while this uses virtual (effective)
1233 addresses. */
1234 struct claim_args {
1235 /* in */
1236 unsigned_cell virt;
1237 unsigned_cell size;
1238 /* out */
1239 } args;
1240 /* read the args */
1241 if (chirp_read_t2h_args(&args, sizeof(args),
1242 2 /*n_args*/, 0 /*n_returns*/,
1243 data, processor, cia))
1244 return -1;
1245 TRACE(trace_os_emul, ("release - in - virt=0x%lx size=%ld\n",
1246 (unsigned long)args.virt,
1247 (long int)args.size));
1248 /* use the memory device to release (real) memory at the requested
1249 address */
1251 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
1252 unsigned_cell mem_in[2];
1253 mem_in[0] = args.size;
1254 mem_in[1] = args.virt;
1255 if (device_instance_call_method(memory, "release",
1256 2, mem_in, 0, NULL) < 0)
1257 error("chirp: claim failed to release memory virt=0x%lx size=%ld",
1258 (unsigned long)args.virt,
1259 (long int)args.size);
1261 /* if using virtual addresses, remove the 1-1 map of this address space */
1262 if (!data->real_mode) {
1263 error("chirp: release method does not support virtual mode");
1265 /* return the base address */
1266 TRACE(trace_os_emul, ("release - out\n"));
1267 chirp_write_h2t_args(&args,
1268 sizeof(args),
1269 data,
1270 processor, cia);
1271 return 0;
1275 /* Control transfer */
1277 static int
1278 chirp_emul_boot(os_emul_data *data,
1279 cpu *processor,
1280 unsigned_word cia)
1282 /* unlike OpenFirmware this one can take an argument */
1283 struct boot_args {
1284 /*in*/
1285 unsigned_cell bootspec;
1286 /*out*/
1287 } args;
1288 char bootspec[1024];
1289 /* read in the arguments */
1290 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
1291 cpu_halt(processor, cia, was_exited, -1);
1292 if (args.bootspec != 0)
1293 emul_read_string(bootspec, args.bootspec, sizeof(bootspec),
1294 processor, cia);
1295 else
1296 strcpy(bootspec, "(null)");
1297 TRACE(trace_os_emul, ("boot - in bootspec=`%s'\n", bootspec));
1298 /* just report this and exit */
1299 printf_filtered("chrp: boot %s called, exiting.\n", bootspec);
1300 cpu_halt(processor, cia, was_exited, 0);
1301 return 0;
1304 static int
1305 chirp_emul_enter(os_emul_data *data,
1306 cpu *processor,
1307 unsigned_word cia)
1309 error("chirp: enter method not implemented\n");
1310 return 0;
1313 static int
1314 chirp_emul_exit(os_emul_data *data,
1315 cpu *processor,
1316 unsigned_word cia)
1318 /* unlike OpenBoot this one can take an argument */
1319 struct exit_args {
1320 /*in*/
1321 signed_cell status;
1322 /*out*/
1323 } args;
1324 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
1325 cpu_halt(processor, cia, was_exited, -1);
1326 cpu_halt(processor, cia, was_exited, args.status);
1327 return 0;
1330 static int
1331 chirp_emul_chain(os_emul_data *data,
1332 cpu *processor,
1333 unsigned_word cia)
1335 error("chirp: chain method not implemented\n");
1336 return 0;
1340 /* user interface */
1342 static int
1343 chirp_emul_interpret(os_emul_data *data,
1344 cpu *processor,
1345 unsigned_word cia)
1347 error("chirp: interpret method not implemented\n");
1348 return 0;
1351 static int
1352 chirp_emul_set_callback(os_emul_data *data,
1353 cpu *processor,
1354 unsigned_word cia)
1356 error("chirp: set_callback method not implemented\n");
1357 return 0;
1360 static int
1361 chirp_emul_set_symbol_lookup(os_emul_data *data,
1362 cpu *processor,
1363 unsigned_word cia)
1365 error("chirp: set_symbol_lookup method not implemented\n");
1366 return 0;
1370 /* Time */
1372 static int
1373 chirp_emul_milliseconds(os_emul_data *data,
1374 cpu *processor,
1375 unsigned_word cia)
1377 struct test_args {
1378 /*in*/
1379 /*out*/
1380 unsigned_cell ms;
1381 } args;
1382 uint64_t time;
1383 /* read in the arguments */
1384 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
1385 return -1;
1386 /* make up a number */
1387 time = event_queue_time(psim_event_queue(cpu_system(processor))) / 1000000;
1388 args.ms = time;
1389 /* write the arguments back out */
1390 TRACE(trace_os_emul, ("milliseconds - out - ms=%ld\n",
1391 (unsigned long)args.ms));
1392 chirp_write_h2t_args(&args,
1393 sizeof(args),
1394 data,
1395 processor, cia);
1396 return 0;
1402 static chirp_services services[] = {
1404 /* client interface */
1405 { "test", chirp_emul_test },
1407 /* device tree */
1408 { "peer", chirp_emul_peer },
1409 { "child", chirp_emul_child },
1410 { "parent", chirp_emul_parent },
1411 { "instance-to-package", chirp_emul_instance_to_package },
1412 { "getproplen", chirp_emul_getproplen },
1413 { "getprop", chirp_emul_getprop },
1414 { "nextprop", chirp_emul_nextprop },
1415 /* { "setprop", chirp_emul_setprop }, */
1416 { "canon", chirp_emul_canon },
1417 { "finddevice", chirp_emul_finddevice },
1418 { "instance-to-path", chirp_emul_instance_to_path },
1419 { "package-to-path", chirp_emul_package_to_path },
1420 { "call-method", chirp_emul_call_method },
1422 /* device I/O */
1423 { "open", chirp_emul_open },
1424 { "close", chirp_emul_close },
1425 { "read", chirp_emul_read },
1426 { "write", chirp_emul_write },
1427 { "seek", chirp_emul_seek },
1428 { "write", chirp_emul_write },
1430 /* memory */
1431 { "claim", chirp_emul_claim },
1432 { "release", chirp_emul_release },
1434 /* control transfer */
1435 { "boot", chirp_emul_boot },
1436 { "enter", chirp_emul_enter },
1437 { "exit", chirp_emul_exit },
1438 { "chain", chirp_emul_chain },
1440 /* user interface */
1441 { "interpret", chirp_emul_interpret },
1442 { "set_callback", chirp_emul_set_callback },
1443 { "set_symbol_lookup", chirp_emul_set_symbol_lookup },
1445 /* time */
1446 { "milliseconds", chirp_emul_milliseconds },
1448 { 0, /* sentinal */ },
1452 /* main handlers */
1454 /* Any starting address greater than this is assumed to be an Chirp
1455 rather than VEA */
1457 #ifndef CHIRP_START_ADDRESS
1458 #define CHIRP_START_ADDRESS 0x80000000
1459 #endif
1460 #ifndef CHIRP_LOAD_BASE
1461 #define CHIRP_LOAD_BASE -1
1462 #endif
1465 typedef struct _chirp_note_desc {
1466 int32_t real_mode;
1467 int32_t real_base;
1468 int32_t real_size;
1469 int32_t virt_base;
1470 int32_t virt_size;
1471 int32_t load_base;
1472 } chirp_note_desc;
1474 typedef enum {
1475 note_missing,
1476 note_found,
1477 note_correct,
1478 } note_found_status;
1479 typedef struct _chirp_note {
1480 chirp_note_desc desc;
1481 note_found_status found;
1482 } chirp_note;
1484 typedef struct _chirp_note_head {
1485 uint32_t namesz;
1486 uint32_t descsz;
1487 uint32_t type;
1488 } chirp_note_head;
1490 static void
1491 map_over_chirp_note(bfd *image,
1492 asection *sect,
1493 void *obj)
1495 chirp_note *note = (chirp_note*)obj;
1496 if (strcmp(sect->name, ".note") == 0) {
1497 chirp_note_head head;
1498 char name[16];
1499 /* check the head */
1500 if (!bfd_get_section_contents(image, sect,
1501 &head, 0, sizeof(head)))
1502 return;
1503 head.namesz = bfd_get_32(image, (void*)&head.namesz);
1504 head.descsz = bfd_get_32(image, (void*)&head.descsz);
1505 head.type = bfd_get_32(image, (void*)&head.type);
1506 if (head.type != 0x1275)
1507 return;
1508 /* check the name field */
1509 if (head.namesz > sizeof(name)) {
1510 error("chirp: note name too long (%d > %d)\n", (int)head.namesz, (int)sizeof(name));
1512 if (!bfd_get_section_contents(image, sect,
1513 name, sizeof(head), head.namesz)) {
1514 error("chirp: note name unreadable\n");
1516 if (strcmp(name, "PowerPC") != 0) {
1517 printf_filtered("chirp: note name (%s) not `PowerPC'\n", name);
1519 /* check the size */
1520 if (head.descsz == sizeof(note->desc) - sizeof(int32_t)) {
1521 sim_io_printf_filtered("chirp: note descriptor missing load-base\n");
1523 else if (head.descsz != sizeof(note->desc)) {
1524 sim_io_printf_filtered("chirp: note descriptor of wrong size\n");
1525 note->found = note_found;
1526 return;
1528 note->found = note_correct;
1529 /* get the contents */
1530 if (!bfd_get_section_contents(image, sect,
1531 &note->desc, /* page align start */
1532 ((sizeof(head) + head.namesz) + 3) & ~3,
1533 head.descsz)) {
1534 error("chirp: note descriptor unreadable\n");
1536 note->desc.real_mode = bfd_get_32(image, (void*)&note->desc.real_mode);
1537 note->desc.real_base = bfd_get_32(image, (void*)&note->desc.real_base);
1538 note->desc.real_size = bfd_get_32(image, (void*)&note->desc.real_size);
1539 note->desc.virt_base = bfd_get_32(image, (void*)&note->desc.virt_base);
1540 note->desc.virt_size = bfd_get_32(image, (void*)&note->desc.virt_size);
1541 if (head.descsz == sizeof(note->desc))
1542 note->desc.load_base = bfd_get_32(image, (void*)&note->desc.load_base);
1543 else
1544 note->desc.load_base = (int32_t)-1;
1549 static os_emul_data *
1550 emul_chirp_create(device *root,
1551 bfd *image,
1552 const char *name)
1554 os_emul_data *chirp;
1555 device *node;
1556 chirp_note note;
1557 int i;
1559 /* Sanity check that this really is the chosen emulation */
1560 if (name == NULL && image == NULL)
1561 return NULL;
1562 if (name != NULL
1563 && strcmp(name, "ob") != 0
1564 && strcmp(name, "ieee1274") != 0
1565 && strcmp(name, "chrp") != 0
1566 && strcmp(name, "chirp") != 0
1567 && strcmp(name, "openboot") != 0)
1568 return NULL;
1570 /* look for an elf note section, enter its values into the device tree */
1571 memset(&note, 0, sizeof(note));
1572 if (image != NULL)
1573 bfd_map_over_sections(image, map_over_chirp_note, &note);
1574 if (name == NULL && image != NULL && note.found == note_missing)
1575 return NULL;
1577 /* Assume that it is a chirp emulation */
1579 chirp = ZALLOC(os_emul_data);
1580 chirp->root = root;
1581 chirp->services = services;
1583 /* the root node */
1584 tree_parse(root, "/name \"gpl,clayton");
1586 /* default options */
1587 emul_add_tree_options(root, image, "chirp", "oea",
1588 0 /*oea-interrupt-prefix*/);
1590 /* hardware */
1591 emul_add_tree_hardware(root);
1593 /* basic information */
1594 chirp->memory_size
1595 = tree_find_integer_property(root, "/openprom/options/oea-memory-size");
1596 chirp->little_endian
1597 = tree_find_boolean_property(root, "/options/little-endian?");
1598 chirp->floating_point_available
1599 = tree_find_boolean_property(root, "/openprom/options/floating-point?");
1600 chirp->interrupt_prefix =
1601 tree_find_integer_property(root, "/openprom/options/oea-interrupt-prefix");
1604 /* Perform an interum layout of the openboot firmware in memory */
1607 /* a page for firmware calls */
1608 chirp->sizeof_code = 4096;
1609 chirp->code_offset = 0x4000; /* possible space for interrupt table */
1611 /* the stack */
1612 chirp->sizeof_stack = 32 * 1024;
1613 chirp->stack_offset = chirp->code_offset + chirp->sizeof_code;
1615 /* the hash table */
1616 if (!note.desc.real_mode) {
1617 chirp->nr_page_table_entry_groups = (chirp->memory_size < 0x800000
1618 ? 1024 /* min allowed */
1619 : (chirp->memory_size / 4096 / 2));
1620 chirp->sizeof_htab = chirp->nr_page_table_entry_groups * 64;
1622 chirp->htab_offset = chirp->stack_offset + chirp->sizeof_stack;
1624 /* the actual amount of space needed */
1625 chirp->real_size = chirp->htab_offset + chirp->sizeof_htab;
1628 /* now go through and see if it fits in what is available */
1631 /* resolve real-mode? */
1632 if (note.found == note_correct)
1633 chirp->real_mode = note.desc.real_mode;
1634 else if (tree_find_property(root, "/options/real-mode?") != NULL)
1635 chirp->real_mode = tree_find_boolean_property(root, "/options/real-mode?");
1636 else
1637 chirp->real_mode = 0;
1638 if (tree_find_property(root, "/options/real-mode?") != NULL) {
1639 if (!chirp->real_mode
1640 != !tree_find_boolean_property(root, "/options/real-mode?"))
1641 error("chirp: /options/real-mode? conflicts with note section\n");
1643 else
1644 tree_parse(root, "/options/real-mode? %s",
1645 chirp->real_mode ? "true" : "false");
1647 /* resolve real-base */
1648 if (note.found == note_correct
1649 && note.desc.real_base != (int32_t)-1)
1650 chirp->real_base = note.desc.real_base;
1651 else if (tree_find_property(root, "/options/real-base") != NULL)
1652 chirp->real_base = tree_find_integer_property(root, "/options/real-base");
1653 else
1654 chirp->real_base = chirp->memory_size - chirp->real_size;
1655 if (tree_find_property(root, "/options/real-base") != NULL) {
1656 if (chirp->real_base != tree_find_integer_property(root, "/options/real-base"))
1657 error("chirp: /options/real-base conflicts with note section\n");
1659 else
1660 tree_parse(root, "/options/real-base 0x%lx",
1661 (unsigned long)chirp->real_base);
1663 /* resolve real-size */
1664 if (note.found == note_correct
1665 && note.desc.real_size != (int32_t)-1
1666 && note.desc.real_size != 0
1667 && chirp->real_size > note.desc.real_size)
1668 error("chirp: insufficient physical memory for firmware\n");
1669 if (tree_find_property(root, "/options/real-size") != NULL) {
1670 if (chirp->real_size > tree_find_integer_property(root, "/options/real-size"))
1671 error("chirp: /options/real-size conflicts with note section\n");
1673 else
1674 tree_parse(root, "/options/real-size 0x%lx",
1675 (unsigned long)chirp->real_size);
1677 /* resolve virt-base */
1678 if (chirp->real_mode)
1679 chirp->virt_base = chirp->real_base;
1680 else if (note.found == note_correct && note.desc.virt_base != -1)
1681 chirp->virt_base = note.desc.virt_base;
1682 else if (tree_find_property(root, "/options/virt-base") != NULL)
1683 chirp->virt_base = tree_find_integer_property(root, "/options/virt-base");
1684 else
1685 chirp->virt_base = CHIRP_START_ADDRESS;
1686 if (tree_find_property(root, "/options/virt-base") != NULL) {
1687 unsigned_word virt_base = tree_find_integer_property(root, "/options/virt-base");
1688 if (virt_base != -1 && chirp->virt_base != virt_base)
1689 error("chirp: /options/virt-base conflicts with note section\n");
1691 else
1692 tree_parse(root, "/options/virt-base 0x%lx",
1693 chirp->real_mode ? -1 : (unsigned long)chirp->virt_base);
1695 /* resolve virt-size */
1696 chirp->virt_size = chirp->real_size;
1697 if (note.found == note_correct
1698 && note.desc.virt_size != (int32_t)-1
1699 && note.desc.virt_size != 0
1700 && !chirp->real_mode
1701 && chirp->virt_size > note.desc.virt_size)
1702 error("chirp: insufficent virtual memory for firmware\n");
1703 if (tree_find_property(root, "/options/virt-size") != NULL) {
1704 if (chirp->virt_size > tree_find_integer_property(root, "/options/virt-size"))
1705 error("chirp: /options/virt-size conflicts with note section\n");
1707 else
1708 tree_parse(root, "/options/virt-size 0x%lx",
1709 chirp->real_mode ? -1 : (unsigned long)chirp->virt_size);
1711 /* resolve load-base */
1712 if (note.found == note_correct
1713 && note.desc.load_base != (int32_t)-1)
1714 chirp->load_base = note.desc.load_base;
1715 else if (tree_find_property(root, "/options/load-base") != NULL)
1716 chirp->load_base = tree_find_integer_property(root, "/options/load-base");
1717 else
1718 chirp->load_base = CHIRP_LOAD_BASE;
1719 if (tree_find_property(root, "/options/load-base") != NULL) {
1720 if (chirp->load_base != tree_find_integer_property(root, "/options/load-base"))
1721 error("chirp: /options/load-base conflicts with note section\n");
1723 else
1724 tree_parse(root, "/options/load-base 0x%lx",
1725 (unsigned long)chirp->load_base);
1727 /* now adjust the preliminary firmware addresses to final values */
1728 chirp->code_ra = chirp->code_offset + chirp->real_base;
1729 chirp->stack_ra = chirp->stack_offset + chirp->real_base;
1730 chirp->htab_ra = chirp->htab_offset + chirp->real_base;
1732 /* the virtual addresses. In real mode these are real addresses. */
1734 chirp->code_va = chirp->code_offset + chirp->virt_base;
1735 chirp->stack_va = chirp->stack_offset + chirp->virt_base;
1736 chirp->htab_va = chirp->htab_offset + chirp->virt_base;
1738 chirp->code_client_va = chirp->code_va;
1739 chirp->code_client_ra = chirp->code_ra;
1741 chirp->code_callback_va = chirp->code_client_va + 16;
1742 chirp->code_callback_ra = chirp->code_client_ra + 16;
1744 chirp->code_loop_va = chirp->code_callback_va + 16;
1745 chirp->code_loop_ra = chirp->code_callback_ra + 16;
1747 /* initialization */
1749 tree_parse(root, "/openprom/init");
1750 tree_parse(root, "/openprom/init/register");
1751 tree_parse(root, "/openprom/init/register/0.pc 0x%lx",
1752 (unsigned long)bfd_get_start_address(image));
1753 tree_parse(root, "/openprom/init/register/pc 0x%lx",
1754 (unsigned long)chirp->code_loop_va);
1755 tree_parse(root, "/openprom/init/register/msr 0x%x",
1756 (msr_machine_check_enable
1757 | (chirp->real_mode
1759 : (msr_instruction_relocate
1760 | msr_data_relocate))
1761 | (chirp->little_endian
1762 ? (msr_little_endian_mode
1763 | msr_interrupt_little_endian_mode)
1764 : 0)
1765 | (chirp->floating_point_available
1766 ? msr_floating_point_available
1767 : 0)
1768 | (chirp->interrupt_prefix
1769 ? msr_interrupt_prefix
1770 : 0)
1772 tree_parse(root, "/openprom/init/register/sdr1 0x%lx",
1773 (unsigned long)(chirp->htab_ra
1774 | MASK32(16, 22)
1775 | ((chirp->sizeof_htab - 1) >> 16)));
1776 /* make certain that the segment registers map straight through */
1777 for (i = 0; i < 16; i++) {
1778 tree_parse(root, "/openprom/init/register/sr%d 0x%lx",
1779 i, (unsigned long)i);
1782 /* establish an initial state for all processors */
1785 /* the client interface address */
1786 tree_parse(root, "/openprom/init/register/r5 0x%lx",
1787 (unsigned long)chirp->code_client_va);
1788 /* a stack */
1789 tree_parse(root, "/openprom/init/register/sp 0x%lx",
1790 (unsigned long)(chirp->stack_va + chirp->sizeof_stack - 16));
1791 /* in chrp mode any arguments end up being concatinated */
1792 tree_parse(root, "/openprom/init/stack/stack-type chirp");
1795 /* client interface - emul-call followed by return instruction */
1798 node = tree_parse(root, "/openprom/init/data@0x%lx",
1799 (unsigned long)chirp->code_client_ra);
1800 tree_parse(node, "./psim,description \"client-interface instruction");
1801 tree_parse(node, "./real-address 0x%lx",
1802 (unsigned long)chirp->code_client_ra);
1803 tree_parse(node, "./data 0x%lx",
1804 (unsigned long)emul_call_instruction);
1806 node = tree_parse(root, "/openprom/init/data@0x%lx",
1807 (unsigned long)(chirp->code_client_ra + 4));
1808 tree_parse(node, "./psim,description \"client-interface return instruction");
1809 tree_parse(node, "./real-address 0x%lx",
1810 (unsigned long)(chirp->code_client_ra + 4));
1811 tree_parse(node, "./data 0x%lx",
1812 (unsigned long)emul_blr_instruction);
1815 /* return address for client callbacks - an emul-call instruction
1816 that is again followed by a return instruction */
1819 node = tree_parse(root, "/openprom/init/data@0x%lx",
1820 (unsigned long)chirp->code_callback_ra);
1821 tree_parse(node, "./psim,description \"client-callback instruction");
1822 tree_parse(node, "./real-address 0x%lx",
1823 (unsigned long)chirp->code_callback_ra);
1824 tree_parse(node, "./data 0x%lx",
1825 (unsigned long)emul_call_instruction);
1827 node = tree_parse(root, "/openprom/init/data@0x%lx",
1828 (unsigned long)(chirp->code_callback_ra + 4));
1829 tree_parse(node, "./psim,description \"client-callback return instruction");
1830 tree_parse(node, "./real-address 0x%lx",
1831 (unsigned long)(chirp->code_callback_ra + 4));
1832 tree_parse(node, "./data 0x%lx",
1833 (unsigned long)emul_blr_instruction);
1835 /* loop to keep other processors busy */
1837 node = tree_parse(root, "/openprom/init/data@0x%lx",
1838 (unsigned long)chirp->code_loop_ra);
1839 tree_parse(node, "./psim,description \"processor busy loop");
1840 tree_parse(node, "./real-address 0x%lx",
1841 (unsigned long)chirp->code_loop_ra);
1842 tree_parse(node, "./data 0x%lx",
1843 (unsigned long)emul_loop_instruction);
1845 /* hash table */
1847 /* create a hash table */
1849 if (!chirp->real_mode) {
1850 node = tree_parse(root, "/openprom/init/htab@0x%lx",
1851 (unsigned long)chirp->htab_ra);
1852 tree_parse(node, "./claim 0");
1853 tree_parse(node, "./real-address 0x%lx",
1854 (unsigned long)chirp->htab_ra);
1855 tree_parse(node, "./nr-bytes 0x%lx",
1856 (unsigned long)chirp->sizeof_htab);
1859 /* map in the stack */
1861 if (!chirp->real_mode) {
1862 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1863 (unsigned long)chirp->stack_ra);
1864 tree_parse(node, "./psim,description \"map in the stack");
1865 tree_parse(node, "./claim 1");
1866 tree_parse(node, "./virtual-address 0x%lx",
1867 (unsigned long)chirp->stack_va);
1868 tree_parse(node, "./real-address 0x%lx",
1869 (unsigned long)chirp->stack_ra);
1870 tree_parse(node, "./nr-bytes 0x%lx",
1871 (unsigned long)chirp->sizeof_stack);
1872 tree_parse(node, "./wimg %d", 0x7);
1873 tree_parse(node, "./pp %d", 0x2);
1876 /* map in the chrp openboot callback code */
1878 if (!chirp->real_mode) {
1879 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1880 (unsigned long)chirp->code_ra);
1881 tree_parse(node, "./psim,description \"map in chrp openboot callback code");
1882 tree_parse(node, "./claim 1");
1883 tree_parse(node, "./virtual-address 0x%lx",
1884 (unsigned long)chirp->code_va);
1885 tree_parse(node, "./real-address 0x%lx",
1886 (unsigned long)chirp->code_ra);
1887 tree_parse(node, "./nr-bytes 0x%lx",
1888 (unsigned long)chirp->sizeof_code);
1889 tree_parse(node, "./wimg %d", 0x7);
1890 tree_parse(node, "./pp %d", 0x2);
1893 /* map in the program to run */
1895 if (chirp->real_mode) {
1896 node = tree_parse(node, "/openprom/init/load-binary");
1897 tree_parse(node, "./psim,description \"load the binary");
1898 tree_parse(node, "./file-name %s", bfd_get_filename(image));
1899 tree_parse(node, "./claim 1");
1901 else {
1902 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1903 (unsigned long)chirp->load_base);
1904 tree_parse(node, "./psim,description \"load & map the binary");
1905 tree_parse(node, "./claim 1");
1906 tree_parse(node, "./file-name \"%s", bfd_get_filename(image));
1907 tree_parse(node, "./wimg %d", 0x7);
1908 tree_parse(node, "./pp %d", 0x2);
1911 /* map in the interrupt vectors */
1913 if (!chirp->real_mode) {
1914 node = tree_parse(root, "/openprom/init/htab/pte@0x0");
1915 tree_parse(node, "./psim,description \"map in interrupt vectors");
1916 tree_parse(node, "./virtual-address 0x0");
1917 tree_parse(node, "./real-address 0x0");
1918 tree_parse(node, "./nr-bytes 0x3000");
1919 tree_parse(node, "./wimg %d", 0x7);
1920 tree_parse(node, "./pp %d", 0x2);
1923 return chirp;
1926 static void
1927 emul_chirp_init(os_emul_data *emul_data,
1928 int nr_cpus)
1930 emul_data->state = serving;
1933 static int
1934 emul_chirp_instruction_call(cpu *processor,
1935 unsigned_word cia,
1936 unsigned_word ra,
1937 os_emul_data *emul_data)
1939 unsigned_word service_name_addr;
1940 unsigned_word result;
1941 char service_buf[32];
1942 char *service_name;
1943 chirp_services *service;
1945 switch (emul_data->state) {
1947 case serving:
1948 /* we are waiting on an OpenBoot request from the client program
1949 via the client interface */
1950 if (cia != emul_data->code_client_va)
1951 return 0;
1952 emul_data->return_address = LR;
1953 emul_data->arguments = cpu_registers(processor)->gpr[3];
1954 /* try to determine what to do */
1955 service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3],
1956 processor, cia);
1957 service_name = emul_read_string(service_buf, service_name_addr,
1958 sizeof(service_buf), processor, cia);
1959 emul_data->n_args = emul_read_word(emul_data->arguments + sizeof(unsigned_cell),
1960 processor, cia);
1961 emul_data->n_returns = emul_read_word(emul_data->arguments + 2 * sizeof(unsigned_cell),
1962 processor, cia);
1963 /* verify what was passed */
1964 if (service_name_addr == 0
1965 || service_name == NULL) {
1966 error("OpenFirmware called with invalid (NULL) service name from 0x%lx with args 0x%lx\n",
1967 (unsigned long)emul_data->return_address,
1968 (unsigned long)emul_data->arguments);
1970 if (emul_data->n_args > 6) { /* See iee1275 requirements on nr returns */
1971 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, too many args (%d)\n",
1972 service_name,
1973 (unsigned long)emul_data->return_address,
1974 (unsigned long)emul_data->arguments,
1975 emul_data->n_returns);
1977 if (emul_data->n_returns > 6) {
1978 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, with too many returns (%d)\n",
1979 service_name,
1980 (unsigned long)emul_data->return_address,
1981 (unsigned long)emul_data->arguments,
1982 emul_data->n_args);
1984 /* look it up */
1985 TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n",
1986 service_name,
1987 (unsigned long)emul_data->return_address,
1988 (unsigned long)emul_data->arguments));
1989 service = services;
1990 while (service->name != NULL && strcmp(service->name, service_name) != 0)
1991 service++;
1992 /* found or not? */
1993 if (service->name == NULL) {
1994 error("OpenBoot service `%s' not found\n", service_name);
1995 TRACE(trace_os_emul, ("%s not found\n", service_name));
1996 cpu_registers(processor)->gpr[3] = -1;
1998 else {
1999 emul_data->service = service;
2000 /* call upon it */
2001 result = service->handler(emul_data, processor, cia);
2002 if (result != 0)
2003 TRACE(trace_os_emul, ("%s aborted with %ld\n", service_name, (long)result));
2004 cpu_registers(processor)->gpr[3] = result;
2006 break;
2008 default:
2009 error("emul_chirp_instruction_call() unknown internal state\n");
2010 result = -1;
2011 break;
2015 /* return to caller - instruction following this is a function return */
2016 return 1;
2019 const os_emul emul_chirp = {
2020 "chirp",
2021 emul_chirp_create,
2022 emul_chirp_init,
2023 NULL, /*system_call*/
2024 emul_chirp_instruction_call,
2025 0 /*data*/
2028 #endif