1/* Simulator hardware option handling. 2 Copyright (C) 1998, 2007 Free Software Foundation, Inc. 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 9the Free Software Foundation; either version 3 of the License, or 10(at your option) any later version. 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 17You should have received a copy of the GNU General Public License 18along 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 46struct 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 56struct hw * 57sim_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 69struct printer { 70 struct sim_state *file; 71 void (*print) (struct sim_state *, const char *, va_list ap); 72}; 73 74static void 75do_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 84void 85sim_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 99enum { 100 OPTION_HW_INFO = OPTION_START, 101 OPTION_HW_TRACE, 102 OPTION_HW_DEVICE, 103 OPTION_HW_LIST, 104 OPTION_HW_FILE, 105}; 106 107static DECLARE_OPTION_HANDLER (hw_option_handler); 108 109static 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 }, 114 { {"info-hw", no_argument, NULL, OPTION_HW_INFO }, 115 '\0', NULL, NULL, 116 hw_option_handler }, 117 118 { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE }, 119 '\0', "on|off", "Trace all hardware devices", 120 hw_option_handler }, 121 { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE }, 122 '\0', NULL, NULL, 123 hw_option_handler }, 124 125 { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE }, 126 '\0', "DEVICE", "Add the specified device", 127 hw_option_handler }, 128 129 { {"hw-list", no_argument, NULL, OPTION_HW_LIST }, 130 '\0', NULL, "List the device tree", 131 hw_option_handler }, 132 133 { {"hw-file", required_argument, NULL, OPTION_HW_FILE }, 134 '\0', "FILE", "Add the devices listed in the file", 135 hw_option_handler }, 136 137 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } 138}; 139 140 141 142/* Copied from ../ppc/psim.c:psim_merge_device_file() */ 143 144static SIM_RC 145merge_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 214static SIM_RC 215hw_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, 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 290static MODULE_INIT_FN sim_hw_init; 291static MODULE_UNINSTALL_FN sim_hw_uninstall; 292 293SIM_RC 294sim_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 306static SIM_RC 307sim_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 318static void 319sim_hw_uninstall (struct sim_state *sd) 320{ 321 /* hw_tree_delete (STATE_HW (sd)->tree); */ 322 zfree (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 335void 336sim_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 351void 352sim_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 372unsigned 373sim_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 384unsigned 385sim_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 400void 401hw_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 428void 429hw_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 440void 441sim_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 458void 459hw_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 468struct _sim_cpu * 469hw_system_cpu (struct hw *me) 470{ 471 return STATE_HW (hw_system (me))->cpu; 472} 473 474void 475hw_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 493int 494do_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