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