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