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