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