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