]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/emul_chirp.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / sim / ppc / emul_chirp.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
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
72 typedef int (chirp_handler)
73 (os_emul_data *data,
74 cpu *processor,
75 unsigned_word cia);
76
77 typedef 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 */
85 typedef enum {
86 serving,
87 emulating,
88 faulting,
89 } chirp_emul_state;
90
91 struct _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 */
137 static const char *
138 ihandle_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
153 static int
154 chirp_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
189 static void
190 chirp_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
213 static int
214 chirp_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
254 static int
255 chirp_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
303 static int
304 chirp_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
349 static int
350 chirp_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
395 static int
396 chirp_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
437 static int
438 chirp_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
488 static int
489 chirp_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
568 static int
569 chirp_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);
587 emul_read_string(previous,
588 args.previous,
589 sizeof(previous),
590 processor, cia);
591 TRACE(trace_os_emul, ("nextprop - in - phandle=0x%lx(0x%lx`%s') previous=`%s' buf=0x%lx\n",
592 (unsigned long)args.phandle,
593 (unsigned long)phandle,
594 (phandle == NULL ? "" : device_name(phandle)),
595 previous,
596 (unsigned long)args.buf));
597 /* find the next property */
598 if (args.phandle == 0
599 || phandle == NULL) {
600 args.flag = -1;
601 }
602 else {
603 const device_property *prev_prop = device_find_property(phandle, previous);
604 if (prev_prop == NULL) {
605 args.flag = -1; /* name invalid */
606 }
607 else {
608 const device_property *next_prop;
609 next_prop = device_next_property(prev_prop);
610 if (next_prop == NULL) {
611 args.flag = 0; /* last property */
612 }
613 else {
614 emul_write_buffer(next_prop->name, args.buf, strlen(next_prop->name),
615 processor, cia);
616 TRACE(trace_os_emul, ("nextprop - name=`%s'\n", next_prop->name));
617 args.flag = 1; /* worked ok */
618 }
619 }
620 }
621 /* write back the result */
622 TRACE(trace_os_emul, ("nextprop - out - flag=%ld\n",
623 (unsigned long)args.flag));
624 chirp_write_h2t_args(&args,
625 sizeof(args),
626 data,
627 processor, cia);
628 return 0;
629 }
630
631 #if 0
632 static int
633 chirp_emul_setprop(os_emul_data *data,
634 cpu *processor,
635 unsigned_word cia)
636 {
637 error("chirp: setprop method not implemented\n");
638 return 0;
639 }
640 #endif
641
642 static int
643 chirp_emul_canon(os_emul_data *data,
644 cpu *processor,
645 unsigned_word cia)
646 {
647 struct canon_args {
648 /*in*/
649 unsigned_cell device_specifier;
650 unsigned_cell buf;
651 unsigned_cell buflen;
652 /*out*/
653 unsigned_cell length;
654 } args;
655 char device_specifier[1024];
656 device *phandle;
657 const char *path;
658 int length;
659 /* read in the args */
660 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
661 return -1;
662 emul_read_string(device_specifier,
663 args.device_specifier,
664 sizeof(device_specifier),
665 processor, cia);
666 TRACE(trace_os_emul, ("canon - in - device_specifier=`%s' buf=0x%lx buflen=%lx\n",
667 device_specifier,
668 (unsigned long)args.buf,
669 (unsigned long)args.buflen));
670 /* canon the name */
671 phandle = tree_find_device(data->root, device_specifier);
672 if (phandle == NULL) {
673 length = -1;
674 path = "";
675 args.length = -1;
676 }
677 else {
678 path = device_path(phandle);
679 length = strlen(path);
680 if (length >= args.buflen)
681 length = args.buflen - 1;
682 emul_write_buffer(path, args.buf, length,
683 processor, cia);
684 args.length = length;
685 }
686 /* write back the result */
687 TRACE(trace_os_emul, ("canon - out - length=%ld buf=`%s'\n",
688 (unsigned long)args.length,
689 path));
690 chirp_write_h2t_args(&args,
691 sizeof(args),
692 data,
693 processor, cia);
694 return 0;
695 }
696
697 static int
698 chirp_emul_finddevice(os_emul_data *data,
699 cpu *processor,
700 unsigned_word cia)
701 {
702 struct finddevice_args {
703 /*in*/
704 unsigned_cell device_specifier;
705 /*out*/
706 unsigned_cell phandle;
707 } args;
708 char device_specifier[1024];
709 device *phandle;
710 /* get the args */
711 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
712 return -1;
713 emul_read_string(device_specifier,
714 args.device_specifier,
715 sizeof(device_specifier),
716 processor, cia);
717 TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n",
718 device_specifier));
719 /* find the device */
720 phandle = tree_find_device(data->root, device_specifier);
721 if (phandle == NULL)
722 args.phandle = -1;
723 else
724 args.phandle = device_to_external(phandle);
725 /* return its phandle */
726 TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(0x%lx`%s')\n",
727 (unsigned long)args.phandle,
728 (unsigned long)phandle,
729 (phandle == NULL ? "" : device_name(phandle))));
730 chirp_write_h2t_args(&args,
731 sizeof(args),
732 data,
733 processor, cia);
734 return 0;
735 }
736
737 static int
738 chirp_emul_instance_to_path(os_emul_data *data,
739 cpu *processor,
740 unsigned_word cia)
741 {
742 struct instance_to_path_args {
743 /*in*/
744 unsigned_cell ihandle;
745 unsigned_cell buf;
746 unsigned_cell buflen;
747 /*out*/
748 unsigned_cell length;
749 } args;
750 device_instance *ihandle;
751 const char *path;
752 int length;
753 /* get the args */
754 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
755 return -1;
756 ihandle = external_to_device_instance(data->root, args.ihandle);
757 TRACE(trace_os_emul, ("instance-to-path - in - ihandle=0x%lx(0x%lx`%s') buf=0x%lx buflen=%ld\n",
758 (unsigned long)args.ihandle,
759 (unsigned long)ihandle,
760 ihandle_name(ihandle),
761 (unsigned long)args.buf,
762 (unsigned long)args.buflen));
763 /* get the devices name */
764 if (ihandle == NULL) {
765 args.length = -1;
766 path = "(null)";
767 }
768 else {
769 path = device_instance_path(ihandle);
770 length = strlen(path);
771 if (length >= args.buflen)
772 length = args.buflen - 1;
773 emul_write_buffer(path, args.buf, length,
774 processor, cia);
775 args.length = length;
776 }
777 /* return its phandle */
778 TRACE(trace_os_emul, ("instance-to-path - out - length=%ld buf=`%s')\n",
779 (unsigned long)args.length,
780 path));
781 chirp_write_h2t_args(&args,
782 sizeof(args),
783 data,
784 processor, cia);
785 return 0;
786 }
787
788 static int
789 chirp_emul_package_to_path(os_emul_data *data,
790 cpu *processor,
791 unsigned_word cia)
792 {
793 struct package_to_path_args {
794 /*in*/
795 unsigned_cell phandle;
796 unsigned_cell buf;
797 unsigned_cell buflen;
798 /*out*/
799 unsigned_cell length;
800 } args;
801 device *phandle;
802 const char *path;
803 /* get the args */
804 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
805 return -1;
806 phandle = external_to_device(data->root, args.phandle);
807 TRACE(trace_os_emul, ("package-to-path - in - phandle=0x%lx(0x%lx`%s') buf=0x%lx buflen=%ld\n",
808 (unsigned long)args.phandle,
809 (unsigned long)phandle,
810 (phandle == NULL ? "" : device_name(phandle)),
811 (unsigned long)args.buf,
812 (unsigned long)args.buflen));
813 /* get the devices name */
814 if (phandle == NULL) {
815 args.length = -1;
816 path = "(null)";
817 }
818 else {
819 int length;
820 path = device_path(phandle);
821 length = strlen(path);
822 if (length >= args.buflen)
823 length = args.buflen - 1;
824 emul_write_buffer(path, args.buf, length,
825 processor, cia);
826 args.length = length;
827 }
828 /* return its phandle */
829 TRACE(trace_os_emul, ("package-to-path - out - length=%ld buf=`%s')\n",
830 (unsigned long)args.length,
831 path));
832 chirp_write_h2t_args(&args,
833 sizeof(args),
834 data,
835 processor, cia);
836 return 0;
837 }
838
839 static int
840 chirp_emul_call_method(os_emul_data *data,
841 cpu *processor,
842 unsigned_word cia)
843 {
844 struct call_method_args {
845 /*in*/
846 unsigned_cell method;
847 unsigned_cell ihandle;
848 /*in/out*/
849 unsigned_cell stack[13]; /*6in + 6out + catch */
850 } args;
851 char method[32];
852 device_instance *ihandle;
853 /* some useful info about our mini stack */
854 int n_stack_args;
855 int n_stack_returns;
856 int stack_catch_result;
857 int stack_returns;
858 /* read the args */
859 if (chirp_read_t2h_args(&args, sizeof(args), -1, -1, data, processor, cia))
860 return -1;
861 emul_read_string(method,
862 args.method,
863 sizeof(method),
864 processor, cia);
865 ihandle = external_to_device_instance(data->root, args.ihandle);
866 n_stack_args = data->n_args - 2;
867 n_stack_returns = data->n_returns - 1;
868 stack_catch_result = n_stack_args;
869 stack_returns = stack_catch_result + 1;
870 TRACE(trace_os_emul, ("call-method - in - n_args=%ld n_returns=%ld method=`%s' ihandle=0x%lx(0x%lx`%s')\n",
871 (unsigned long)data->n_args,
872 (unsigned long)data->n_returns,
873 method,
874 (unsigned long)args.ihandle,
875 (unsigned long)ihandle,
876 ihandle_name(ihandle)));
877 /* see if we can emulate this method */
878 if (ihandle == NULL) {
879 /* OpenFirmware doesn't define this error */
880 error("chirp: invalid ihandle passed to call-method method");
881 }
882 else {
883 args.stack[stack_catch_result] =
884 device_instance_call_method(ihandle,
885 method,
886 n_stack_args,
887 &args.stack[0],
888 n_stack_returns,
889 &args.stack[stack_returns]);
890 }
891 /* finished */
892 TRACE(trace_os_emul, ("call-method - out - catch-result=%ld\n",
893 (unsigned long)args.stack[stack_catch_result]));
894 chirp_write_h2t_args(&args,
895 sizeof(args),
896 data,
897 processor, cia);
898 return 0;
899 }
900
901
902 /* Device I/O */
903
904 static int
905 chirp_emul_open(os_emul_data *data,
906 cpu *processor,
907 unsigned_word cia)
908 {
909 struct open_args {
910 /*in*/
911 unsigned_cell device_specifier;
912 /*out*/
913 unsigned_cell ihandle;
914 } args;
915 char device_specifier[1024];
916 device_instance *ihandle;
917 /* read the args */
918 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
919 return -1;
920 emul_read_string(device_specifier,
921 args.device_specifier,
922 sizeof(device_specifier),
923 processor, cia);
924 TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n",
925 device_specifier));
926 /* open the device */
927 ihandle = tree_instance(data->root, device_specifier);
928 if (ihandle == NULL)
929 args.ihandle = -1;
930 else
931 args.ihandle = device_instance_to_external(ihandle);
932 /* return the ihandle result */
933 TRACE(trace_os_emul, ("open - out - ihandle=0x%lx(0x%lx`%s')\n",
934 (unsigned long)args.ihandle,
935 (unsigned long)ihandle,
936 ihandle_name(ihandle)));
937 chirp_write_h2t_args(&args,
938 sizeof(args),
939 data,
940 processor, cia);
941 return 0;
942 }
943
944 static int
945 chirp_emul_close(os_emul_data *data,
946 cpu *processor,
947 unsigned_word cia)
948 {
949 struct close_args {
950 /*in*/
951 unsigned_cell ihandle;
952 /*out*/
953 } args;
954 device_instance *ihandle;
955 /* read the args */
956 if (chirp_read_t2h_args(&args, sizeof(args), 1, 0, data, processor, cia))
957 return -1;
958 ihandle = external_to_device_instance(data->root, args.ihandle);
959 TRACE(trace_os_emul, ("close - in - ihandle=0x%lx(0x%lx`%s')\n",
960 (unsigned long)args.ihandle,
961 (unsigned long)ihandle,
962 ihandle_name(ihandle)));
963 /* close the device */
964 if (ihandle == NULL) {
965 /* OpenFirmware doesn't define this error */
966 error("chirp: invalid ihandle passed to close method");
967 }
968 else {
969 device_instance_delete(ihandle);
970 }
971 /* return the ihandle result */
972 TRACE(trace_os_emul, ("close - out\n"));
973 chirp_write_h2t_args(&args,
974 sizeof(args),
975 data,
976 processor, cia);
977 return 0;
978 }
979
980 static int
981 chirp_emul_read(os_emul_data *data,
982 cpu *processor,
983 unsigned_word cia)
984 {
985 struct read_args {
986 /*in*/
987 unsigned_cell ihandle;
988 unsigned_cell addr;
989 unsigned_cell len;
990 /*out*/
991 unsigned_cell actual;
992 } args;
993 char buf[1024];
994 device_instance *ihandle;
995 /* read the args */
996 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
997 return -1;
998 ihandle = external_to_device_instance(data->root, args.ihandle);
999 TRACE(trace_os_emul, ("read - in - ihandle=0x%lx(0x%lx`%s') addr=0x%lx len=%ld\n",
1000 (unsigned long)args.ihandle,
1001 (unsigned long)ihandle,
1002 ihandle_name(ihandle),
1003 (unsigned long)args.addr,
1004 (unsigned long)args.len));
1005 if (ihandle == NULL) {
1006 /* OpenFirmware doesn't define this error */
1007 error("chirp: invalid ihandle passed to read method");
1008 }
1009 else {
1010 /* do the reads */
1011 int actual = 0;
1012 while (actual < args.len) {
1013 int remaining = args.len - actual;
1014 int to_read = (remaining <= sizeof(buf) ? remaining : sizeof(buf));
1015 int nr_read = device_instance_read(ihandle, buf, to_read);
1016 if (nr_read < 0) {
1017 actual = nr_read; /* the error */
1018 break;
1019 }
1020 else if (nr_read == 0) {
1021 break;
1022 }
1023 emul_write_buffer(buf,
1024 args.addr + actual,
1025 nr_read,
1026 processor, cia);
1027 actual += nr_read;
1028 }
1029 if (actual >= 0) {
1030 args.actual = actual;
1031 if (actual < sizeof(buf))
1032 buf[actual] = '\0';
1033 else
1034 buf[sizeof(buf) - 1] = '\0';
1035 }
1036 else {
1037 switch (actual) {
1038 case sim_io_eof:
1039 args.actual = 0;
1040 break;
1041 case sim_io_not_ready:
1042 ASSERT(sim_io_not_ready == -2);
1043 args.actual = sim_io_not_ready;
1044 break;
1045 default:
1046 error("Bad error value %ld", (long)actual);
1047 break;
1048 }
1049 }
1050 }
1051 /* return the result */
1052 TRACE(trace_os_emul, ("read - out - actual=%ld `%s'\n",
1053 (long)args.actual,
1054 ((args.actual > 0 && args.actual < sizeof(buf)) ? buf : "")
1055 ));
1056 chirp_write_h2t_args(&args,
1057 sizeof(args),
1058 data,
1059 processor, cia);
1060 return 0;
1061 }
1062
1063 static int
1064 chirp_emul_write(os_emul_data *data,
1065 cpu *processor,
1066 unsigned_word cia)
1067 {
1068 struct write_args {
1069 /*in*/
1070 unsigned_cell ihandle;
1071 unsigned_cell addr;
1072 unsigned_cell len;
1073 /*out*/
1074 unsigned_cell actual;
1075 } args;
1076 char buf[1024];
1077 device_instance *ihandle;
1078 int actual;
1079 /* get the args */
1080 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
1081 return -1;
1082 actual = args.len;
1083 if (actual >= sizeof(buf))
1084 actual = sizeof(buf) - 1;
1085 emul_read_buffer(buf,
1086 args.addr,
1087 actual,
1088 processor, cia);
1089 buf[actual] = '\0';
1090 ihandle = external_to_device_instance(data->root, args.ihandle);
1091 TRACE(trace_os_emul, ("write - in - ihandle=0x%lx(0x%lx`%s') `%s' (%ld)\n",
1092 (unsigned long)args.ihandle,
1093 (unsigned long)ihandle,
1094 ihandle_name(ihandle),
1095 buf, (long)actual));
1096 if (ihandle == NULL) {
1097 /* OpenFirmware doesn't define this error */
1098 error("chirp: invalid ihandle passed to write method");
1099 }
1100 else {
1101 /* write it out */
1102 actual = device_instance_write(ihandle, buf, actual);
1103 if (actual < 0)
1104 args.actual = 0;
1105 else
1106 args.actual = actual;
1107 }
1108 /* return the result */
1109 TRACE(trace_os_emul, ("write - out - actual=%ld\n",
1110 (long)args.actual));
1111 chirp_write_h2t_args(&args,
1112 sizeof(args),
1113 data,
1114 processor, cia);
1115 return 0;
1116 }
1117
1118 static int
1119 chirp_emul_seek(os_emul_data *data,
1120 cpu *processor,
1121 unsigned_word cia)
1122 {
1123 struct seek_args {
1124 /*in*/
1125 unsigned_cell ihandle;
1126 unsigned_cell pos_hi;
1127 unsigned_cell pos_lo;
1128 /*out*/
1129 unsigned_cell status;
1130 } args;
1131 int status;
1132 device_instance *ihandle;
1133 /* get the args */
1134 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia))
1135 return -1;
1136 ihandle = external_to_device_instance(data->root, args.ihandle);
1137 TRACE(trace_os_emul, ("seek - in - ihandle=0x%lx(0x%lx`%s') pos.hi=0x%lx pos.lo=0x%lx\n",
1138 (unsigned long)args.ihandle,
1139 (unsigned long)ihandle,
1140 ihandle_name(ihandle),
1141 args.pos_hi, args.pos_lo));
1142 if (ihandle == NULL) {
1143 /* OpenFirmware doesn't define this error */
1144 error("chirp: invalid ihandle passed to seek method");
1145 }
1146 else {
1147 /* seek it out */
1148 status = device_instance_seek(ihandle, args.pos_hi, args.pos_lo);
1149 args.status = status;
1150 }
1151 /* return the result */
1152 TRACE(trace_os_emul, ("seek - out - status=%ld\n",
1153 (long)args.status));
1154 chirp_write_h2t_args(&args,
1155 sizeof(args),
1156 data,
1157 processor, cia);
1158 return 0;
1159 }
1160
1161
1162 /* memory */
1163
1164 static int
1165 chirp_emul_claim(os_emul_data *data,
1166 cpu *processor,
1167 unsigned_word cia)
1168 {
1169 /* NOTE: the client interface claim routine is *very* different to
1170 the "claim" method described in IEEE-1275 appendix A. The latter
1171 uses real addresses while this uses virtual (effective)
1172 addresses. */
1173 struct claim_args {
1174 /* in */
1175 unsigned_cell virt;
1176 unsigned_cell size;
1177 unsigned_cell align;
1178 /* out */
1179 unsigned_cell baseaddr;
1180 } args;
1181 /* read the args */
1182 if (chirp_read_t2h_args(&args, sizeof(args),
1183 3 /*n_args*/, 1 /*n_returns*/,
1184 data, processor, cia))
1185 return -1;
1186 TRACE(trace_os_emul, ("claim - in - virt=0x%lx size=%ld align=%d\n",
1187 (unsigned long)args.virt,
1188 (long int)args.size,
1189 (int)args.align));
1190 /* use the memory device to allocate (real) memory at the requested
1191 address */
1192 {
1193 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
1194 unsigned_cell mem_in[3];
1195 unsigned_cell mem_out[1];
1196 mem_in[0] = args.align; /*top-of-stack*/
1197 mem_in[1] = args.size;
1198 mem_in[2] = args.virt;
1199 if (device_instance_call_method(memory, "claim",
1200 3, mem_in, 1, mem_out) < 0)
1201 error("chirp: claim failed to allocate memory virt=0x%lx size=%ld align=%d",
1202 (unsigned long)args.virt,
1203 (long int)args.size,
1204 (int)args.align);
1205 args.baseaddr = mem_out[0];
1206 }
1207 /* if using virtual addresses, create a 1-1 map of this address space */
1208 if (!data->real_mode) {
1209 error("chirp: claim method does not support virtual mode");
1210 }
1211 /* return the base address */
1212 TRACE(trace_os_emul, ("claim - out - baseaddr=0x%lx\n",
1213 (unsigned long)args.baseaddr));
1214 chirp_write_h2t_args(&args,
1215 sizeof(args),
1216 data,
1217 processor, cia);
1218 return 0;
1219 }
1220
1221 static int
1222 chirp_emul_release(os_emul_data *data,
1223 cpu *processor,
1224 unsigned_word cia)
1225 {
1226 /* NOTE: the client interface release routine is *very* different to
1227 the "claim" method described in IEEE-1275 appendix A. The latter
1228 uses real addresses while this uses virtual (effective)
1229 addresses. */
1230 struct claim_args {
1231 /* in */
1232 unsigned_cell virt;
1233 unsigned_cell size;
1234 /* out */
1235 } args;
1236 /* read the args */
1237 if (chirp_read_t2h_args(&args, sizeof(args),
1238 2 /*n_args*/, 0 /*n_returns*/,
1239 data, processor, cia))
1240 return -1;
1241 TRACE(trace_os_emul, ("release - in - virt=0x%lx size=%ld\n",
1242 (unsigned long)args.virt,
1243 (long int)args.size));
1244 /* use the memory device to release (real) memory at the requested
1245 address */
1246 {
1247 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory");
1248 unsigned_cell mem_in[2];
1249 mem_in[0] = args.size;
1250 mem_in[1] = args.virt;
1251 if (device_instance_call_method(memory, "release",
1252 2, mem_in, 0, NULL) < 0)
1253 error("chirp: claim failed to release memory virt=0x%lx size=%ld",
1254 (unsigned long)args.virt,
1255 (long int)args.size);
1256 }
1257 /* if using virtual addresses, remove the 1-1 map of this address space */
1258 if (!data->real_mode) {
1259 error("chirp: release method does not support virtual mode");
1260 }
1261 /* return the base address */
1262 TRACE(trace_os_emul, ("release - out\n"));
1263 chirp_write_h2t_args(&args,
1264 sizeof(args),
1265 data,
1266 processor, cia);
1267 return 0;
1268 }
1269
1270
1271 /* Control transfer */
1272
1273 static int
1274 chirp_emul_boot(os_emul_data *data,
1275 cpu *processor,
1276 unsigned_word cia)
1277 {
1278 /* unlike OpenFirmware this one can take an argument */
1279 struct boot_args {
1280 /*in*/
1281 unsigned_cell bootspec;
1282 /*out*/
1283 } args;
1284 char bootspec[1024];
1285 /* read in the arguments */
1286 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
1287 cpu_halt(processor, cia, was_exited, -1);
1288 if (args.bootspec != 0)
1289 emul_read_string(bootspec, args.bootspec, sizeof(bootspec),
1290 processor, cia);
1291 else
1292 strcpy(bootspec, "(null)");
1293 TRACE(trace_os_emul, ("boot - in bootspec=`%s'\n", bootspec));
1294 /* just report this and exit */
1295 printf_filtered("chrp: boot %s called, exiting.\n", bootspec);
1296 cpu_halt(processor, cia, was_exited, 0);
1297 return 0;
1298 }
1299
1300 static int
1301 chirp_emul_enter(os_emul_data *data,
1302 cpu *processor,
1303 unsigned_word cia)
1304 {
1305 error("chirp: enter method not implemented\n");
1306 return 0;
1307 }
1308
1309 static int
1310 chirp_emul_exit(os_emul_data *data,
1311 cpu *processor,
1312 unsigned_word cia)
1313 {
1314 /* unlike OpenBoot this one can take an argument */
1315 struct exit_args {
1316 /*in*/
1317 signed_cell status;
1318 /*out*/
1319 } args;
1320 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia))
1321 cpu_halt(processor, cia, was_exited, -1);
1322 cpu_halt(processor, cia, was_exited, args.status);
1323 return 0;
1324 }
1325
1326 static int
1327 chirp_emul_chain(os_emul_data *data,
1328 cpu *processor,
1329 unsigned_word cia)
1330 {
1331 error("chirp: chain method not implemented\n");
1332 return 0;
1333 }
1334
1335
1336 /* user interface */
1337
1338 static int
1339 chirp_emul_interpret(os_emul_data *data,
1340 cpu *processor,
1341 unsigned_word cia)
1342 {
1343 error("chirp: interpret method not implemented\n");
1344 return 0;
1345 }
1346
1347 static int
1348 chirp_emul_set_callback(os_emul_data *data,
1349 cpu *processor,
1350 unsigned_word cia)
1351 {
1352 error("chirp: set_callback method not implemented\n");
1353 return 0;
1354 }
1355
1356 static int
1357 chirp_emul_set_symbol_lookup(os_emul_data *data,
1358 cpu *processor,
1359 unsigned_word cia)
1360 {
1361 error("chirp: set_symbol_lookup method not implemented\n");
1362 return 0;
1363 }
1364
1365
1366 /* Time */
1367
1368 static int
1369 chirp_emul_milliseconds(os_emul_data *data,
1370 cpu *processor,
1371 unsigned_word cia)
1372 {
1373 struct test_args {
1374 /*in*/
1375 /*out*/
1376 unsigned_cell ms;
1377 } args;
1378 unsigned64 time;
1379 /* read in the arguments */
1380 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia))
1381 return -1;
1382 /* make up a number */
1383 time = event_queue_time(psim_event_queue(cpu_system(processor))) / 1000000;
1384 args.ms = time;
1385 /* write the arguments back out */
1386 TRACE(trace_os_emul, ("milliseconds - out - ms=%ld\n",
1387 (unsigned long)args.ms));
1388 chirp_write_h2t_args(&args,
1389 sizeof(args),
1390 data,
1391 processor, cia);
1392 return 0;
1393 }
1394
1395
1396
1397
1398 static chirp_services services[] = {
1399
1400 /* client interface */
1401 { "test", chirp_emul_test },
1402
1403 /* device tree */
1404 { "peer", chirp_emul_peer },
1405 { "child", chirp_emul_child },
1406 { "parent", chirp_emul_parent },
1407 { "instance-to-package", chirp_emul_instance_to_package },
1408 { "getproplen", chirp_emul_getproplen },
1409 { "getprop", chirp_emul_getprop },
1410 { "nextprop", chirp_emul_nextprop },
1411 /* { "setprop", chirp_emul_setprop }, */
1412 { "canon", chirp_emul_canon },
1413 { "finddevice", chirp_emul_finddevice },
1414 { "instance-to-path", chirp_emul_instance_to_path },
1415 { "package-to-path", chirp_emul_package_to_path },
1416 { "call-method", chirp_emul_call_method },
1417
1418 /* device I/O */
1419 { "open", chirp_emul_open },
1420 { "close", chirp_emul_close },
1421 { "read", chirp_emul_read },
1422 { "write", chirp_emul_write },
1423 { "seek", chirp_emul_seek },
1424 { "write", chirp_emul_write },
1425
1426 /* memory */
1427 { "claim", chirp_emul_claim },
1428 { "release", chirp_emul_release },
1429
1430 /* control transfer */
1431 { "boot", chirp_emul_boot },
1432 { "enter", chirp_emul_enter },
1433 { "exit", chirp_emul_exit },
1434 { "chain", chirp_emul_chain },
1435
1436 /* user interface */
1437 { "interpret", chirp_emul_interpret },
1438 { "set_callback", chirp_emul_set_callback },
1439 { "set_symbol_lookup", chirp_emul_set_symbol_lookup },
1440
1441 /* time */
1442 { "milliseconds", chirp_emul_milliseconds },
1443
1444 { 0, /* sentinal */ },
1445 };
1446
1447
1448 /* main handlers */
1449
1450 /* Any starting address greater than this is assumed to be an Chirp
1451 rather than VEA */
1452
1453 #ifndef CHIRP_START_ADDRESS
1454 #define CHIRP_START_ADDRESS 0x80000000
1455 #endif
1456 #ifndef CHIRP_LOAD_BASE
1457 #define CHIRP_LOAD_BASE -1
1458 #endif
1459
1460
1461 typedef struct _chirp_note_desc {
1462 signed32 real_mode;
1463 signed32 real_base;
1464 signed32 real_size;
1465 signed32 virt_base;
1466 signed32 virt_size;
1467 signed32 load_base;
1468 } chirp_note_desc;
1469
1470 typedef enum {
1471 note_missing,
1472 note_found,
1473 note_correct,
1474 } note_found_status;
1475 typedef struct _chirp_note {
1476 chirp_note_desc desc;
1477 note_found_status found;
1478 } chirp_note;
1479
1480 typedef struct _chirp_note_head {
1481 unsigned32 namesz;
1482 unsigned32 descsz;
1483 unsigned32 type;
1484 } chirp_note_head;
1485
1486 static void
1487 map_over_chirp_note(bfd *image,
1488 asection *sect,
1489 PTR obj)
1490 {
1491 chirp_note *note = (chirp_note*)obj;
1492 if (strcmp(sect->name, ".note") == 0) {
1493 chirp_note_head head;
1494 char name[16];
1495 /* check the head */
1496 if (!bfd_get_section_contents(image, sect,
1497 &head, 0, sizeof(head)))
1498 return;
1499 head.namesz = bfd_get_32(image, (void*)&head.namesz);
1500 head.descsz = bfd_get_32(image, (void*)&head.descsz);
1501 head.type = bfd_get_32(image, (void*)&head.type);
1502 if (head.type != 0x1275)
1503 return;
1504 /* check the name field */
1505 if (head.namesz > sizeof(name)) {
1506 error("chirp: note name too long (%d > %d)\n", (int)head.namesz, sizeof(name));
1507 }
1508 if (!bfd_get_section_contents(image, sect,
1509 name, sizeof(head), head.namesz)) {
1510 error("chirp: note name unreadable\n");
1511 }
1512 if (strcmp(name, "PowerPC") != 0) {
1513 printf_filtered("chirp: note name (%s) not `PowerPC'\n", name);
1514 }
1515 /* check the size */
1516 if (head.descsz == sizeof(note->desc) - sizeof(signed32)) {
1517 sim_io_printf_filtered("chirp: note descriptor missing load-base\n");
1518 }
1519 else if (head.descsz != sizeof(note->desc)) {
1520 sim_io_printf_filtered("chirp: note descriptor of wrong size\n");
1521 note->found = note_found;
1522 return;
1523 }
1524 note->found = note_correct;
1525 /* get the contents */
1526 if (!bfd_get_section_contents(image, sect,
1527 &note->desc, /* page align start */
1528 ((sizeof(head) + head.namesz) + 3) & ~3,
1529 head.descsz)) {
1530 error("chirp: note descriptor unreadable\n");
1531 }
1532 note->desc.real_mode = bfd_get_32(image, (void*)&note->desc.real_mode);
1533 note->desc.real_base = bfd_get_32(image, (void*)&note->desc.real_base);
1534 note->desc.real_size = bfd_get_32(image, (void*)&note->desc.real_size);
1535 note->desc.virt_base = bfd_get_32(image, (void*)&note->desc.virt_base);
1536 note->desc.virt_size = bfd_get_32(image, (void*)&note->desc.virt_size);
1537 if (head.descsz == sizeof(note->desc))
1538 note->desc.load_base = bfd_get_32(image, (void*)&note->desc.load_base);
1539 else
1540 note->desc.load_base = CHIRP_LOAD_BASE;
1541 }
1542 }
1543
1544
1545 static os_emul_data *
1546 emul_chirp_create(device *root,
1547 bfd *image,
1548 const char *name)
1549 {
1550 os_emul_data *chirp;
1551 device *node;
1552 chirp_note note;
1553 int i;
1554
1555 /* Sanity check that this really is the chosen emulation */
1556 if (name == NULL && image == NULL)
1557 return NULL;
1558 if (name != NULL
1559 && strcmp(name, "ob") != 0
1560 && strcmp(name, "ieee1274") != 0
1561 && strcmp(name, "chrp") != 0
1562 && strcmp(name, "chirp") != 0
1563 && strcmp(name, "openboot") != 0)
1564 return NULL;
1565
1566 /* look for an elf note section, enter its values into the device tree */
1567 memset(&note, 0, sizeof(note));
1568 if (image != NULL)
1569 bfd_map_over_sections(image, map_over_chirp_note, &note);
1570 if (name == NULL && image != NULL && note.found == note_missing)
1571 return NULL;
1572
1573 /* Assume that it is a chirp emulation */
1574
1575 chirp = ZALLOC(os_emul_data);
1576 chirp->root = root;
1577 chirp->services = services;
1578
1579 /* the root node */
1580 tree_parse(root, "/name \"gpl,clayton");
1581
1582 /* default options */
1583 emul_add_tree_options(root, image, "chirp", "oea",
1584 0 /*oea-interrupt-prefix*/);
1585
1586 /* hardware */
1587 emul_add_tree_hardware(root);
1588
1589 /* basic information */
1590 chirp->memory_size
1591 = tree_find_integer_property(root, "/openprom/options/oea-memory-size");
1592 chirp->little_endian
1593 = tree_find_boolean_property(root, "/options/little-endian?");
1594 chirp->floating_point_available
1595 = tree_find_boolean_property(root, "/openprom/options/floating-point?");
1596 chirp->interrupt_prefix =
1597 tree_find_integer_property(root, "/openprom/options/oea-interrupt-prefix");
1598
1599
1600 /* Perform an interum layout of the openboot firmware in memory */
1601
1602
1603 /* a page for firmware calls */
1604 chirp->sizeof_code = 4096;
1605 chirp->code_offset = 0x4000; /* possible space for interrupt table */
1606
1607 /* the stack */
1608 chirp->sizeof_stack = 32 * 1024;
1609 chirp->stack_offset = chirp->code_offset + chirp->sizeof_code;
1610
1611 /* the hash table */
1612 if (!note.desc.real_mode) {
1613 chirp->nr_page_table_entry_groups = (chirp->memory_size < 0x800000
1614 ? 1024 /* min allowed */
1615 : (chirp->memory_size / 4096 / 2));
1616 chirp->sizeof_htab = chirp->nr_page_table_entry_groups * 64;
1617 }
1618 chirp->htab_offset = chirp->stack_offset + chirp->sizeof_stack;
1619
1620 /* the actual amount of space needed */
1621 chirp->real_size = chirp->htab_offset + chirp->sizeof_htab;
1622
1623
1624 /* now go through and see if it fits in what is available */
1625
1626
1627 /* resolve real-mode? */
1628 if (note.found == note_correct)
1629 chirp->real_mode = note.desc.real_mode;
1630 else if (tree_find_property(root, "/options/real-mode?") != NULL)
1631 chirp->real_mode = tree_find_boolean_property(root, "/options/real-mode?");
1632 else
1633 chirp->real_mode = 0;
1634 if (tree_find_property(root, "/options/real-mode?") != NULL) {
1635 if (!chirp->real_mode
1636 != !tree_find_boolean_property(root, "/options/real-mode?"))
1637 error("chirp: /options/real-mode? conflicts with note section\n");
1638 }
1639 else
1640 tree_parse(root, "/options/real-mode? %s",
1641 chirp->real_mode ? "true" : "false");
1642
1643 /* resolve real-base */
1644 if (note.found == note_correct
1645 && note.desc.real_base != (signed32)-1)
1646 chirp->real_base = note.desc.real_base;
1647 else if (tree_find_property(root, "/options/real-base") != NULL)
1648 chirp->real_base = tree_find_integer_property(root, "/options/real-base");
1649 else
1650 chirp->real_base = chirp->memory_size - chirp->real_size;
1651 if (tree_find_property(root, "/options/real-base") != NULL) {
1652 if (chirp->real_base != tree_find_integer_property(root, "/options/real-base"))
1653 error("chirp: /options/real-base conflicts with note section\n");
1654 }
1655 else
1656 tree_parse(root, "/options/real-base 0x%lx",
1657 (unsigned long)chirp->real_base);
1658
1659 /* resolve real-size */
1660 if (note.found == note_correct
1661 && note.desc.real_size != (signed32)-1
1662 && note.desc.real_size != 0
1663 && chirp->real_size > note.desc.real_size)
1664 error("chirp: insufficient physical memory for firmware\n");
1665 if (tree_find_property(root, "/options/real-size") != NULL) {
1666 if (chirp->real_size > tree_find_integer_property(root, "/options/real-size"))
1667 error("chirp: /options/real-size conflicts with note section\n");
1668 }
1669 else
1670 tree_parse(root, "/options/real-size 0x%lx",
1671 (unsigned long)chirp->real_size);
1672
1673 /* resolve virt-base */
1674 if (chirp->real_mode)
1675 chirp->virt_base = chirp->real_base;
1676 else if (note.found == note_correct && note.desc.virt_base != -1)
1677 chirp->virt_base = note.desc.virt_base;
1678 else if (tree_find_property(root, "/options/virt-base") != NULL)
1679 chirp->virt_base = tree_find_integer_property(root, "/options/virt-base");
1680 else
1681 chirp->virt_base = CHIRP_START_ADDRESS;
1682 if (tree_find_property(root, "/options/virt-base") != NULL) {
1683 unsigned_word virt_base = tree_find_integer_property(root, "/options/virt-base");
1684 if (virt_base != -1 && chirp->virt_base != virt_base)
1685 error("chirp: /options/virt-base conflicts with note section\n");
1686 }
1687 else
1688 tree_parse(root, "/options/virt-base 0x%lx",
1689 chirp->real_mode ? -1 : (unsigned long)chirp->virt_base);
1690
1691 /* resolve virt-size */
1692 chirp->virt_size = chirp->real_size;
1693 if (note.found == note_correct
1694 && note.desc.virt_size != (signed32)-1
1695 && note.desc.virt_size != 0
1696 && !chirp->real_mode
1697 && chirp->virt_size > note.desc.virt_size)
1698 error("chirp: insufficent virtual memory for firmware\n");
1699 if (tree_find_property(root, "/options/virt-size") != NULL) {
1700 if (chirp->virt_size > tree_find_integer_property(root, "/options/virt-size"))
1701 error("chirp: /options/virt-size conflicts with note section\n");
1702 }
1703 else
1704 tree_parse(root, "/options/virt-size 0x%lx",
1705 chirp->real_mode ? -1 : (unsigned long)chirp->virt_size);
1706
1707 /* resolve load-base */
1708 if (note.found == note_correct
1709 && note.desc.load_base != (signed32)-1)
1710 chirp->load_base = note.desc.load_base;
1711 else if (tree_find_property(root, "/options/load-base") != NULL)
1712 chirp->load_base = tree_find_integer_property(root, "/options/load-base");
1713 else
1714 chirp->load_base = CHIRP_LOAD_BASE;
1715 if (tree_find_property(root, "/options/load-base") != NULL) {
1716 if (chirp->load_base != tree_find_integer_property(root, "/options/load-base"))
1717 error("chirp: /options/load-base conflicts with note section\n");
1718 }
1719 else
1720 tree_parse(root, "/options/load-base 0x%lx",
1721 (unsigned long)chirp->load_base);
1722
1723 /* now adjust the preliminary firmware addresses to final values */
1724 chirp->code_ra = chirp->code_offset + chirp->real_base;
1725 chirp->stack_ra = chirp->stack_offset + chirp->real_base;
1726 chirp->htab_ra = chirp->htab_offset + chirp->real_base;
1727
1728 /* the virtual addresses. In real mode these are real addresses. */
1729
1730 chirp->code_va = chirp->code_offset + chirp->virt_base;
1731 chirp->stack_va = chirp->stack_offset + chirp->virt_base;
1732 chirp->htab_va = chirp->htab_offset + chirp->virt_base;
1733
1734 chirp->code_client_va = chirp->code_va;
1735 chirp->code_client_ra = chirp->code_ra;
1736
1737 chirp->code_callback_va = chirp->code_client_va + 16;
1738 chirp->code_callback_ra = chirp->code_client_ra + 16;
1739
1740 chirp->code_loop_va = chirp->code_callback_va + 16;
1741 chirp->code_loop_ra = chirp->code_callback_ra + 16;
1742
1743 /* initialization */
1744
1745 tree_parse(root, "/openprom/init");
1746 tree_parse(root, "/openprom/init/register");
1747 tree_parse(root, "/openprom/init/register/0.pc 0x%lx",
1748 (unsigned long)bfd_get_start_address(image));
1749 tree_parse(root, "/openprom/init/register/pc 0x%lx",
1750 (unsigned long)chirp->code_loop_va);
1751 tree_parse(root, "/openprom/init/register/msr 0x%x",
1752 (msr_machine_check_enable
1753 | (chirp->real_mode
1754 ? 0
1755 : (msr_instruction_relocate
1756 | msr_data_relocate))
1757 | (chirp->little_endian
1758 ? (msr_little_endian_mode
1759 | msr_interrupt_little_endian_mode)
1760 : 0)
1761 | (chirp->floating_point_available
1762 ? msr_floating_point_available
1763 : 0)
1764 | (chirp->interrupt_prefix
1765 ? msr_interrupt_prefix
1766 : 0)
1767 ));
1768 tree_parse(root, "/openprom/init/register/sdr1 0x%lx",
1769 (unsigned long)(chirp->htab_ra
1770 | MASK32(16, 22)
1771 | ((chirp->sizeof_htab - 1) >> 16)));
1772 /* make certain that the segment registers map straight through */
1773 for (i = 0; i < 16; i++) {
1774 tree_parse(root, "/openprom/init/register/sr%d 0x%lx",
1775 i, (unsigned long)i);
1776 }
1777
1778 /* establish an initial state for all processors */
1779
1780
1781 /* the client interface address */
1782 tree_parse(root, "/openprom/init/register/r5 0x%lx",
1783 (unsigned long)chirp->code_client_va);
1784 /* a stack */
1785 tree_parse(root, "/openprom/init/register/sp 0x%lx",
1786 (unsigned long)(chirp->stack_va + chirp->sizeof_stack - 16));
1787 /* in chrp mode any arguments end up being concatinated */
1788 tree_parse(root, "/openprom/init/stack/stack-type chirp");
1789
1790
1791 /* client interface - emul-call followed by return instruction */
1792
1793
1794 node = tree_parse(root, "/openprom/init/data@0x%lx",
1795 (unsigned long)chirp->code_client_ra);
1796 tree_parse(node, "./psim,description \"client-interface instruction");
1797 tree_parse(node, "./real-address 0x%lx",
1798 (unsigned long)chirp->code_client_ra);
1799 tree_parse(node, "./data 0x%lx",
1800 (unsigned long)emul_call_instruction);
1801
1802 node = tree_parse(root, "/openprom/init/data@0x%lx",
1803 (unsigned long)(chirp->code_client_ra + 4));
1804 tree_parse(node, "./psim,description \"client-interface return instruction");
1805 tree_parse(node, "./real-address 0x%lx",
1806 (unsigned long)(chirp->code_client_ra + 4));
1807 tree_parse(node, "./data 0x%lx",
1808 (unsigned long)emul_blr_instruction);
1809
1810
1811 /* return address for client callbacks - an emul-call instruction
1812 that is again followed by a return instruction */
1813
1814
1815 node = tree_parse(root, "/openprom/init/data@0x%lx",
1816 (unsigned long)chirp->code_callback_ra);
1817 tree_parse(node, "./psim,description \"client-callback instruction");
1818 tree_parse(node, "./real-address 0x%lx",
1819 (unsigned long)chirp->code_callback_ra);
1820 tree_parse(node, "./data 0x%lx",
1821 (unsigned long)emul_call_instruction);
1822
1823 node = tree_parse(root, "/openprom/init/data@0x%lx",
1824 (unsigned long)(chirp->code_callback_ra + 4));
1825 tree_parse(node, "./psim,description \"client-callback return instruction");
1826 tree_parse(node, "./real-address 0x%lx",
1827 (unsigned long)(chirp->code_callback_ra + 4));
1828 tree_parse(node, "./data 0x%lx",
1829 (unsigned long)emul_blr_instruction);
1830
1831 /* loop to keep other processors busy */
1832
1833 node = tree_parse(root, "/openprom/init/data@0x%lx",
1834 (unsigned long)chirp->code_loop_ra);
1835 tree_parse(node, "./psim,description \"processor busy loop");
1836 tree_parse(node, "./real-address 0x%lx",
1837 (unsigned long)chirp->code_loop_ra);
1838 tree_parse(node, "./data 0x%lx",
1839 (unsigned long)emul_loop_instruction);
1840
1841 /* hash table */
1842
1843 /* create a hash table */
1844
1845 if (!chirp->real_mode) {
1846 node = tree_parse(root, "/openprom/init/htab@0x%lx",
1847 (unsigned long)chirp->htab_ra);
1848 tree_parse(node, "./claim 0");
1849 tree_parse(node, "./real-address 0x%lx",
1850 (unsigned long)chirp->htab_ra);
1851 tree_parse(node, "./nr-bytes 0x%lx",
1852 (unsigned long)chirp->sizeof_htab);
1853 }
1854
1855 /* map in the stack */
1856
1857 if (!chirp->real_mode) {
1858 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1859 (unsigned long)chirp->stack_ra);
1860 tree_parse(node, "./psim,description \"map in the stack");
1861 tree_parse(node, "./claim 1");
1862 tree_parse(node, "./virtual-address 0x%lx",
1863 (unsigned long)chirp->stack_va);
1864 tree_parse(node, "./real-address 0x%lx",
1865 (unsigned long)chirp->stack_ra);
1866 tree_parse(node, "./nr-bytes 0x%lx",
1867 (unsigned long)chirp->sizeof_stack);
1868 tree_parse(node, "./wimg %d", 0x7);
1869 tree_parse(node, "./pp %d", 0x2);
1870 }
1871
1872 /* map in the chrp openboot callback code */
1873
1874 if (!chirp->real_mode) {
1875 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1876 (unsigned long)chirp->code_ra);
1877 tree_parse(node, "./psim,description \"map in chrp openboot callback code");
1878 tree_parse(node, "./claim 1");
1879 tree_parse(node, "./virtual-address 0x%lx",
1880 (unsigned long)chirp->code_va);
1881 tree_parse(node, "./real-address 0x%lx",
1882 (unsigned long)chirp->code_ra);
1883 tree_parse(node, "./nr-bytes 0x%lx",
1884 (unsigned long)chirp->sizeof_code);
1885 tree_parse(node, "./wimg %d", 0x7);
1886 tree_parse(node, "./pp %d", 0x2);
1887 }
1888
1889 /* map in the program to run */
1890
1891 if (chirp->real_mode) {
1892 node = tree_parse(node, "/openprom/init/load-binary");
1893 tree_parse(node, "./psim,description \"load the binary");
1894 tree_parse(node, "./file-name %s", bfd_get_filename(image));
1895 tree_parse(node, "./claim 1");
1896 }
1897 else {
1898 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx",
1899 (unsigned long)chirp->load_base);
1900 tree_parse(node, "./psim,description \"load & map the binary");
1901 tree_parse(node, "./claim 1");
1902 tree_parse(node, "./file-name \"%s", bfd_get_filename(image));
1903 tree_parse(node, "./wimg %d", 0x7);
1904 tree_parse(node, "./pp %d", 0x2);
1905 }
1906
1907 return chirp;
1908 }
1909
1910 static void
1911 emul_chirp_init(os_emul_data *emul_data,
1912 int nr_cpus)
1913 {
1914 emul_data->state = serving;
1915 }
1916
1917 static int
1918 emul_chirp_instruction_call(cpu *processor,
1919 unsigned_word cia,
1920 unsigned_word ra,
1921 os_emul_data *emul_data)
1922 {
1923 unsigned_word service_name_addr;
1924 unsigned_word result;
1925 char service_buf[32];
1926 char *service_name;
1927 chirp_services *service;
1928
1929 switch (emul_data->state) {
1930
1931 case serving:
1932 /* we are waiting on an OpenBoot request from the client program
1933 via the client interface */
1934 if (cia != emul_data->code_client_va)
1935 return 0;
1936 emul_data->return_address = LR;
1937 emul_data->arguments = cpu_registers(processor)->gpr[3];
1938 /* try to determine what to do */
1939 service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3],
1940 processor, cia);
1941 service_name = emul_read_string(service_buf, service_name_addr,
1942 sizeof(service_buf), processor, cia);
1943 emul_data->n_args = emul_read_word(emul_data->arguments + sizeof(unsigned_cell),
1944 processor, cia);
1945 emul_data->n_returns = emul_read_word(emul_data->arguments + 2 * sizeof(unsigned_cell),
1946 processor, cia);
1947 /* verify what was passed */
1948 if (service_name_addr == 0
1949 || service_name == NULL) {
1950 error("OpenFirmware called with invalid (NULL) service name from 0x%lx with args 0x%lx\n",
1951 (unsigned long)emul_data->return_address,
1952 (unsigned long)emul_data->arguments);
1953 }
1954 if (emul_data->n_args > 6) { /* See iee1275 requirements on nr returns */
1955 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, too many args (%d)\n",
1956 (unsigned long)emul_data->return_address,
1957 (unsigned long)emul_data->arguments,
1958 emul_data->n_returns);
1959 }
1960 if (emul_data->n_returns > 6) {
1961 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, with too many returns (%d)\n",
1962 (unsigned long)emul_data->return_address,
1963 (unsigned long)emul_data->arguments,
1964 emul_data->n_args);
1965 }
1966 /* look it up */
1967 TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n",
1968 service_name,
1969 (unsigned long)emul_data->return_address,
1970 (unsigned long)emul_data->arguments));
1971 service = services;
1972 while (service->name != NULL && strcmp(service->name, service_name) != 0)
1973 service++;
1974 /* found or not? */
1975 if (service->name == NULL) {
1976 error("OpenBoot service `%s' not found\n", service_name);
1977 TRACE(trace_os_emul, ("%s not found\n", service_name));
1978 cpu_registers(processor)->gpr[3] = -1;
1979 }
1980 else {
1981 emul_data->service = service;
1982 /* call upon it */
1983 result = service->handler(emul_data, processor, cia);
1984 if (result != 0)
1985 TRACE(trace_os_emul, ("%s aborted with %ld\n", service_name, (long)result));
1986 cpu_registers(processor)->gpr[3] = result;
1987 }
1988 break;
1989
1990 default:
1991 error("emul_chirp_instruction_call() unknown internal state\n");
1992 result = -1;
1993 break;
1994
1995 }
1996
1997 /* return to caller - instruction following this is a function return */
1998 return 1;
1999 }
2000
2001 const os_emul emul_chirp = {
2002 "chirp",
2003 emul_chirp_create,
2004 emul_chirp_init,
2005 NULL, /*system_call*/
2006 emul_chirp_instruction_call,
2007 0 /*data*/
2008 };
2009
2010 #endif