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