1 /* Simulator hardware option handling.
2    Copyright (C) 1998 Free Software Foundation, Inc.
3    Contributed by Cygnus Support and Andrew Cagney.
4 
5 This file is part of GDB, the GNU debugger.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20 
21 #include "sim-main.h"
22 #include "sim-assert.h"
23 #include "sim-options.h"
24 
25 #include "sim-hw.h"
26 
27 #include "hw-tree.h"
28 #include "hw-device.h"
29 #include "hw-main.h"
30 #include "hw-base.h"
31 
32 
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #else
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39 #endif
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #include <ctype.h>
44 #include <errno.h>
45 
46 
47 struct sim_hw {
48   struct hw *tree;
49   int trace_p;
50   int info_p;
51   /* if called from a processor */
52   sim_cpu *cpu;
53   sim_cia cia;
54 };
55 
56 
57 struct hw *
sim_hw_parse(struct sim_state * sd,const char * fmt,...)58 sim_hw_parse (struct sim_state *sd,
59 	      const char *fmt,
60 	      ...)
61 {
62   struct hw *current;
63   va_list ap;
64   va_start (ap, fmt);
65   current = hw_tree_vparse (STATE_HW (sd)->tree, fmt, ap);
66   va_end (ap);
67   return current;
68 }
69 
70 struct printer {
71   struct sim_state *file;
72   void (*print) (struct sim_state *, const char *, va_list ap);
73 };
74 
75 static void
do_print(void * file,const char * fmt,...)76 do_print (void *file, const char *fmt, ...)
77 {
78   struct printer *p = file;
79   va_list ap;
80   va_start (ap, fmt);
81   p->print (p->file, fmt, ap);
82   va_end (ap);
83 }
84 
85 void
sim_hw_print(struct sim_state * sd,void (* print)(struct sim_state *,const char *,va_list ap))86 sim_hw_print (struct sim_state *sd,
87 	      void (*print) (struct sim_state *, const char *, va_list ap))
88 {
89   struct printer p;
90   p.file = sd;
91   p.print = print;
92   hw_tree_print (STATE_HW (sd)->tree, do_print, &p);
93 }
94 
95 
96 
97 
98 /* command line options. */
99 
100 enum {
101   OPTION_HW_INFO = OPTION_START,
102   OPTION_HW_TRACE,
103   OPTION_HW_DEVICE,
104   OPTION_HW_LIST,
105   OPTION_HW_FILE,
106 };
107 
108 static DECLARE_OPTION_HANDLER (hw_option_handler);
109 
110 static const OPTION hw_options[] =
111 {
112   { {"hw-info", no_argument, NULL, OPTION_HW_INFO },
113       '\0', NULL, "List configurable hw regions",
114       hw_option_handler },
115   { {"info-hw", no_argument, NULL, OPTION_HW_INFO },
116       '\0', NULL, NULL,
117       hw_option_handler },
118 
119   { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE },
120       '\0', "on|off", "Trace all hardware devices",
121       hw_option_handler },
122   { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE },
123       '\0', NULL, NULL,
124       hw_option_handler },
125 
126   { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE },
127       '\0', "DEVICE", "Add the specified device",
128       hw_option_handler },
129 
130   { {"hw-list", no_argument, NULL, OPTION_HW_LIST },
131       '\0', NULL, "List the device tree",
132       hw_option_handler },
133 
134   { {"hw-file", required_argument, NULL, OPTION_HW_FILE },
135       '\0', "FILE", "Add the devices listed in the file",
136       hw_option_handler },
137 
138   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
139 };
140 
141 
142 
143 /* Copied from ../ppc/psim.c:psim_merge_device_file() */
144 
145 static SIM_RC
merge_device_file(struct sim_state * sd,const char * file_name)146 merge_device_file (struct sim_state *sd,
147 		   const char *file_name)
148 {
149   FILE *description;
150   struct hw *current = STATE_HW (sd)->tree;
151   int line_nr;
152   char device_path[1000];
153 
154   /* try opening the file */
155   description = fopen (file_name, "r");
156   if (description == NULL)
157     {
158       perror (file_name);
159       return SIM_RC_FAIL;
160     }
161 
162   line_nr = 0;
163   while (fgets (device_path, sizeof(device_path), description))
164     {
165       char *device;
166       /* check that a complete line was read */
167       if (strchr (device_path, '\n') == NULL)
168 	{
169 	  fclose (description);
170 	  sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
171 	  return SIM_RC_FAIL;
172 	}
173       *strchr (device_path, '\n') = '\0';
174       line_nr++;
175       /* skip comments ("#" or ";") and blank lines lines */
176       for (device = device_path;
177 	   *device != '\0' && isspace (*device);
178 	   device++);
179       if (device[0] == '#'
180 	  || device[0] == ';'
181 	  || device[0] == '\0')
182 	continue;
183       /* merge any appended lines */
184       while (device_path[strlen (device_path) - 1] == '\\')
185 	{
186 	  int curlen = strlen (device_path) - 1;
187 	  /* zap the `\' at the end of the line */
188 	  device_path[curlen] = '\0';
189 	  /* append the next line */
190 	  if (!fgets (device_path + curlen,
191 		      sizeof (device_path) - curlen,
192 		      description))
193 	    {
194 	      fclose (description);
195 	      sim_io_eprintf (sd, "%s:%d: unexpected eof", file_name, line_nr);
196 	      return SIM_RC_FAIL;
197 	    }
198 	  if (strchr(device_path, '\n') == NULL)
199 	    {
200 	      fclose(description);
201 	      sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
202 	      return SIM_RC_FAIL;
203 	    }
204 	  *strchr(device_path, '\n') = '\0';
205 	  line_nr++;
206 	}
207       /* parse this line */
208       current = hw_tree_parse (current, "%s", device);
209     }
210   fclose (description);
211   return SIM_RC_OK;
212 }
213 
214 
215 static SIM_RC
hw_option_handler(struct sim_state * sd,sim_cpu * cpu,int opt,char * arg,int is_command)216 hw_option_handler (struct sim_state *sd, sim_cpu *cpu, int opt,
217 		   char *arg, int is_command)
218 {
219   switch (opt)
220     {
221 
222     case OPTION_HW_INFO:
223       {
224 	/* delay info until after the tree is finished */
225 	STATE_HW (sd)->info_p = 1;
226 	return SIM_RC_OK;
227 	break;
228       }
229 
230     case OPTION_HW_TRACE:
231       {
232 	if (arg == NULL)
233 	  {
234 	    STATE_HW (sd)->trace_p = 1;
235 	  }
236 	else if (strcmp (arg, "yes") == 0
237 		 || strcmp (arg, "on") == 0)
238 	  {
239 	    STATE_HW (sd)->trace_p = 1;
240 	  }
241 	else if (strcmp (arg, "no") == 0
242 		 || strcmp (arg, "off") == 0)
243 	  {
244 	    STATE_HW (sd)->trace_p = 0;
245 	  }
246 	else
247 	  {
248 	    sim_io_eprintf (sd, "Option --hw-trace ignored\n");
249 	    /* set tracing on all devices */
250 	    return SIM_RC_FAIL;
251 	  }
252 	/* FIXME: Not very nice - see also hw-base.c */
253 	if (STATE_HW (sd)->trace_p)
254 	  hw_tree_parse (STATE_HW (sd)->tree, "/global-trace? true");
255 	return SIM_RC_OK;
256 	break;
257       }
258 
259     case OPTION_HW_DEVICE:
260       {
261 	hw_tree_parse (STATE_HW (sd)->tree, arg);
262 	return SIM_RC_OK;
263       }
264 
265     case OPTION_HW_LIST:
266       {
267 	sim_hw_print (sd, sim_io_vprintf);
268 	return SIM_RC_OK;
269       }
270 
271     case OPTION_HW_FILE:
272       {
273 	return merge_device_file (sd, arg);
274       }
275 
276     default:
277       sim_io_eprintf (sd, "Unknown hw option %d\n", opt);
278       return SIM_RC_FAIL;
279 
280     }
281 
282   return SIM_RC_FAIL;
283 }
284 
285 
286 /* "hw" module install handler.
287 
288    This is called via sim_module_install to install the "hw" subsystem
289    into the simulator.  */
290 
291 static MODULE_INIT_FN sim_hw_init;
292 static MODULE_UNINSTALL_FN sim_hw_uninstall;
293 
294 SIM_RC
sim_hw_install(struct sim_state * sd)295 sim_hw_install (struct sim_state *sd)
296 {
297   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
298   sim_add_option_table (sd, NULL, hw_options);
299   sim_module_add_uninstall_fn (sd, sim_hw_uninstall);
300   sim_module_add_init_fn (sd, sim_hw_init);
301   STATE_HW (sd) = ZALLOC (struct sim_hw);
302   STATE_HW (sd)->tree = hw_tree_create (sd, "core");
303   return SIM_RC_OK;
304 }
305 
306 
307 static SIM_RC
sim_hw_init(struct sim_state * sd)308 sim_hw_init (struct sim_state *sd)
309 {
310   /* FIXME: anything needed? */
311   hw_tree_finish (STATE_HW (sd)->tree);
312   if (STATE_HW (sd)->info_p)
313     sim_hw_print (sd, sim_io_vprintf);
314   return SIM_RC_OK;
315 }
316 
317 /* Uninstall the "hw" subsystem from the simulator.  */
318 
319 static void
sim_hw_uninstall(struct sim_state * sd)320 sim_hw_uninstall (struct sim_state *sd)
321 {
322   /* hw_tree_delete (STATE_HW (sd)->tree); */
323   zfree (STATE_HW (sd));
324   STATE_HW (sd) = NULL;
325 }
326 
327 
328 
329 /* Data transfers to/from the hardware device tree.  There are several
330    cases. */
331 
332 
333 /* CPU: The simulation is running and the current CPU/CIA
334    initiates a data transfer. */
335 
336 void
sim_cpu_hw_io_read_buffer(sim_cpu * cpu,sim_cia cia,struct hw * hw,void * dest,int space,unsigned_word addr,unsigned nr_bytes)337 sim_cpu_hw_io_read_buffer (sim_cpu *cpu,
338 			   sim_cia cia,
339 			   struct hw *hw,
340 			   void *dest,
341 			   int space,
342 			   unsigned_word addr,
343 			   unsigned nr_bytes)
344 {
345   SIM_DESC sd = CPU_STATE (cpu);
346   STATE_HW (sd)->cpu = cpu;
347   STATE_HW (sd)->cia = cia;
348   if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes)
349     sim_engine_abort (sd, cpu, cia, "broken CPU read");
350 }
351 
352 void
sim_cpu_hw_io_write_buffer(sim_cpu * cpu,sim_cia cia,struct hw * hw,const void * source,int space,unsigned_word addr,unsigned nr_bytes)353 sim_cpu_hw_io_write_buffer (sim_cpu *cpu,
354 			    sim_cia cia,
355 			    struct hw *hw,
356 			    const void *source,
357 			    int space,
358 			    unsigned_word addr,
359 			    unsigned nr_bytes)
360 {
361   SIM_DESC sd = CPU_STATE (cpu);
362   STATE_HW (sd)->cpu = cpu;
363   STATE_HW (sd)->cia = cia;
364   if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes)
365     sim_engine_abort (sd, cpu, cia, "broken CPU write");
366 }
367 
368 
369 
370 
371 /* SYSTEM: A data transfer is being initiated by the system. */
372 
373 unsigned
sim_hw_io_read_buffer(struct sim_state * sd,struct hw * hw,void * dest,int space,unsigned_word addr,unsigned nr_bytes)374 sim_hw_io_read_buffer (struct sim_state *sd,
375 		       struct hw *hw,
376 		       void *dest,
377 		       int space,
378 		       unsigned_word addr,
379 		       unsigned nr_bytes)
380 {
381   STATE_HW (sd)->cpu = NULL;
382   return hw_io_read_buffer (hw, dest, space, addr, nr_bytes);
383 }
384 
385 unsigned
sim_hw_io_write_buffer(struct sim_state * sd,struct hw * hw,const void * source,int space,unsigned_word addr,unsigned nr_bytes)386 sim_hw_io_write_buffer (struct sim_state *sd,
387 			struct hw *hw,
388 			const void *source,
389 			int space,
390 			unsigned_word addr,
391 			unsigned nr_bytes)
392 {
393   STATE_HW (sd)->cpu = NULL;
394   return hw_io_write_buffer (hw, source, space, addr, nr_bytes);
395 }
396 
397 
398 
399 /* Abort the simulation specifying HW as the reason */
400 
401 void
hw_vabort(struct hw * me,const char * fmt,va_list ap)402 hw_vabort (struct hw *me,
403 	   const char *fmt,
404 	   va_list ap)
405 {
406   const char *name;
407   char *msg;
408   /* find an identity */
409   if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
410     name = hw_path (me);
411   else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
412     name = hw_name (me);
413   else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
414     name = hw_family (me);
415   else
416     name = "device";
417   /* construct an updated format string */
418   msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1);
419   strcpy (msg, name);
420   strcat (msg, ": ");
421   strcat (msg, fmt);
422   /* report the problem */
423   sim_engine_vabort (hw_system (me),
424 		     STATE_HW (hw_system (me))->cpu,
425 		     STATE_HW (hw_system (me))->cia,
426 		     msg, ap);
427 }
428 
429 void
hw_abort(struct hw * me,const char * fmt,...)430 hw_abort (struct hw *me,
431 	  const char *fmt,
432 	  ...)
433 {
434   va_list ap;
435   /* report the problem */
436   va_start (ap, fmt);
437   hw_vabort (me, fmt, ap);
438   va_end (ap);
439 }
440 
441 void
sim_hw_abort(struct sim_state * sd,struct hw * me,const char * fmt,...)442 sim_hw_abort (struct sim_state *sd,
443 	      struct hw *me,
444 	      const char *fmt,
445 	      ...)
446 {
447   va_list ap;
448   va_start (ap, fmt);
449   if (me == NULL)
450     sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap);
451   else
452     hw_vabort (me, fmt, ap);
453   va_end (ap);
454 }
455 
456 
457 /* MISC routines to tie HW into the rest of the system */
458 
459 void
hw_halt(struct hw * me,int reason,int status)460 hw_halt (struct hw *me,
461 	 int reason,
462 	 int status)
463 {
464   struct sim_state *sd = hw_system (me);
465   struct sim_hw *sim = STATE_HW (sd);
466   sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status);
467 }
468 
469 struct _sim_cpu *
hw_system_cpu(struct hw * me)470 hw_system_cpu (struct hw *me)
471 {
472   return STATE_HW (hw_system (me))->cpu;
473 }
474 
475 void
hw_trace(struct hw * me,const char * fmt,...)476 hw_trace (struct hw *me,
477 	  const char *fmt,
478 	  ...)
479 {
480   if (hw_trace_p (me)) /* to be sure, to be sure */
481     {
482       va_list ap;
483       va_start (ap, fmt);
484       sim_io_eprintf (hw_system (me), "%s: ", hw_path (me));
485       sim_io_evprintf (hw_system (me), fmt, ap);
486       sim_io_eprintf (hw_system (me), "\n");
487       va_end (ap);
488     }
489 }
490 
491 
492 /* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
493 
494 int
do_hw_poll_read(struct hw * me,do_hw_poll_read_method * read,int sim_io_fd,void * buf,unsigned sizeof_buf)495 do_hw_poll_read (struct hw *me,
496 		 do_hw_poll_read_method *read,
497 		 int sim_io_fd,
498 		 void *buf,
499 		 unsigned sizeof_buf)
500 {
501   int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf);
502   if (status > 0)
503     return status;
504   else if (status == 0 && sizeof_buf == 0)
505     return 0;
506   else if (status == 0)
507     return HW_IO_EOF;
508   else /* status < 0 */
509     {
510 #ifdef EAGAIN
511       if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN)
512 	return HW_IO_NOT_READY;
513       else
514 	return HW_IO_EOF;
515 #else
516       return HW_IO_EOF;
517 #endif
518     }
519 }
520