1 /* This file is part of the program psim.
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifndef _EMUL_CHIRP_C_
23 #define _EMUL_CHIRP_C_
25 /* Note: this module is called via a table. There is no benefit in
28 #include "emul_generic.h"
29 #include "emul_chirp.h"
43 #ifndef STATIC_INLINE_EMUL_CHIRP
44 #define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE
48 /* Descriptor of the open boot services being emulated */
50 typedef int (chirp_handler
)
54 typedef struct _chirp_services
{
56 chirp_handler
*handler
;
60 /* The OpenBoot emulation is, at any time either waiting for a client
61 request or waiting on a client callback */
68 struct _os_emul_data
{
69 chirp_emul_state state
;
70 unsigned_word return_address
;
71 unsigned_word arguments
;
72 chirp_services
*service
;
73 unsigned_word serving_instruction_ea
;
74 unsigned_word catching_instruction_ea
;
80 /* OpenBoot emulation functions */
83 chirp_emul_child(os_emul_data
*data
,
94 unsigned32 child_phandle
;
98 emul_read_buffer(&args
, data
->arguments
,
101 if (T2H_4(args
.n_args
) != 1 || T2H_4(args
.n_returns
) != 1) {
102 TRACE(trace_os_emul
, ("child - invalid nr - n_args=%ld, n_returns=%ld\n",
103 (long)T2H_4(args
.n_args
),
104 (long)T2H_4(args
.n_returns
)));
107 /* read in the arguments */
108 dev
= cap_internal(data
->phandles
, args
.phandle
);
109 TRACE(trace_os_emul
, ("child - in - phandle=0x%lx(0x%lx`%s')\n",
110 (unsigned long)T2H_4(args
.phandle
),
112 (dev
== NULL
? "" : device_name(dev
))));
113 if (dev
== (device
*)0)
115 child_dev
= device_child(dev
);
116 if (child_dev
== NULL
)
117 args
.child_phandle
= 0;
119 args
.child_phandle
= cap_external(data
->phandles
, child_dev
);
120 TRACE(trace_os_emul
, ("child - out - child_phandle=0x%lx(0x%lx`%s')\n",
121 (unsigned long)T2H_4(args
.child_phandle
),
122 (unsigned long)child_dev
,
123 (child_dev
== NULL
? "" : device_name(child_dev
))));
124 emul_write_buffer(&args
, data
->arguments
,
131 chirp_emul_exit(os_emul_data
*data
,
135 cpu_halt(processor
, cia
, was_exited
, 0); /* always succeeds */
140 chirp_emul_finddevice(os_emul_data
*data
,
144 struct finddevice_args
{
147 unsigned32 n_returns
;
149 unsigned32 device_specifier
;
153 char device_specifier
[1024];
155 emul_read_buffer(&args
, data
->arguments
,
158 if (T2H_4(args
.n_args
) != 1 || T2H_4(args
.n_returns
) != 1) {
159 TRACE(trace_os_emul
, ("finddevice - invalid nr - n_args=%ld, n_returns=%ld\n",
160 (long)T2H_4(args
.n_args
),
161 (long)T2H_4(args
.n_returns
)));
164 emul_read_string(device_specifier
,
165 T2H_4(args
.device_specifier
),
166 sizeof(device_specifier
),
168 TRACE(trace_os_emul
, ("finddevice - in - device_specifier=`%s'\n",
170 dev
= device_tree_find_device(data
->root
,
172 if (dev
== (device
*)0)
175 args
.phandle
= cap_external(data
->phandles
, dev
);
176 TRACE(trace_os_emul
, ("finddevice - out - phandle=0x%lx(0x%lx`%s')\n",
177 (unsigned long)T2H_4(args
.phandle
),
179 (dev
== NULL
? "" : device_name(dev
))));
180 emul_write_buffer(&args
, data
->arguments
,
187 chirp_emul_getprop(os_emul_data
*data
,
191 struct getprop_args
{
194 unsigned32 n_returns
;
205 const device_property
*prop
;
206 emul_read_buffer(&args
, data
->arguments
,
209 if (T2H_4(args
.n_args
) != 4 || T2H_4(args
.n_returns
) != 1) {
210 TRACE(trace_os_emul
, ("getprop - invalid nr - n_args=%ld, n_returns=%ld\n",
211 (long)T2H_4(args
.n_args
),
212 (long)T2H_4(args
.n_returns
)));
215 /* read in the arguments */
216 dev
= cap_internal(data
->phandles
, args
.phandle
);
217 emul_read_string(name
,
221 TRACE(trace_os_emul
, ("getprop - in - phandle=0x%lx(0x%lx`%s') name=`%s' buf=0x%lx buflen=%ld\n",
222 (unsigned long)T2H_4(args
.phandle
),
224 (dev
== NULL
? "" : device_name(dev
)),
226 (unsigned long)T2H_4(args
.buf
),
227 (unsigned long)T2H_4(args
.buflen
)));
228 if (dev
== (device
*)0)
230 prop
= device_find_property(dev
, name
);
231 if (prop
== (device_property
*)0) {
235 int size
= T2H_4(args
.buflen
);
236 if (size
> prop
->sizeof_array
)
237 size
= prop
->sizeof_array
;
238 emul_write_buffer(prop
->array
, T2H_4(args
.buf
),
241 args
.size
= H2T_4(size
);
243 switch (prop
->type
) {
244 case string_property
:
245 TRACE(trace_os_emul
, ("getprop - value=`%s' (string)\n",
246 (char*)prop
->array
));
251 TRACE(trace_os_emul
, ("getprop - out - size=%ld\n",
252 (unsigned long)T2H_4(args
.size
)));
253 emul_write_buffer(&args
, data
->arguments
,
260 chirp_emul_getproplen(os_emul_data
*data
,
264 struct getproplen_args
{
267 unsigned32 n_returns
;
276 const device_property
*prop
;
277 emul_read_buffer(&args
, data
->arguments
,
280 if (T2H_4(args
.n_args
) != 2 || T2H_4(args
.n_returns
) != 1) {
281 TRACE(trace_os_emul
, ("getproplen - invalid nr - n_args=%ld, n_returns=%ld\n",
282 (long)T2H_4(args
.n_args
),
283 (long)T2H_4(args
.n_returns
)));
286 /* read in the arguments */
287 dev
= cap_internal(data
->phandles
, args
.phandle
);
288 if (dev
== (device
*)0)
290 emul_read_string(name
,
294 TRACE(trace_os_emul
, ("getproplen - in - phandle=0x%lx(0x%lx`%s') name=`%s'\n",
295 (unsigned long)T2H_4(args
.phandle
),
297 (dev
== NULL
? "" : device_name(dev
)),
299 prop
= device_find_property(dev
, name
);
300 if (prop
== (device_property
*)0) {
304 args
.proplen
= H2T_4(prop
->sizeof_array
);
306 TRACE(trace_os_emul
, ("getproplen - out - proplen=%ld\n",
307 (unsigned long)T2H_4(args
.proplen
)));
308 emul_write_buffer(&args
, data
->arguments
,
315 chirp_emul_open(os_emul_data
*data
,
322 unsigned32 n_returns
;
324 unsigned32 device_specifier
;
329 emul_read_buffer(&args
, data
->arguments
,
332 if (T2H_4(args
.n_args
) != 1 || T2H_4(args
.n_returns
) != 1) {
333 TRACE(trace_os_emul
, ("open - invalid nr - n_args=%ld, n_returns=%ld\n",
334 (long)T2H_4(args
.n_args
),
335 (long)T2H_4(args
.n_returns
)));
338 /* read in the arguments */
339 emul_read_string(name
,
340 T2H_4(args
.device_specifier
),
343 TRACE(trace_os_emul
, ("open - in - device_specifier=`%s'\n",
345 printf_filtered("OpenBoot - open unimplemented for %s\n", name
);
347 TRACE(trace_os_emul
, ("open - out - ihandle=0x%lx\n",
348 (unsigned long)T2H_4(args
.ihandle
)));
349 emul_write_buffer(&args
, data
->arguments
,
356 chirp_emul_parent(os_emul_data
*data
,
363 unsigned32 n_returns
;
367 unsigned32 parent_phandle
;
371 emul_read_buffer(&args
, data
->arguments
,
374 if (T2H_4(args
.n_args
) != 1 || T2H_4(args
.n_returns
) != 1) {
375 TRACE(trace_os_emul
, ("parent - invalid nr - n_args=%ld, n_returns=%ld\n",
376 (long)T2H_4(args
.n_args
),
377 (long)T2H_4(args
.n_returns
)));
380 /* read in the arguments */
381 dev
= cap_internal(data
->phandles
, args
.phandle
);
382 TRACE(trace_os_emul
, ("parent - in - phandle=0x%lx(0x%lx`%s')\n",
383 (unsigned long)T2H_4(args
.phandle
),
385 (dev
== NULL
? "" : device_name(dev
))));
386 if (dev
== (device
*)0)
388 parent_dev
= device_parent(dev
);
389 if (parent_dev
== NULL
)
390 args
.parent_phandle
= 0;
392 args
.parent_phandle
= cap_external(data
->phandles
, parent_dev
);
393 TRACE(trace_os_emul
, ("parent - out - parent_phandle=0x%lx(0x%lx`%s')\n",
394 (unsigned long)T2H_4(args
.parent_phandle
),
395 (unsigned long)parent_dev
,
396 (parent_dev
== NULL
? "" : device_name(parent_dev
))));
397 emul_write_buffer(&args
, data
->arguments
,
404 chirp_emul_peer(os_emul_data
*data
,
411 unsigned32 n_returns
;
415 unsigned32 sibling_phandle
;
418 device
*sibling_dev
= NULL
;
419 emul_read_buffer(&args
, data
->arguments
,
422 if (T2H_4(args
.n_args
) != 1 || T2H_4(args
.n_returns
) != 1) {
423 TRACE(trace_os_emul
, ("peer - invalid nr - n_args=%ld, n_returns=%ld\n",
424 (long)T2H_4(args
.n_args
),
425 (long)T2H_4(args
.n_returns
)));
428 /* read in the arguments */
429 dev
= cap_internal(data
->phandles
, args
.phandle
);
430 TRACE(trace_os_emul
, ("peer - in - phandle=0x%lx(0x%lx`%s')\n",
431 (unsigned long)T2H_4(args
.phandle
),
433 (dev
== NULL
? "" : device_name(dev
))));
434 if (dev
== NULL
&& args
.phandle
!= 0)
436 if (args
.phandle
== 0)
437 sibling_dev
= data
->root
;
439 sibling_dev
= device_sibling(dev
);
440 if (sibling_dev
== NULL
)
441 args
.sibling_phandle
= 0;
443 args
.sibling_phandle
= cap_external(data
->phandles
, sibling_dev
);
444 TRACE(trace_os_emul
, ("peer - out - sibling_phandle=0x%lx(0x%lx`%s')\n",
445 (unsigned long)T2H_4(args
.sibling_phandle
),
446 (unsigned long)sibling_dev
,
447 (sibling_dev
== NULL
? "" : device_name(sibling_dev
))));
448 emul_write_buffer(&args
, data
->arguments
,
455 chirp_emul_read(os_emul_data
*data
,
462 unsigned32 n_returns
;
472 emul_read_buffer(&args
, data
->arguments
,
475 if (T2H_4(args
.n_args
) != 3 || T2H_4(args
.n_returns
) != 1) {
476 TRACE(trace_os_emul
, ("read - invalid nr - n_args=%ld, n_returns=%ld\n",
477 (long)T2H_4(args
.n_args
),
478 (long)T2H_4(args
.n_returns
)));
481 /* read in the arguments */
482 actual
= T2H_4(args
.len
);
483 if (actual
>= sizeof(buf
))
484 actual
= sizeof(buf
) - 1;
485 emul_read_buffer(buf
,
491 TRACE(trace_os_emul
, ("read - in - ihandle=0x%lx `%s' (%ld)\n",
492 (unsigned long)args
.ihandle
, buf
, (long)actual
));
493 read(BE2H_4(args
.ihandle
), buf
, actual
);
494 args
.actual
= H2T_4(actual
);
495 TRACE(trace_os_emul
, ("read - out - actual=%ld\n",
496 (long)T2H_4(args
.actual
)));
497 emul_write_buffer(&args
, data
->arguments
,
504 chirp_emul_write(os_emul_data
*data
,
511 unsigned32 n_returns
;
521 emul_read_buffer(&args
, data
->arguments
,
524 if (T2H_4(args
.n_args
) != 3 || T2H_4(args
.n_returns
) != 1) {
525 TRACE(trace_os_emul
, ("write - invalid nr - n_args=%ld, n_returns=%ld\n",
526 (long)T2H_4(args
.n_args
),
527 (long)T2H_4(args
.n_returns
)));
530 /* read in the arguments */
531 actual
= T2H_4(args
.len
);
532 if (actual
>= sizeof(buf
))
533 actual
= sizeof(buf
) - 1;
534 emul_read_buffer(buf
,
540 TRACE(trace_os_emul
, ("write - in - ihandle=0x%lx `%s' (%ld)\n",
541 (unsigned long)args
.ihandle
, buf
, (long)actual
));
542 write(BE2H_4(args
.ihandle
), buf
, actual
);
543 args
.actual
= H2T_4(actual
);
544 TRACE(trace_os_emul
, ("write - out - actual=%ld\n",
545 (long)T2H_4(args
.actual
)));
546 emul_write_buffer(&args
, data
->arguments
,
553 chirp_services services
[] = {
554 { "child", chirp_emul_child
},
555 { "exit", chirp_emul_exit
},
556 { "finddevice", chirp_emul_finddevice
},
557 { "getprop", chirp_emul_getprop
},
558 { "getproplen", chirp_emul_getproplen
},
559 { "open", chirp_emul_open
},
560 { "parent", chirp_emul_parent
},
561 { "peer", chirp_emul_peer
},
562 { "read", chirp_emul_read
},
563 { "write", chirp_emul_write
},
564 { 0, /* sentinal */ },
570 /* Any starting address greater than this is assumed to be an Chirp
573 #ifndef CHIRP_START_ADDRESS
574 #define CHIRP_START_ADDRESS 0x80000000
577 typedef struct _chirp_note_desc
{
585 typedef struct _chirp_note
{
586 chirp_note_desc desc
;
590 typedef struct _chirp_note_head
{
597 map_over_chirp_note(bfd
*image
,
601 chirp_note
*note
= (chirp_note
*)obj
;
602 if (strcmp(sect
->name
, ".note") == 0) {
603 chirp_note_head head
;
606 if (!bfd_get_section_contents(image
, sect
,
607 &head
, 0, sizeof(head
)))
609 head
.namesz
= bfd_get_32(image
, (void*)&head
.namesz
);
610 head
.descsz
= bfd_get_32(image
, (void*)&head
.descsz
);
611 head
.type
= bfd_get_32(image
, (void*)&head
.type
);
612 if (head
.type
!= 0x1275)
615 /* check the name field */
616 if (head
.namesz
> sizeof(name
))
618 if (!bfd_get_section_contents(image
, sect
,
619 name
, sizeof(head
), head
.namesz
))
621 if (strcmp(name
, "PowerPC") != 0)
623 /* get the contents */
624 if (!bfd_get_section_contents(image
, sect
,
625 ¬e
->desc
, sizeof(head
) + head
.namesz
,
628 note
->desc
.real_mode
= bfd_get_32(image
, (void*)¬e
->desc
.real_mode
);
629 note
->desc
.real_base
= bfd_get_32(image
, (void*)¬e
->desc
.real_base
);
630 note
->desc
.real_size
= bfd_get_32(image
, (void*)¬e
->desc
.real_size
);
631 note
->desc
.virt_base
= bfd_get_32(image
, (void*)¬e
->desc
.virt_base
);
632 note
->desc
.virt_size
= bfd_get_32(image
, (void*)¬e
->desc
.virt_size
);
638 static os_emul_data
*
639 emul_chirp_create(device
*root
,
647 /* Sanity check that this really is the chosen emulation */
648 if (name
== NULL
&& image
== NULL
)
651 && strcmp(name
, "ob") != 0
652 && strcmp(name
, "ieee1274") != 0
653 && strcmp(name
, "chrp") != 0
654 && strcmp(name
, "chirp") != 0
655 && strcmp(name
, "openboot") != 0)
658 /* look for an elf note section */
659 memset(¬e
, 0, sizeof(note
));
661 bfd_map_over_sections(image
, map_over_chirp_note
, ¬e
);
662 if (name
== NULL
&& image
!= NULL
&& !note
.found
)
666 device_add_string_property(root
,
671 const unsigned_word memory_size
= 0x200000;
674 const unsigned nr_page_table_entry_groups
= (memory_size
< 0x800000
675 ? 1024 /* min allowed */
676 : (memory_size
/ 4096 / 2));
677 const unsigned sizeof_htab
= nr_page_table_entry_groups
* 64;
678 const unsigned_word htab_ra
= memory_size
- sizeof_htab
;
680 /* a page for firmware calls */
681 const unsigned_word sizeof_code
= 4096;
682 const unsigned_word code_ra
= htab_ra
- sizeof_code
;
685 const unsigned sizeof_stack
= 32 * 1024;
686 const unsigned_word stack_ra
= code_ra
- sizeof_stack
;
688 /* the firmware's home */
689 const int real_mode
= 0;
690 /* const unsigned_word real_base = stack_ra; */
691 /* const unsigned real_size = memory_size - real_base; */
692 const unsigned_word virt_base
= CHIRP_START_ADDRESS
;
693 /* const unsigned virt_size = real_size;*/
695 /* the virtual addresses */
696 const unsigned_word stack_va
= virt_base
;
697 const unsigned_word code_va
= stack_va
+ sizeof_stack
;
698 const unsigned_word code_client_va
= code_va
;
699 const unsigned_word code_callback_va
= code_client_va
+ 16;
700 const unsigned_word code_loop_va
= code_callback_va
+ 16;
701 const unsigned_word htab_va
= code_va
+ sizeof_code
;
703 #ifdef bfd_big_endian /* new bfd */
704 big_endian
= bfd_big_endian(image
);
706 big_endian
= image
->xvec
->byteorder_big_p
;
711 device
*options
= device_tree_add_found(root
, "/", "options");
712 device_add_integer_property(options
,
715 device_add_boolean_property(options
,
718 device_add_string_property(options
,
721 device_add_boolean_property(options
,
723 (WITH_ALIGNMENT
== STRICT_ALIGNMENT
725 device_add_boolean_property(options
,
727 WITH_FLOATING_POINT
);
728 device_add_string_property(options
,
734 device_tree_add_found_uw_u_u(root
, "/", "memory",
735 0, memory_size
, access_read_write_exec
);
739 device
*init
= device_tree_add_found(root
, "/", "init");
741 device
*init_register
= device_tree_add_found(init
, "", "register");
742 device_add_integer_property(init_register
,
745 device_add_integer_property(init_register
,
747 bfd_get_start_address(image
));
748 device_add_integer_property(init_register
,
750 stack_va
+ sizeof_stack
- 16);
752 /* init the code callback along with a loop for the unused cpu's */
753 device_add_integer_property(init_register
,
756 device_tree_add_found_uw_u_u(init
, "",
758 code_ra
+ (code_client_va
- code_va
),
759 4, 0x1); /*emul-call*/
760 device_tree_add_found_uw_u_u(init
, "",
762 code_ra
+ (code_callback_va
- code_va
),
763 4, 0x1); /*emul-call*/
764 device_tree_add_found_uw_u_u(init
, "",
766 code_ra
+ (code_loop_va
- code_va
),
767 4, 0x48000000); /*b .*/
768 device_add_integer_property(init_register
,
770 (msr_machine_check_enable
773 : (msr_instruction_relocate
774 | msr_data_relocate
))
777 : (msr_little_endian_mode
778 | msr_interrupt_little_endian_mode
780 device_add_integer_property(init_register
,
784 | ((sizeof_htab
- 1) >> 16)));
786 device_add_integer_property(init_register
,
789 device_add_integer_property(init_register
,
793 { /* hash table and vm */
794 device
*htab_root
= device_tree_add_found_uw_u(init
, "", "htab",
795 htab_ra
, sizeof_htab
);
796 device_tree_add_found_uw_uw_u_u_u(htab_root
, "", "pte",
797 stack_ra
, stack_va
, sizeof_stack
,
798 0x7/*wimg*/, 0x2/*pp*/);
799 device_tree_add_found_uw_uw_u_u_u(htab_root
, "", "pte",
800 code_ra
, code_va
, sizeof_code
,
801 0x7/*wimg*/, 0x2/*pp*/);
802 device_tree_add_found_uw_uw_u_u_u(htab_root
, "", "pte",
803 htab_ra
, htab_va
, sizeof_htab
,
804 0x7/*wimg*/, 0x2/*pp*/);
805 device_tree_add_found_uw_u_u_c(htab_root
, "", "pte",
807 0x7/*wimg*/, 0x2/*pp*/,
808 bfd_get_filename (image
));
813 { /* chosen options */
814 device
*chosen
= device_tree_add_found(root
, "/", "chosen");
815 device_add_string_property(chosen
,
818 device_add_integer_property(chosen
,
820 0); /* FIXME: ihandle of stdin */
821 device_add_integer_property(chosen
,
823 1); /* FIXME: ihandle of stdout */
824 device_add_string_property(chosen
,
827 device_add_string_property(chosen
,
831 device_add_integer_property(chosen
,
833 0); /* FIXME: ihandle of memory */
834 device_add_integer_property(chosen
,
840 /* FIXME - should come from the device tree */
841 data
= ZALLOC(os_emul_data
);
842 data
->serving_instruction_ea
= code_client_va
;
843 data
->catching_instruction_ea
= code_callback_va
;
844 data
->phandles
= cap_create("chirp");
851 emul_chirp_init(os_emul_data
*emul_data
,
854 emul_data
->state
= serving
;
855 cap_init(emul_data
->phandles
);
859 emul_chirp_instruction_call(cpu
*processor
,
862 os_emul_data
*emul_data
)
864 unsigned_word service_name_addr
;
865 unsigned_word result
;
866 char service_buf
[32];
868 chirp_services
*service
;
870 switch (emul_data
->state
) {
873 /* we are waiting on an OpenBoot request from the client program
874 via the client interface */
875 if (cia
!= emul_data
->serving_instruction_ea
)
877 emul_data
->return_address
= LR
;
878 emul_data
->arguments
= cpu_registers(processor
)->gpr
[3];
879 /* try to determine what to do */
880 service_name_addr
= emul_read_word(cpu_registers(processor
)->gpr
[3],
882 service_name
= emul_read_string(service_buf
, service_name_addr
,
883 sizeof(service_buf
), processor
, cia
);
884 TRACE(trace_os_emul
, ("%s called from 0x%lx with args 0x%lx\n",
886 (unsigned long)emul_data
->return_address
,
887 (unsigned long)emul_data
->arguments
));
890 while (service
->name
!= NULL
&& strcmp(service
->name
, service_name
) != 0)
892 if (service
->name
== NULL
) {
893 error("OpenBoot service `%s' not found\n", service_name
);
894 TRACE(trace_os_emul
, ("%s not found\n", service_name
));
895 cpu_registers(processor
)->gpr
[3] = 0;
896 cpu_restart(processor
, emul_data
->return_address
);
898 emul_data
->service
= service
;
900 result
= service
->handler(emul_data
, processor
, cia
);
904 /* We were handling a client request but encountered a page fault
905 (or other exception). The fault needs to be passed back to the
906 client using the the client suplied call back interface */
907 error("emul_chirp_instruction_call() faulting unimplemented\n");
912 /* Have called the client (via the callback interface) because
913 some fault (hash table miss) occured. The client has finished
914 handling this and is now returning */
915 error("emul_chirp_instruction_call() catching unimplemented\n");
920 error("emul_chirp_instruction_call() unknown internal state\n");
926 /* return to caller */
927 cpu_registers(processor
)->gpr
[3] = result
;
928 cpu_restart(processor
, emul_data
->return_address
);
932 const os_emul emul_chirp
= {
936 NULL
, /*system_call*/
937 emul_chirp_instruction_call
,