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