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