1/* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002-2023 Free Software Foundation, Inc. 4 5 Contributed by Andrew Cagney and Red Hat. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22/* This must come before any other includes. */ 23#include "defs.h" 24 25#include <ctype.h> 26#include <stdlib.h> 27#include <string.h> 28 29#include "hw-main.h" 30#include "hw-base.h" 31#include "hw-config.h" 32 33struct hw_base_data 34{ 35 int finished_p; 36 const struct hw_descriptor *descriptor; 37 hw_delete_callback *to_delete; 38}; 39 40static int 41generic_hw_unit_decode (struct hw *bus, 42 const char *unit, 43 hw_unit *phys) 44{ 45 memset (phys, 0, sizeof (*phys)); 46 if (unit == NULL) 47 return 0; 48 else 49 { 50 int nr_cells = 0; 51 const int max_nr_cells = hw_unit_nr_address_cells (bus); 52 while (1) 53 { 54 char *end = NULL; 55 unsigned long val; 56 val = strtoul (unit, &end, 0); 57 /* parse error? */ 58 if (unit == end) 59 return -1; 60 /* two many cells? */ 61 if (nr_cells >= max_nr_cells) 62 return -1; 63 /* save it */ 64 phys->cells[nr_cells] = val; 65 nr_cells++; 66 unit = end; 67 /* more to follow? */ 68 if (isspace (*unit) || *unit == '\0') 69 break; 70 if (*unit != ',') 71 return -1; 72 unit++; 73 } 74 if (nr_cells < max_nr_cells) 75 { 76 /* shift everything to correct position */ 77 int i; 78 79 for (i = 1; i <= nr_cells; i++) 80 phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i]; 81 for (i = 0; i < (max_nr_cells - nr_cells); i++) 82 phys->cells[i] = 0; 83 } 84 phys->nr_cells = max_nr_cells; 85 return max_nr_cells; 86 } 87} 88 89static int 90generic_hw_unit_encode (struct hw *bus, 91 const hw_unit *phys, 92 char *buf, 93 int sizeof_buf) 94{ 95 int i; 96 int len; 97 char *pos = buf; 98 /* skip leading zero's */ 99 for (i = 0; i < phys->nr_cells; i++) 100 { 101 if (phys->cells[i] != 0) 102 break; 103 } 104 /* don't output anything if empty */ 105 if (phys->nr_cells == 0) 106 { 107 strcpy (pos, ""); 108 len = 0; 109 } 110 else if (i == phys->nr_cells) 111 { 112 /* all zero */ 113 strcpy (pos, "0"); 114 len = 1; 115 } 116 else 117 { 118 for (; i < phys->nr_cells; i++) 119 { 120 if (pos != buf) 121 { 122 strcat (pos, ","); 123 pos = strchr (pos, '\0'); 124 } 125 if (phys->cells[i] < 10) 126 sprintf (pos, "%ld", (unsigned long)phys->cells[i]); 127 else 128 sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]); 129 pos = strchr (pos, '\0'); 130 } 131 len = pos - buf; 132 } 133 if (len >= sizeof_buf) 134 hw_abort (NULL, "generic_unit_encode - buffer overflow\n"); 135 return len; 136} 137 138static int 139generic_hw_unit_address_to_attach_address (struct hw *me, 140 const hw_unit *address, 141 int *attach_space, 142 unsigned_word *attach_address, 143 struct hw *client) 144{ 145 int i; 146 for (i = 0; i < address->nr_cells - 2; i++) 147 { 148 if (address->cells[i] != 0) 149 hw_abort (me, "Only 32bit addresses supported"); 150 } 151 if (address->nr_cells >= 2) 152 *attach_space = address->cells[address->nr_cells - 2]; 153 else 154 *attach_space = 0; 155 *attach_address = address->cells[address->nr_cells - 1]; 156 return 1; 157} 158 159static int 160generic_hw_unit_size_to_attach_size (struct hw *me, 161 const hw_unit *size, 162 unsigned *nr_bytes, 163 struct hw *client) 164{ 165 int i; 166 for (i = 0; i < size->nr_cells - 1; i++) 167 { 168 if (size->cells[i] != 0) 169 hw_abort (me, "Only 32bit sizes supported"); 170 } 171 *nr_bytes = size->cells[0]; 172 return *nr_bytes; 173} 174 175 176/* ignore/passthrough versions of each function */ 177 178static void 179passthrough_hw_attach_address (struct hw *me, 180 int level, 181 int space, 182 address_word addr, 183 address_word nr_bytes, 184 struct hw *client) /*callback/default*/ 185{ 186 if (hw_parent (me) == NULL) 187 hw_abort (client, "hw_attach_address: no parent attach method"); 188 hw_attach_address (hw_parent (me), level, 189 space, addr, nr_bytes, 190 client); 191} 192 193static void 194passthrough_hw_detach_address (struct hw *me, 195 int level, 196 int space, 197 address_word addr, 198 address_word nr_bytes, 199 struct hw *client) /*callback/default*/ 200{ 201 if (hw_parent (me) == NULL) 202 hw_abort (client, "hw_attach_address: no parent attach method"); 203 hw_detach_address (hw_parent (me), level, 204 space, addr, nr_bytes, 205 client); 206} 207 208static unsigned 209panic_hw_io_read_buffer (struct hw *me, 210 void *dest, 211 int space, 212 unsigned_word addr, 213 unsigned nr_bytes) 214{ 215 hw_abort (me, "no io-read method"); 216 return 0; 217} 218 219static unsigned 220panic_hw_io_write_buffer (struct hw *me, 221 const void *source, 222 int space, 223 unsigned_word addr, 224 unsigned nr_bytes) 225{ 226 hw_abort (me, "no io-write method"); 227 return 0; 228} 229 230static unsigned 231passthrough_hw_dma_read_buffer (struct hw *me, 232 void *dest, 233 int space, 234 unsigned_word addr, 235 unsigned nr_bytes) 236{ 237 if (hw_parent (me) == NULL) 238 hw_abort (me, "no parent dma-read method"); 239 return hw_dma_read_buffer (hw_parent (me), dest, 240 space, addr, nr_bytes); 241} 242 243static unsigned 244passthrough_hw_dma_write_buffer (struct hw *me, 245 const void *source, 246 int space, 247 unsigned_word addr, 248 unsigned nr_bytes, 249 int violate_read_only_section) 250{ 251 if (hw_parent (me) == NULL) 252 hw_abort (me, "no parent dma-write method"); 253 return hw_dma_write_buffer (hw_parent (me), source, 254 space, addr, 255 nr_bytes, 256 violate_read_only_section); 257} 258 259static void 260ignore_hw_delete (struct hw *me) 261{ 262 /* NOP */ 263} 264 265 266 267 268static const char * 269full_name_of_hw (struct hw *leaf, 270 char *buf, 271 unsigned sizeof_buf) 272{ 273 /* get a buffer */ 274 if (buf == NULL) 275 { 276 sizeof_buf = 1024; 277 buf = hw_malloc (leaf, sizeof_buf); 278 } 279 280 /* use head recursion to construct the path */ 281 282 if (hw_parent (leaf) == NULL) 283 /* root */ 284 { 285 if (sizeof_buf < 1) 286 hw_abort (leaf, "buffer overflow"); 287 *buf = '\0'; 288 } 289 else 290 /* sub node */ 291 { 292 char unit[1024]; 293 full_name_of_hw (hw_parent (leaf), buf, sizeof_buf); 294 if (hw_unit_encode (hw_parent (leaf), 295 hw_unit_address (leaf), 296 unit + 1, 297 sizeof (unit) - 1) 298 > 0) 299 unit[0] = '@'; 300 else 301 unit[0] = '\0'; 302 if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit) 303 >= sizeof_buf) 304 hw_abort (leaf, "buffer overflow"); 305 strcat (buf, "/"); 306 strcat (buf, hw_name (leaf)); 307 strcat (buf, unit); 308 } 309 310 return buf; 311} 312 313struct hw * 314hw_create (struct sim_state *sd, 315 struct hw *parent, 316 const char *family, 317 const char *name, 318 const char *unit, 319 const char *args) 320{ 321 /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */ 322 struct hw *hw = ZALLOC (struct hw); 323 324 /* our identity */ 325 hw->family_of_hw = hw_strdup (hw, family); 326 hw->name_of_hw = hw_strdup (hw, name); 327 hw->args_of_hw = hw_strdup (hw, args); 328 329 /* a hook into the system */ 330 if (sd != NULL) 331 hw->system_of_hw = sd; 332 else if (parent != NULL) 333 hw->system_of_hw = hw_system (parent); 334 else 335 hw_abort (parent, "No system found"); 336 337 /* in a tree */ 338 if (parent != NULL) 339 { 340 struct hw **sibling = &parent->child_of_hw; 341 while ((*sibling) != NULL) 342 sibling = &(*sibling)->sibling_of_hw; 343 *sibling = hw; 344 hw->parent_of_hw = parent; 345 } 346 347 /* top of tree */ 348 if (parent != NULL) 349 { 350 struct hw *root = parent; 351 while (root->parent_of_hw != NULL) 352 root = root->parent_of_hw; 353 hw->root_of_hw = root; 354 } 355 356 /* a unique identifier for the device on the parents bus */ 357 if (parent != NULL) 358 { 359 hw_unit_decode (parent, unit, &hw->unit_address_of_hw); 360 } 361 362 /* Determine our path */ 363 if (parent != NULL) 364 hw->path_of_hw = full_name_of_hw (hw, NULL, 0); 365 else 366 hw->path_of_hw = "/"; 367 368 /* create our base type */ 369 hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data); 370 hw->base_of_hw->finished_p = 0; 371 372 /* our callbacks */ 373 set_hw_io_read_buffer (hw, panic_hw_io_read_buffer); 374 set_hw_io_write_buffer (hw, panic_hw_io_write_buffer); 375 set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer); 376 set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer); 377 set_hw_unit_decode (hw, generic_hw_unit_decode); 378 set_hw_unit_encode (hw, generic_hw_unit_encode); 379 set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address); 380 set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size); 381 set_hw_attach_address (hw, passthrough_hw_attach_address); 382 set_hw_detach_address (hw, passthrough_hw_detach_address); 383 set_hw_delete (hw, ignore_hw_delete); 384 385 /* locate a descriptor */ 386 { 387 const struct hw_descriptor * const *table; 388 for (table = hw_descriptors; 389 *table != NULL; 390 table++) 391 { 392 const struct hw_descriptor *entry; 393 for (entry = *table; 394 entry->family != NULL; 395 entry++) 396 { 397 if (strcmp (family, entry->family) == 0) 398 { 399 hw->base_of_hw->descriptor = entry; 400 break; 401 } 402 } 403 } 404 if (hw->base_of_hw->descriptor == NULL) 405 { 406 hw_abort (parent, "Unknown device `%s'", family); 407 } 408 } 409 410 /* Attach dummy ports */ 411 create_hw_alloc_data (hw); 412 create_hw_property_data (hw); 413 create_hw_port_data (hw); 414 create_hw_event_data (hw); 415 create_hw_handle_data (hw); 416 create_hw_instance_data (hw); 417 418 return hw; 419} 420 421 422int 423hw_finished_p (struct hw *me) 424{ 425 return (me->base_of_hw->finished_p); 426} 427 428void 429hw_finish (struct hw *me) 430{ 431 if (hw_finished_p (me)) 432 hw_abort (me, "Attempt to finish finished device"); 433 434 /* Fill in the (hopefully) defined address/size cells values */ 435 if (hw_find_property (me, "#address-cells") != NULL) 436 me->nr_address_cells_of_hw_unit = 437 hw_find_integer_property (me, "#address-cells"); 438 else 439 me->nr_address_cells_of_hw_unit = 2; 440 if (hw_find_property (me, "#size-cells") != NULL) 441 me->nr_size_cells_of_hw_unit = 442 hw_find_integer_property (me, "#size-cells"); 443 else 444 me->nr_size_cells_of_hw_unit = 1; 445 446 /* Fill in the (hopefully) defined trace variable */ 447 if (hw_find_property (me, "trace?") != NULL) 448 me->trace_of_hw_p = hw_find_boolean_property (me, "trace?"); 449 /* allow global variable to define default tracing */ 450 else if (! hw_trace_p (me) 451 && hw_find_property (hw_root (me), "global-trace?") != NULL 452 && hw_find_boolean_property (hw_root (me), "global-trace?")) 453 me->trace_of_hw_p = 1; 454 455 456 /* Allow the real device to override any methods */ 457 me->base_of_hw->descriptor->to_finish (me); 458 me->base_of_hw->finished_p = 1; 459} 460 461 462void 463hw_delete (struct hw *me) 464{ 465 /* give the object a chance to tidy up */ 466 me->base_of_hw->to_delete (me); 467 468 delete_hw_instance_data (me); 469 delete_hw_handle_data (me); 470 delete_hw_event_data (me); 471 delete_hw_port_data (me); 472 delete_hw_property_data (me); 473 474 /* now unlink us from the tree */ 475 if (hw_parent (me)) 476 { 477 struct hw **sibling = &hw_parent (me)->child_of_hw; 478 while (*sibling != NULL) 479 { 480 if (*sibling == me) 481 { 482 *sibling = me->sibling_of_hw; 483 me->sibling_of_hw = NULL; 484 me->parent_of_hw = NULL; 485 break; 486 } 487 } 488 } 489 490 /* some sanity checks */ 491 if (hw_child (me) != NULL) 492 { 493 hw_abort (me, "attempt to delete device with children"); 494 } 495 if (hw_sibling (me) != NULL) 496 { 497 hw_abort (me, "attempt to delete device with siblings"); 498 } 499 500 /* blow away all memory belonging to the device */ 501 delete_hw_alloc_data (me); 502 503 /* finally */ 504 free (me); 505} 506 507void 508set_hw_delete (struct hw *hw, hw_delete_callback method) 509{ 510 hw->base_of_hw->to_delete = method; 511} 512 513 514/* Go through the devices various reg properties for those that 515 specify attach addresses */ 516 517 518void 519do_hw_attach_regs (struct hw *hw) 520{ 521 static const char *(reg_property_names[]) = { 522 "attach-addresses", 523 "assigned-addresses", 524 "reg", 525 "alternate-reg" , 526 NULL 527 }; 528 const char **reg_property_name; 529 int nr_valid_reg_properties = 0; 530 for (reg_property_name = reg_property_names; 531 *reg_property_name != NULL; 532 reg_property_name++) 533 { 534 if (hw_find_property (hw, *reg_property_name) != NULL) 535 { 536 reg_property_spec reg; 537 int reg_entry; 538 for (reg_entry = 0; 539 hw_find_reg_array_property (hw, *reg_property_name, reg_entry, 540 ®); 541 reg_entry++) 542 { 543 unsigned_word attach_address; 544 int attach_space; 545 unsigned attach_size; 546 if (!hw_unit_address_to_attach_address (hw_parent (hw), 547 ®.address, 548 &attach_space, 549 &attach_address, 550 hw)) 551 continue; 552 if (!hw_unit_size_to_attach_size (hw_parent (hw), 553 ®.size, 554 &attach_size, hw)) 555 continue; 556 hw_attach_address (hw_parent (hw), 557 0, 558 attach_space, attach_address, attach_size, 559 hw); 560 nr_valid_reg_properties++; 561 } 562 /* if first option matches don't try for any others */ 563 if (reg_property_name == reg_property_names) 564 break; 565 } 566 } 567} 568