1 /* This file is part of the program psim. 2 3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 20 21 #ifndef _EMUL_CHIRP_C_ 22 #define _EMUL_CHIRP_C_ 23 24 /* Note: this module is called via a table. There is no benefit in 25 making it inline */ 26 27 #include "emul_generic.h" 28 #include "emul_chirp.h" 29 30 #include <string.h> 31 #include <unistd.h> 32 33 #ifndef STATIC_INLINE_EMUL_CHIRP 34 #define STATIC_INLINE_EMUL_CHIRP STATIC_INLINE 35 #endif 36 37 38 /* EMULATION 39 40 41 OpenFirmware - IEEE Standard for Boot (Initialization 42 Configuration) Firmware. 43 44 45 DESCRIPTION 46 47 48 BUGS 49 50 51 This code assumes that the memory node has #address-cells and 52 #size-cells set to one. For future implementations, this may not 53 be the case. 54 55 */ 56 57 58 59 60 /* Descriptor of the open boot services being emulated */ 61 62 typedef int (chirp_handler) 63 (os_emul_data *data, 64 cpu *processor, 65 unsigned_word cia); 66 67 typedef struct _chirp_services { 68 const char *name; 69 chirp_handler *handler; 70 } chirp_services; 71 72 73 /* The OpenBoot emulation is, at any time either waiting for a client 74 request or waiting on a client callback */ 75 typedef enum { 76 serving, 77 emulating, 78 faulting, 79 } chirp_emul_state; 80 81 struct _os_emul_data { 82 chirp_emul_state state; 83 unsigned_word return_address; 84 unsigned_word arguments; 85 unsigned_word n_args; 86 unsigned_word n_returns; 87 chirp_services *service; 88 device *root; 89 chirp_services *services; 90 /* configuration */ 91 unsigned_word memory_size; 92 unsigned_word real_base; 93 unsigned_word real_size; 94 unsigned_word virt_base; 95 unsigned_word virt_size; 96 int real_mode; 97 int little_endian; 98 int floating_point_available; 99 int interrupt_prefix; 100 unsigned_word load_base; 101 /* hash table */ 102 unsigned_word nr_page_table_entry_groups; 103 unsigned_word htab_offset; 104 unsigned_word htab_ra; 105 unsigned_word htab_va; 106 unsigned_word sizeof_htab; 107 /* virtual address of htab */ 108 unsigned_word stack_offset; 109 unsigned_word stack_ra; 110 unsigned_word stack_va; 111 unsigned_word sizeof_stack; 112 /* addresses of emulation instructions virtual/real */ 113 unsigned_word code_offset; 114 unsigned_word code_va; 115 unsigned_word code_ra; 116 unsigned_word sizeof_code; 117 unsigned_word code_client_va; 118 unsigned_word code_client_ra; 119 unsigned_word code_callback_va; 120 unsigned_word code_callback_ra; 121 unsigned_word code_loop_va; 122 unsigned_word code_loop_ra; 123 }; 124 125 126 /* returns the name of the corresponding Ihandle */ 127 static const char * 128 ihandle_name(device_instance *ihandle) 129 { 130 if (ihandle == NULL) 131 return ""; 132 else 133 return device_name(device_instance_device(ihandle)); 134 } 135 136 137 138 /* Read/write the argument list making certain that all values are 139 converted to/from host byte order. 140 141 In the below only n_args+n_returns is read/written */ 142 143 static int 144 chirp_read_t2h_args(void *args, 145 int sizeof_args, 146 int n_args, 147 int n_returns, 148 os_emul_data *data, 149 cpu *processor, 150 unsigned_word cia) 151 { 152 unsigned_cell *words; 153 int i; 154 /* check against the number of arguments specified by the client 155 program */ 156 if ((n_args >= 0 && data->n_args != n_args) 157 || (n_returns >= 0 && data->n_returns != n_returns)) { 158 TRACE(trace_os_emul, ("%s - invalid nr of args - n_args=%ld, n_returns=%ld\n", 159 data->service->name, 160 (long)data->n_args, 161 (long)data->n_returns)); 162 return -1; 163 } 164 /* check that there is enough space */ 165 if (sizeof(unsigned_cell) * (data->n_args + data->n_returns) > sizeof_args) 166 return -1; 167 /* bring in the data */ 168 memset(args, 0, sizeof_args); 169 emul_read_buffer(args, data->arguments + 3 * sizeof(unsigned_cell), 170 sizeof(unsigned_cell) * (data->n_args + data->n_returns), 171 processor, cia); 172 /* convert all words to host format */ 173 words = args; 174 for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++) 175 words[i] = T2H_cell(words[i]); 176 return 0; 177 } 178 179 static void 180 chirp_write_h2t_args(void *args, 181 int sizeof_args, 182 os_emul_data *data, 183 cpu *processor, 184 unsigned_word cia) 185 { 186 int i; 187 unsigned_cell *words; 188 /* convert to target everything */ 189 words = args; 190 for (i = 0; i < (sizeof_args / sizeof(unsigned_cell)); i++) 191 words[i] = H2T_cell(words[i]); 192 /* bring in the data */ 193 emul_write_buffer(args, data->arguments + 3 * sizeof(unsigned_cell), 194 sizeof(unsigned_cell) * (data->n_args + data->n_returns), 195 processor, cia); 196 } 197 198 199 /* OpenBoot emulation functions */ 200 201 /* client interface */ 202 203 static int 204 chirp_emul_test(os_emul_data *data, 205 cpu *processor, 206 unsigned_word cia) 207 { 208 struct test_args { 209 /*in*/ 210 unsigned_cell name; /*string*/ 211 /*out*/ 212 unsigned_cell missing; 213 } args; 214 char name[32]; 215 chirp_services *service = NULL; 216 /* read in the arguments */ 217 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 218 return -1; 219 emul_read_string(name, args.name, sizeof(name), 220 processor, cia); 221 TRACE(trace_os_emul, ("test - in - name=`%s'\n", name)); 222 /* see if we know about the service */ 223 service = data->services; 224 while (service->name != NULL && strcmp(service->name, name) != 0) { 225 service++; 226 } 227 if (service->name == NULL) 228 args.missing = -1; 229 else 230 args.missing = 0; 231 /* write the arguments back out */ 232 TRACE(trace_os_emul, ("test - out - missing=%ld\n", 233 (long)args.missing)); 234 chirp_write_h2t_args(&args, 235 sizeof(args), 236 data, 237 processor, cia); 238 return 0; 239 } 240 241 242 /* Device tree */ 243 244 static int 245 chirp_emul_peer(os_emul_data *data, 246 cpu *processor, 247 unsigned_word cia) 248 { 249 struct peer_args { 250 /*in*/ 251 unsigned_cell phandle; 252 /*out*/ 253 unsigned_cell sibling_phandle; 254 } args; 255 device *phandle; 256 device *sibling_phandle = NULL; 257 /* read in the arguments */ 258 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 259 return -1; 260 phandle = external_to_device(data->root, args.phandle); 261 TRACE(trace_os_emul, ("peer - in - phandle=0x%lx(%p`%s')\n", 262 (unsigned long)args.phandle, 263 phandle, 264 (phandle == NULL ? "" : device_name(phandle)))); 265 /* find the peer */ 266 if (args.phandle == 0) { 267 sibling_phandle = data->root; 268 args.sibling_phandle = device_to_external(sibling_phandle); 269 } 270 else if (phandle == NULL) { 271 sibling_phandle = NULL; 272 args.sibling_phandle = -1; 273 } 274 else { 275 sibling_phandle = device_sibling(phandle); 276 if (sibling_phandle == NULL) 277 args.sibling_phandle = 0; 278 else 279 args.sibling_phandle = device_to_external(sibling_phandle); 280 } 281 /* write the arguments back out */ 282 TRACE(trace_os_emul, ("peer - out - sibling_phandle=0x%lx(%p`%s')\n", 283 (unsigned long)args.sibling_phandle, 284 sibling_phandle, 285 (sibling_phandle == NULL ? "" : device_name(sibling_phandle)))); 286 chirp_write_h2t_args(&args, 287 sizeof(args), 288 data, 289 processor, cia); 290 return 0; 291 } 292 293 static int 294 chirp_emul_child(os_emul_data *data, 295 cpu *processor, 296 unsigned_word cia) 297 { 298 struct child_args { 299 /*in*/ 300 unsigned_cell phandle; 301 /*out*/ 302 unsigned_cell child_phandle; 303 } args; 304 device *phandle; 305 device *child_phandle; 306 /* read the arguments in */ 307 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 308 return -1; 309 phandle = external_to_device(data->root, args.phandle); 310 TRACE(trace_os_emul, ("child - in - phandle=0x%lx(%p`%s')\n", 311 (unsigned long)args.phandle, 312 phandle, 313 (phandle == NULL ? "" : device_name(phandle)))); 314 /* find a child */ 315 if (args.phandle == 0 316 || phandle == NULL) { 317 child_phandle = NULL; 318 args.child_phandle = -1; 319 } 320 else { 321 child_phandle = device_child(phandle); 322 if (child_phandle == NULL) 323 args.child_phandle = 0; 324 else 325 args.child_phandle = device_to_external(child_phandle); 326 } 327 /* write the result out */ 328 TRACE(trace_os_emul, ("child - out - child_phandle=0x%lx(%p`%s')\n", 329 (unsigned long)args.child_phandle, 330 child_phandle, 331 (child_phandle == NULL ? "" : device_name(child_phandle)))); 332 chirp_write_h2t_args(&args, 333 sizeof(args), 334 data, 335 processor, cia); 336 return 0; 337 } 338 339 static int 340 chirp_emul_parent(os_emul_data *data, 341 cpu *processor, 342 unsigned_word cia) 343 { 344 struct parent_args { 345 /*in*/ 346 unsigned_cell phandle; 347 /*out*/ 348 unsigned_cell parent_phandle; 349 } args; 350 device *phandle; 351 device *parent_phandle; 352 /* read the args in */ 353 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 354 return -1; 355 phandle = external_to_device(data->root, args.phandle); 356 TRACE(trace_os_emul, ("parent - in - phandle=0x%lx(%p`%s')\n", 357 (unsigned long)args.phandle, 358 phandle, 359 (phandle == NULL ? "" : device_name(phandle)))); 360 /* find a parent */ 361 if (args.phandle == 0 362 || phandle == NULL) { 363 parent_phandle = NULL; 364 args.parent_phandle = -1; 365 } 366 else { 367 parent_phandle = device_parent(phandle); 368 if (parent_phandle == NULL) 369 args.parent_phandle = 0; 370 else 371 args.parent_phandle = device_to_external(parent_phandle); 372 } 373 /* return the result */ 374 TRACE(trace_os_emul, ("parent - out - parent_phandle=0x%lx(%p`%s')\n", 375 (unsigned long)args.parent_phandle, 376 parent_phandle, 377 (parent_phandle == NULL ? "" : device_name(parent_phandle)))); 378 chirp_write_h2t_args(&args, 379 sizeof(args), 380 data, 381 processor, cia); 382 return 0; 383 } 384 385 static int 386 chirp_emul_instance_to_package(os_emul_data *data, 387 cpu *processor, 388 unsigned_word cia) 389 { 390 struct instance_to_package_args { 391 /*in*/ 392 unsigned_cell ihandle; 393 /*out*/ 394 unsigned_cell phandle; 395 } args; 396 device_instance *ihandle; 397 device *phandle = NULL; 398 /* read the args in */ 399 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 400 return -1; 401 ihandle = external_to_device_instance(data->root, args.ihandle); 402 TRACE(trace_os_emul, ("instance-to-package - in - ihandle=0x%lx(%p`%s')\n", 403 (unsigned long)args.ihandle, 404 ihandle, 405 ihandle_name(ihandle))); 406 /* find the corresponding phandle */ 407 if (ihandle == NULL) { 408 phandle = NULL; 409 args.phandle = -1; 410 } 411 else { 412 phandle = device_instance_device(ihandle); 413 args.phandle = device_to_external(phandle); 414 } 415 /* return the result */ 416 TRACE(trace_os_emul, ("instance-to-package - out - phandle=0x%lx(%p`%s')\n", 417 (unsigned long)args.phandle, 418 phandle, 419 (phandle == NULL ? "" : device_name(phandle)))); 420 chirp_write_h2t_args(&args, 421 sizeof(args), 422 data, 423 processor, cia); 424 return 0; 425 } 426 427 static int 428 chirp_emul_getproplen(os_emul_data *data, 429 cpu *processor, 430 unsigned_word cia) 431 { 432 struct getproplen_args { 433 /*in*/ 434 unsigned_cell phandle; 435 unsigned_cell name; 436 /*out*/ 437 unsigned_cell proplen; 438 } args; 439 char name[32]; 440 device *phandle; 441 /* read the args in */ 442 if (chirp_read_t2h_args(&args, sizeof(args), 2, 1, data, processor, cia)) 443 return -1; 444 phandle = external_to_device(data->root, args.phandle); 445 emul_read_string(name, 446 args.name, 447 sizeof(name), 448 processor, cia); 449 TRACE(trace_os_emul, ("getproplen - in - phandle=0x%lx(%p`%s') name=`%s'\n", 450 (unsigned long)args.phandle, 451 phandle, 452 (phandle == NULL ? "" : device_name(phandle)), 453 name)); 454 /* find our prop and get its length */ 455 if (args.phandle == 0 456 || phandle == NULL) { 457 args.proplen = -1; 458 } 459 else { 460 const device_property *prop = device_find_property(phandle, name); 461 if (prop == (device_property*)0) { 462 args.proplen = -1; 463 } 464 else { 465 args.proplen = prop->sizeof_array; 466 } 467 } 468 /* return the result */ 469 TRACE(trace_os_emul, ("getproplen - out - proplen=%ld\n", 470 (unsigned long)args.proplen)); 471 chirp_write_h2t_args(&args, 472 sizeof(args), 473 data, 474 processor, cia); 475 return 0; 476 } 477 478 static int 479 chirp_emul_getprop(os_emul_data *data, 480 cpu *processor, 481 unsigned_word cia) 482 { 483 struct getprop_args { 484 /*in*/ 485 unsigned_cell phandle; 486 unsigned_cell name; 487 unsigned_cell buf; 488 unsigned_cell buflen; 489 /*out*/ 490 unsigned_cell size; 491 } args; 492 char name[32]; 493 device *phandle; 494 /* read in the args, the return is optional */ 495 if (chirp_read_t2h_args(&args, sizeof(args), 4, -1, data, processor, cia)) 496 return -1; 497 phandle = external_to_device(data->root, args.phandle); 498 emul_read_string(name, 499 args.name, 500 sizeof(name), 501 processor, cia); 502 TRACE(trace_os_emul, ("getprop - in - phandle=0x%lx(%p`%s') name=`%s' buf=0x%lx buflen=%ld\n", 503 (unsigned long)args.phandle, 504 phandle, 505 (phandle == NULL ? "" : device_name(phandle)), 506 name, 507 (unsigned long)args.buf, 508 (unsigned long)args.buflen)); 509 /* get the property */ 510 if (args.phandle == 0 511 || phandle == NULL) { 512 args.size = -1; 513 } 514 else { 515 const device_property *prop = device_find_property(phandle, name); 516 if (prop == NULL) { 517 args.size = -1; 518 } 519 else { 520 int size = args.buflen; 521 if (size > prop->sizeof_array) 522 size = prop->sizeof_array; 523 emul_write_buffer(prop->array, args.buf, 524 size, 525 processor, cia); 526 args.size = size; 527 switch (prop->type) { 528 case string_property: 529 TRACE(trace_os_emul, ("getprop - string `%s'\n", 530 device_find_string_property(phandle, name))); 531 break; 532 case ihandle_property: 533 TRACE(trace_os_emul, ("getprop - ihandle=0x%lx(%p`%s')\n", 534 (unsigned long)BE2H_cell(*(unsigned_cell*)prop->array), 535 device_find_ihandle_property(phandle, name), 536 ihandle_name(device_find_ihandle_property(phandle, name)))); 537 break; 538 default: 539 break; 540 } 541 } 542 } 543 /* write back the result */ 544 if (data->n_returns == 0) 545 TRACE(trace_os_emul, ("getprop - out - size=%ld (not returned)\n", 546 (unsigned long)args.size)); 547 else { 548 TRACE(trace_os_emul, ("getprop - out - size=%ld\n", 549 (unsigned long)args.size)); 550 chirp_write_h2t_args(&args, 551 sizeof(args), 552 data, 553 processor, cia); 554 } 555 return 0; 556 } 557 558 static int 559 chirp_emul_nextprop(os_emul_data *data, 560 cpu *processor, 561 unsigned_word cia) 562 { 563 struct nextprop_args { 564 /*in*/ 565 unsigned_cell phandle; 566 unsigned_cell previous; 567 unsigned_cell buf; 568 /*out*/ 569 unsigned_cell flag; 570 } args; 571 char previous[32]; 572 device *phandle; 573 /* read in the args */ 574 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 575 return -1; 576 phandle = external_to_device(data->root, args.phandle); 577 if (args.previous != 0) 578 emul_read_string(previous, 579 args.previous, 580 sizeof(previous), 581 processor, cia); 582 else 583 /* If previous is NULL, make it look like the empty string. The 584 next property after the empty string is the first property. */ 585 strcpy (previous, ""); 586 TRACE(trace_os_emul, ("nextprop - in - phandle=0x%lx(%p`%s') previous=`%s' buf=0x%lx\n", 587 (unsigned long)args.phandle, 588 phandle, 589 (phandle == NULL ? "" : device_name(phandle)), 590 previous, 591 (unsigned long)args.buf)); 592 /* find the next property */ 593 if (args.phandle == 0 594 || phandle == NULL) { 595 args.flag = -1; 596 } 597 else { 598 const device_property *prev_prop = device_find_property(phandle, previous); 599 if (prev_prop == NULL) { 600 if (strcmp (previous, "") == 0) 601 args.flag = 0; /* No properties */ 602 else 603 args.flag = -1; /* name invalid */ 604 } 605 else { 606 const device_property *next_prop; 607 if (strcmp (previous, "") == 0) { 608 next_prop = prev_prop; /* The first property. */ 609 } 610 else { 611 next_prop = device_next_property(prev_prop); 612 } 613 if (next_prop == NULL) { 614 args.flag = 0; /* last property */ 615 } 616 else { 617 emul_write_buffer(next_prop->name, args.buf, strlen(next_prop->name), 618 processor, cia); 619 TRACE(trace_os_emul, ("nextprop - name=`%s'\n", next_prop->name)); 620 args.flag = 1; /* worked ok */ 621 } 622 } 623 } 624 /* write back the result */ 625 TRACE(trace_os_emul, ("nextprop - out - flag=%ld\n", 626 (unsigned long)args.flag)); 627 chirp_write_h2t_args(&args, 628 sizeof(args), 629 data, 630 processor, cia); 631 return 0; 632 } 633 634 #if 0 635 static int 636 chirp_emul_setprop(os_emul_data *data, 637 cpu *processor, 638 unsigned_word cia) 639 { 640 error("chirp: setprop method not implemented\n"); 641 return 0; 642 } 643 #endif 644 645 static int 646 chirp_emul_canon(os_emul_data *data, 647 cpu *processor, 648 unsigned_word cia) 649 { 650 struct canon_args { 651 /*in*/ 652 unsigned_cell device_specifier; 653 unsigned_cell buf; 654 unsigned_cell buflen; 655 /*out*/ 656 unsigned_cell length; 657 } args; 658 char device_specifier[1024]; 659 device *phandle; 660 const char *path; 661 int length; 662 /* read in the args */ 663 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 664 return -1; 665 emul_read_string(device_specifier, 666 args.device_specifier, 667 sizeof(device_specifier), 668 processor, cia); 669 TRACE(trace_os_emul, ("canon - in - device_specifier=`%s' buf=0x%lx buflen=%lx\n", 670 device_specifier, 671 (unsigned long)args.buf, 672 (unsigned long)args.buflen)); 673 /* canon the name */ 674 phandle = tree_find_device(data->root, device_specifier); 675 if (phandle == NULL) { 676 length = -1; 677 path = ""; 678 args.length = -1; 679 } 680 else { 681 path = device_path(phandle); 682 length = strlen(path); 683 if (length >= args.buflen) 684 length = args.buflen - 1; 685 emul_write_buffer(path, args.buf, length, 686 processor, cia); 687 args.length = length; 688 } 689 /* write back the result */ 690 TRACE(trace_os_emul, ("canon - out - length=%ld buf=`%s'\n", 691 (unsigned long)args.length, 692 path)); 693 chirp_write_h2t_args(&args, 694 sizeof(args), 695 data, 696 processor, cia); 697 return 0; 698 } 699 700 static int 701 chirp_emul_finddevice(os_emul_data *data, 702 cpu *processor, 703 unsigned_word cia) 704 { 705 struct finddevice_args { 706 /*in*/ 707 unsigned_cell device_specifier; 708 /*out*/ 709 unsigned_cell phandle; 710 } args; 711 char device_specifier[1024]; 712 device *phandle; 713 /* get the args */ 714 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 715 return -1; 716 emul_read_string(device_specifier, 717 args.device_specifier, 718 sizeof(device_specifier), 719 processor, cia); 720 TRACE(trace_os_emul, ("finddevice - in - device_specifier=`%s'\n", 721 device_specifier)); 722 /* find the device */ 723 phandle = tree_find_device(data->root, device_specifier); 724 if (phandle == NULL) 725 args.phandle = -1; 726 else 727 args.phandle = device_to_external(phandle); 728 /* return its phandle */ 729 TRACE(trace_os_emul, ("finddevice - out - phandle=0x%lx(%p`%s')\n", 730 (unsigned long)args.phandle, 731 phandle, 732 (phandle == NULL ? "" : device_name(phandle)))); 733 chirp_write_h2t_args(&args, 734 sizeof(args), 735 data, 736 processor, cia); 737 return 0; 738 } 739 740 static int 741 chirp_emul_instance_to_path(os_emul_data *data, 742 cpu *processor, 743 unsigned_word cia) 744 { 745 struct instance_to_path_args { 746 /*in*/ 747 unsigned_cell ihandle; 748 unsigned_cell buf; 749 unsigned_cell buflen; 750 /*out*/ 751 unsigned_cell length; 752 } args; 753 device_instance *ihandle; 754 const char *path; 755 int length; 756 /* get the args */ 757 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 758 return -1; 759 ihandle = external_to_device_instance(data->root, args.ihandle); 760 TRACE(trace_os_emul, ("instance-to-path - in - ihandle=0x%lx(%p`%s') buf=0x%lx buflen=%ld\n", 761 (unsigned long)args.ihandle, 762 ihandle, 763 ihandle_name(ihandle), 764 (unsigned long)args.buf, 765 (unsigned long)args.buflen)); 766 /* get the devices name */ 767 if (ihandle == NULL) { 768 args.length = -1; 769 path = "(null)"; 770 } 771 else { 772 path = device_instance_path(ihandle); 773 length = strlen(path); 774 if (length >= args.buflen) 775 length = args.buflen - 1; 776 emul_write_buffer(path, args.buf, length, 777 processor, cia); 778 args.length = length; 779 } 780 /* return its phandle */ 781 TRACE(trace_os_emul, ("instance-to-path - out - length=%ld buf=`%s')\n", 782 (unsigned long)args.length, 783 path)); 784 chirp_write_h2t_args(&args, 785 sizeof(args), 786 data, 787 processor, cia); 788 return 0; 789 } 790 791 static int 792 chirp_emul_package_to_path(os_emul_data *data, 793 cpu *processor, 794 unsigned_word cia) 795 { 796 struct package_to_path_args { 797 /*in*/ 798 unsigned_cell phandle; 799 unsigned_cell buf; 800 unsigned_cell buflen; 801 /*out*/ 802 unsigned_cell length; 803 } args; 804 device *phandle; 805 const char *path; 806 /* get the args */ 807 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 808 return -1; 809 phandle = external_to_device(data->root, args.phandle); 810 TRACE(trace_os_emul, ("package-to-path - in - phandle=0x%lx(%p`%s') buf=0x%lx buflen=%ld\n", 811 (unsigned long)args.phandle, 812 phandle, 813 (phandle == NULL ? "" : device_name(phandle)), 814 (unsigned long)args.buf, 815 (unsigned long)args.buflen)); 816 /* get the devices name */ 817 if (phandle == NULL) { 818 args.length = -1; 819 path = "(null)"; 820 } 821 else { 822 int length; 823 path = device_path(phandle); 824 length = strlen(path); 825 if (length >= args.buflen) 826 length = args.buflen - 1; 827 emul_write_buffer(path, args.buf, length, 828 processor, cia); 829 args.length = length; 830 } 831 /* return its phandle */ 832 TRACE(trace_os_emul, ("package-to-path - out - length=%ld buf=`%s')\n", 833 (unsigned long)args.length, 834 path)); 835 chirp_write_h2t_args(&args, 836 sizeof(args), 837 data, 838 processor, cia); 839 return 0; 840 } 841 842 static int 843 chirp_emul_call_method(os_emul_data *data, 844 cpu *processor, 845 unsigned_word cia) 846 { 847 struct call_method_args { 848 /*in*/ 849 unsigned_cell method; 850 unsigned_cell ihandle; 851 /*in/out*/ 852 unsigned_cell stack[13]; /*6in + 6out + catch */ 853 } args; 854 char method[32]; 855 device_instance *ihandle; 856 /* some useful info about our mini stack */ 857 int n_stack_args; 858 int n_stack_returns; 859 int stack_catch_result; 860 int stack_returns; 861 /* read the args */ 862 if (chirp_read_t2h_args(&args, sizeof(args), -1, -1, data, processor, cia)) 863 return -1; 864 emul_read_string(method, 865 args.method, 866 sizeof(method), 867 processor, cia); 868 ihandle = external_to_device_instance(data->root, args.ihandle); 869 n_stack_args = data->n_args - 2; 870 n_stack_returns = data->n_returns - 1; 871 stack_catch_result = n_stack_args; 872 stack_returns = stack_catch_result + 1; 873 TRACE(trace_os_emul, ("call-method - in - n_args=%ld n_returns=%ld method=`%s' ihandle=0x%lx(%p`%s')\n", 874 (unsigned long)data->n_args, 875 (unsigned long)data->n_returns, 876 method, 877 (unsigned long)args.ihandle, 878 ihandle, 879 ihandle_name(ihandle))); 880 /* see if we can emulate this method */ 881 if (ihandle == NULL) { 882 /* OpenFirmware doesn't define this error */ 883 error("chirp: invalid ihandle passed to call-method method"); 884 } 885 else { 886 args.stack[stack_catch_result] = 887 device_instance_call_method(ihandle, 888 method, 889 n_stack_args, 890 &args.stack[0], 891 n_stack_returns, 892 &args.stack[stack_returns]); 893 } 894 /* finished */ 895 TRACE(trace_os_emul, ("call-method - out - catch-result=%ld\n", 896 (unsigned long)args.stack[stack_catch_result])); 897 chirp_write_h2t_args(&args, 898 sizeof(args), 899 data, 900 processor, cia); 901 return 0; 902 } 903 904 905 /* Device I/O */ 906 907 static int 908 chirp_emul_open(os_emul_data *data, 909 cpu *processor, 910 unsigned_word cia) 911 { 912 struct open_args { 913 /*in*/ 914 unsigned_cell device_specifier; 915 /*out*/ 916 unsigned_cell ihandle; 917 } args; 918 char device_specifier[1024]; 919 device_instance *ihandle; 920 /* read the args */ 921 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 922 return -1; 923 emul_read_string(device_specifier, 924 args.device_specifier, 925 sizeof(device_specifier), 926 processor, cia); 927 TRACE(trace_os_emul, ("open - in - device_specifier=`%s'\n", 928 device_specifier)); 929 /* open the device */ 930 ihandle = tree_instance(data->root, device_specifier); 931 if (ihandle == NULL) 932 args.ihandle = -1; 933 else 934 args.ihandle = device_instance_to_external(ihandle); 935 /* return the ihandle result */ 936 TRACE(trace_os_emul, ("open - out - ihandle=0x%lx(%p`%s')\n", 937 (unsigned long)args.ihandle, 938 ihandle, 939 ihandle_name(ihandle))); 940 chirp_write_h2t_args(&args, 941 sizeof(args), 942 data, 943 processor, cia); 944 return 0; 945 } 946 947 static int 948 chirp_emul_close(os_emul_data *data, 949 cpu *processor, 950 unsigned_word cia) 951 { 952 struct close_args { 953 /*in*/ 954 unsigned_cell ihandle; 955 /*out*/ 956 } args; 957 device_instance *ihandle; 958 /* read the args */ 959 if (chirp_read_t2h_args(&args, sizeof(args), 1, 0, data, processor, cia)) 960 return -1; 961 ihandle = external_to_device_instance(data->root, args.ihandle); 962 TRACE(trace_os_emul, ("close - in - ihandle=0x%lx(%p`%s')\n", 963 (unsigned long)args.ihandle, 964 ihandle, 965 ihandle_name(ihandle))); 966 /* close the device */ 967 if (ihandle == NULL) { 968 /* OpenFirmware doesn't define this error */ 969 error("chirp: invalid ihandle passed to close method"); 970 } 971 else { 972 device_instance_delete(ihandle); 973 } 974 /* return the ihandle result */ 975 TRACE(trace_os_emul, ("close - out\n")); 976 chirp_write_h2t_args(&args, 977 sizeof(args), 978 data, 979 processor, cia); 980 return 0; 981 } 982 983 static int 984 chirp_emul_read(os_emul_data *data, 985 cpu *processor, 986 unsigned_word cia) 987 { 988 struct read_args { 989 /*in*/ 990 unsigned_cell ihandle; 991 unsigned_cell addr; 992 unsigned_cell len; 993 /*out*/ 994 unsigned_cell actual; 995 } args; 996 char buf[1024]; 997 device_instance *ihandle; 998 /* read the args */ 999 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 1000 return -1; 1001 ihandle = external_to_device_instance(data->root, args.ihandle); 1002 TRACE(trace_os_emul, ("read - in - ihandle=0x%lx(%p`%s') addr=0x%lx len=%ld\n", 1003 (unsigned long)args.ihandle, 1004 ihandle, 1005 ihandle_name(ihandle), 1006 (unsigned long)args.addr, 1007 (unsigned long)args.len)); 1008 if (ihandle == NULL) { 1009 /* OpenFirmware doesn't define this error */ 1010 error("chirp: invalid ihandle passed to read method"); 1011 } 1012 else { 1013 /* do the reads */ 1014 int actual = 0; 1015 while (actual < args.len) { 1016 int remaining = args.len - actual; 1017 int to_read = (remaining <= sizeof(buf) ? remaining : sizeof(buf)); 1018 int nr_read = device_instance_read(ihandle, buf, to_read); 1019 if (nr_read < 0) { 1020 actual = nr_read; /* the error */ 1021 break; 1022 } 1023 else if (nr_read == 0) { 1024 break; 1025 } 1026 emul_write_buffer(buf, 1027 args.addr + actual, 1028 nr_read, 1029 processor, cia); 1030 actual += nr_read; 1031 } 1032 if (actual >= 0) { 1033 args.actual = actual; 1034 if (actual < sizeof(buf)) 1035 buf[actual] = '\0'; 1036 else 1037 buf[sizeof(buf) - 1] = '\0'; 1038 } 1039 else { 1040 switch (actual) { 1041 case sim_io_eof: 1042 args.actual = 0; 1043 break; 1044 case sim_io_not_ready: 1045 ASSERT(sim_io_not_ready == -2); 1046 args.actual = sim_io_not_ready; 1047 break; 1048 default: 1049 error("Bad error value %ld", (long)actual); 1050 break; 1051 } 1052 } 1053 } 1054 /* return the result */ 1055 TRACE(trace_os_emul, ("read - out - actual=%ld `%s'\n", 1056 (long)args.actual, 1057 ((args.actual > 0 && args.actual < sizeof(buf)) ? buf : "") 1058 )); 1059 chirp_write_h2t_args(&args, 1060 sizeof(args), 1061 data, 1062 processor, cia); 1063 return 0; 1064 } 1065 1066 static int 1067 chirp_emul_write(os_emul_data *data, 1068 cpu *processor, 1069 unsigned_word cia) 1070 { 1071 struct write_args { 1072 /*in*/ 1073 unsigned_cell ihandle; 1074 unsigned_cell addr; 1075 unsigned_cell len; 1076 /*out*/ 1077 unsigned_cell actual; 1078 } args; 1079 char buf[1024]; 1080 device_instance *ihandle; 1081 int actual; 1082 /* get the args */ 1083 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 1084 return -1; 1085 actual = args.len; 1086 if (actual >= sizeof(buf)) 1087 actual = sizeof(buf) - 1; 1088 emul_read_buffer(buf, 1089 args.addr, 1090 actual, 1091 processor, cia); 1092 buf[actual] = '\0'; 1093 ihandle = external_to_device_instance(data->root, args.ihandle); 1094 TRACE(trace_os_emul, ("write - in - ihandle=0x%lx(%p`%s') `%s' (%ld)\n", 1095 (unsigned long)args.ihandle, 1096 ihandle, 1097 ihandle_name(ihandle), 1098 buf, (long)actual)); 1099 if (ihandle == NULL) { 1100 /* OpenFirmware doesn't define this error */ 1101 error("chirp: invalid ihandle passed to write method"); 1102 } 1103 else { 1104 /* write it out */ 1105 actual = device_instance_write(ihandle, buf, actual); 1106 if (actual < 0) 1107 args.actual = 0; 1108 else 1109 args.actual = actual; 1110 } 1111 /* return the result */ 1112 TRACE(trace_os_emul, ("write - out - actual=%ld\n", 1113 (long)args.actual)); 1114 chirp_write_h2t_args(&args, 1115 sizeof(args), 1116 data, 1117 processor, cia); 1118 return 0; 1119 } 1120 1121 static int 1122 chirp_emul_seek(os_emul_data *data, 1123 cpu *processor, 1124 unsigned_word cia) 1125 { 1126 struct seek_args { 1127 /*in*/ 1128 unsigned_cell ihandle; 1129 unsigned_cell pos_hi; 1130 unsigned_cell pos_lo; 1131 /*out*/ 1132 unsigned_cell status; 1133 } args; 1134 int status; 1135 device_instance *ihandle; 1136 /* get the args */ 1137 if (chirp_read_t2h_args(&args, sizeof(args), 3, 1, data, processor, cia)) 1138 return -1; 1139 ihandle = external_to_device_instance(data->root, args.ihandle); 1140 TRACE(trace_os_emul, ("seek - in - ihandle=0x%lx(%p`%s') pos.hi=0x%lx pos.lo=0x%lx\n", 1141 (unsigned long)args.ihandle, 1142 ihandle, 1143 ihandle_name(ihandle), 1144 (unsigned long)args.pos_hi, 1145 (unsigned long)args.pos_lo)); 1146 if (ihandle == NULL) { 1147 /* OpenFirmware doesn't define this error */ 1148 error("chirp: invalid ihandle passed to seek method"); 1149 } 1150 else { 1151 /* seek it out */ 1152 status = device_instance_seek(ihandle, args.pos_hi, args.pos_lo); 1153 args.status = status; 1154 } 1155 /* return the result */ 1156 TRACE(trace_os_emul, ("seek - out - status=%ld\n", 1157 (long)args.status)); 1158 chirp_write_h2t_args(&args, 1159 sizeof(args), 1160 data, 1161 processor, cia); 1162 return 0; 1163 } 1164 1165 1166 /* memory */ 1167 1168 static int 1169 chirp_emul_claim(os_emul_data *data, 1170 cpu *processor, 1171 unsigned_word cia) 1172 { 1173 /* NOTE: the client interface claim routine is *very* different to 1174 the "claim" method described in IEEE-1275 appendix A. The latter 1175 uses real addresses while this uses virtual (effective) 1176 addresses. */ 1177 struct claim_args { 1178 /* in */ 1179 unsigned_cell virt; 1180 unsigned_cell size; 1181 unsigned_cell align; 1182 /* out */ 1183 unsigned_cell baseaddr; 1184 } args; 1185 /* read the args */ 1186 if (chirp_read_t2h_args(&args, sizeof(args), 1187 3 /*n_args*/, 1 /*n_returns*/, 1188 data, processor, cia)) 1189 return -1; 1190 TRACE(trace_os_emul, ("claim - in - virt=0x%lx size=%ld align=%d\n", 1191 (unsigned long)args.virt, 1192 (long int)args.size, 1193 (int)args.align)); 1194 /* use the memory device to allocate (real) memory at the requested 1195 address */ 1196 { 1197 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory"); 1198 unsigned_cell mem_in[3]; 1199 unsigned_cell mem_out[1]; 1200 mem_in[0] = args.align; /*top-of-stack*/ 1201 mem_in[1] = args.size; 1202 mem_in[2] = args.virt; 1203 if (device_instance_call_method(memory, "claim", 1204 3, mem_in, 1, mem_out) < 0) 1205 error("chirp: claim failed to allocate memory virt=0x%lx size=%ld align=%d", 1206 (unsigned long)args.virt, 1207 (long int)args.size, 1208 (int)args.align); 1209 args.baseaddr = mem_out[0]; 1210 } 1211 /* if using virtual addresses, create a 1-1 map of this address space */ 1212 if (!data->real_mode) { 1213 error("chirp: claim method does not support virtual mode"); 1214 } 1215 /* return the base address */ 1216 TRACE(trace_os_emul, ("claim - out - baseaddr=0x%lx\n", 1217 (unsigned long)args.baseaddr)); 1218 chirp_write_h2t_args(&args, 1219 sizeof(args), 1220 data, 1221 processor, cia); 1222 return 0; 1223 } 1224 1225 static int 1226 chirp_emul_release(os_emul_data *data, 1227 cpu *processor, 1228 unsigned_word cia) 1229 { 1230 /* NOTE: the client interface release routine is *very* different to 1231 the "claim" method described in IEEE-1275 appendix A. The latter 1232 uses real addresses while this uses virtual (effective) 1233 addresses. */ 1234 struct claim_args { 1235 /* in */ 1236 unsigned_cell virt; 1237 unsigned_cell size; 1238 /* out */ 1239 } args; 1240 /* read the args */ 1241 if (chirp_read_t2h_args(&args, sizeof(args), 1242 2 /*n_args*/, 0 /*n_returns*/, 1243 data, processor, cia)) 1244 return -1; 1245 TRACE(trace_os_emul, ("release - in - virt=0x%lx size=%ld\n", 1246 (unsigned long)args.virt, 1247 (long int)args.size)); 1248 /* use the memory device to release (real) memory at the requested 1249 address */ 1250 { 1251 device_instance *memory = tree_find_ihandle_property(data->root, "/chosen/memory"); 1252 unsigned_cell mem_in[2]; 1253 mem_in[0] = args.size; 1254 mem_in[1] = args.virt; 1255 if (device_instance_call_method(memory, "release", 1256 2, mem_in, 0, NULL) < 0) 1257 error("chirp: claim failed to release memory virt=0x%lx size=%ld", 1258 (unsigned long)args.virt, 1259 (long int)args.size); 1260 } 1261 /* if using virtual addresses, remove the 1-1 map of this address space */ 1262 if (!data->real_mode) { 1263 error("chirp: release method does not support virtual mode"); 1264 } 1265 /* return the base address */ 1266 TRACE(trace_os_emul, ("release - out\n")); 1267 chirp_write_h2t_args(&args, 1268 sizeof(args), 1269 data, 1270 processor, cia); 1271 return 0; 1272 } 1273 1274 1275 /* Control transfer */ 1276 1277 static int 1278 chirp_emul_boot(os_emul_data *data, 1279 cpu *processor, 1280 unsigned_word cia) 1281 { 1282 /* unlike OpenFirmware this one can take an argument */ 1283 struct boot_args { 1284 /*in*/ 1285 unsigned_cell bootspec; 1286 /*out*/ 1287 } args; 1288 char bootspec[1024]; 1289 /* read in the arguments */ 1290 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia)) 1291 cpu_halt(processor, cia, was_exited, -1); 1292 if (args.bootspec != 0) 1293 emul_read_string(bootspec, args.bootspec, sizeof(bootspec), 1294 processor, cia); 1295 else 1296 strcpy(bootspec, "(null)"); 1297 TRACE(trace_os_emul, ("boot - in bootspec=`%s'\n", bootspec)); 1298 /* just report this and exit */ 1299 printf_filtered("chrp: boot %s called, exiting.\n", bootspec); 1300 cpu_halt(processor, cia, was_exited, 0); 1301 return 0; 1302 } 1303 1304 static int 1305 chirp_emul_enter(os_emul_data *data, 1306 cpu *processor, 1307 unsigned_word cia) 1308 { 1309 error("chirp: enter method not implemented\n"); 1310 return 0; 1311 } 1312 1313 static int 1314 chirp_emul_exit(os_emul_data *data, 1315 cpu *processor, 1316 unsigned_word cia) 1317 { 1318 /* unlike OpenBoot this one can take an argument */ 1319 struct exit_args { 1320 /*in*/ 1321 signed_cell status; 1322 /*out*/ 1323 } args; 1324 if (chirp_read_t2h_args(&args, sizeof(args), -1, 0, data, processor, cia)) 1325 cpu_halt(processor, cia, was_exited, -1); 1326 cpu_halt(processor, cia, was_exited, args.status); 1327 return 0; 1328 } 1329 1330 static int 1331 chirp_emul_chain(os_emul_data *data, 1332 cpu *processor, 1333 unsigned_word cia) 1334 { 1335 error("chirp: chain method not implemented\n"); 1336 return 0; 1337 } 1338 1339 1340 /* user interface */ 1341 1342 static int 1343 chirp_emul_interpret(os_emul_data *data, 1344 cpu *processor, 1345 unsigned_word cia) 1346 { 1347 error("chirp: interpret method not implemented\n"); 1348 return 0; 1349 } 1350 1351 static int 1352 chirp_emul_set_callback(os_emul_data *data, 1353 cpu *processor, 1354 unsigned_word cia) 1355 { 1356 error("chirp: set_callback method not implemented\n"); 1357 return 0; 1358 } 1359 1360 static int 1361 chirp_emul_set_symbol_lookup(os_emul_data *data, 1362 cpu *processor, 1363 unsigned_word cia) 1364 { 1365 error("chirp: set_symbol_lookup method not implemented\n"); 1366 return 0; 1367 } 1368 1369 1370 /* Time */ 1371 1372 static int 1373 chirp_emul_milliseconds(os_emul_data *data, 1374 cpu *processor, 1375 unsigned_word cia) 1376 { 1377 struct test_args { 1378 /*in*/ 1379 /*out*/ 1380 unsigned_cell ms; 1381 } args; 1382 uint64_t time; 1383 /* read in the arguments */ 1384 if (chirp_read_t2h_args(&args, sizeof(args), 1, 1, data, processor, cia)) 1385 return -1; 1386 /* make up a number */ 1387 time = event_queue_time(psim_event_queue(cpu_system(processor))) / 1000000; 1388 args.ms = time; 1389 /* write the arguments back out */ 1390 TRACE(trace_os_emul, ("milliseconds - out - ms=%ld\n", 1391 (unsigned long)args.ms)); 1392 chirp_write_h2t_args(&args, 1393 sizeof(args), 1394 data, 1395 processor, cia); 1396 return 0; 1397 } 1398 1399 1400 1401 1402 static chirp_services services[] = { 1403 1404 /* client interface */ 1405 { "test", chirp_emul_test }, 1406 1407 /* device tree */ 1408 { "peer", chirp_emul_peer }, 1409 { "child", chirp_emul_child }, 1410 { "parent", chirp_emul_parent }, 1411 { "instance-to-package", chirp_emul_instance_to_package }, 1412 { "getproplen", chirp_emul_getproplen }, 1413 { "getprop", chirp_emul_getprop }, 1414 { "nextprop", chirp_emul_nextprop }, 1415 /* { "setprop", chirp_emul_setprop }, */ 1416 { "canon", chirp_emul_canon }, 1417 { "finddevice", chirp_emul_finddevice }, 1418 { "instance-to-path", chirp_emul_instance_to_path }, 1419 { "package-to-path", chirp_emul_package_to_path }, 1420 { "call-method", chirp_emul_call_method }, 1421 1422 /* device I/O */ 1423 { "open", chirp_emul_open }, 1424 { "close", chirp_emul_close }, 1425 { "read", chirp_emul_read }, 1426 { "write", chirp_emul_write }, 1427 { "seek", chirp_emul_seek }, 1428 { "write", chirp_emul_write }, 1429 1430 /* memory */ 1431 { "claim", chirp_emul_claim }, 1432 { "release", chirp_emul_release }, 1433 1434 /* control transfer */ 1435 { "boot", chirp_emul_boot }, 1436 { "enter", chirp_emul_enter }, 1437 { "exit", chirp_emul_exit }, 1438 { "chain", chirp_emul_chain }, 1439 1440 /* user interface */ 1441 { "interpret", chirp_emul_interpret }, 1442 { "set_callback", chirp_emul_set_callback }, 1443 { "set_symbol_lookup", chirp_emul_set_symbol_lookup }, 1444 1445 /* time */ 1446 { "milliseconds", chirp_emul_milliseconds }, 1447 1448 { 0, /* sentinal */ }, 1449 }; 1450 1451 1452 /* main handlers */ 1453 1454 /* Any starting address greater than this is assumed to be an Chirp 1455 rather than VEA */ 1456 1457 #ifndef CHIRP_START_ADDRESS 1458 #define CHIRP_START_ADDRESS 0x80000000 1459 #endif 1460 #ifndef CHIRP_LOAD_BASE 1461 #define CHIRP_LOAD_BASE -1 1462 #endif 1463 1464 1465 typedef struct _chirp_note_desc { 1466 int32_t real_mode; 1467 int32_t real_base; 1468 int32_t real_size; 1469 int32_t virt_base; 1470 int32_t virt_size; 1471 int32_t load_base; 1472 } chirp_note_desc; 1473 1474 typedef enum { 1475 note_missing, 1476 note_found, 1477 note_correct, 1478 } note_found_status; 1479 typedef struct _chirp_note { 1480 chirp_note_desc desc; 1481 note_found_status found; 1482 } chirp_note; 1483 1484 typedef struct _chirp_note_head { 1485 uint32_t namesz; 1486 uint32_t descsz; 1487 uint32_t type; 1488 } chirp_note_head; 1489 1490 static void 1491 map_over_chirp_note(bfd *image, 1492 asection *sect, 1493 void *obj) 1494 { 1495 chirp_note *note = (chirp_note*)obj; 1496 if (strcmp(sect->name, ".note") == 0) { 1497 chirp_note_head head; 1498 char name[16]; 1499 /* check the head */ 1500 if (!bfd_get_section_contents(image, sect, 1501 &head, 0, sizeof(head))) 1502 return; 1503 head.namesz = bfd_get_32(image, (void*)&head.namesz); 1504 head.descsz = bfd_get_32(image, (void*)&head.descsz); 1505 head.type = bfd_get_32(image, (void*)&head.type); 1506 if (head.type != 0x1275) 1507 return; 1508 /* check the name field */ 1509 if (head.namesz > sizeof(name)) { 1510 error("chirp: note name too long (%d > %d)\n", (int)head.namesz, (int)sizeof(name)); 1511 } 1512 if (!bfd_get_section_contents(image, sect, 1513 name, sizeof(head), head.namesz)) { 1514 error("chirp: note name unreadable\n"); 1515 } 1516 if (strcmp(name, "PowerPC") != 0) { 1517 printf_filtered("chirp: note name (%s) not `PowerPC'\n", name); 1518 } 1519 /* check the size */ 1520 if (head.descsz == sizeof(note->desc) - sizeof(int32_t)) { 1521 sim_io_printf_filtered("chirp: note descriptor missing load-base\n"); 1522 } 1523 else if (head.descsz != sizeof(note->desc)) { 1524 sim_io_printf_filtered("chirp: note descriptor of wrong size\n"); 1525 note->found = note_found; 1526 return; 1527 } 1528 note->found = note_correct; 1529 /* get the contents */ 1530 if (!bfd_get_section_contents(image, sect, 1531 ¬e->desc, /* page align start */ 1532 ((sizeof(head) + head.namesz) + 3) & ~3, 1533 head.descsz)) { 1534 error("chirp: note descriptor unreadable\n"); 1535 } 1536 note->desc.real_mode = bfd_get_32(image, (void*)¬e->desc.real_mode); 1537 note->desc.real_base = bfd_get_32(image, (void*)¬e->desc.real_base); 1538 note->desc.real_size = bfd_get_32(image, (void*)¬e->desc.real_size); 1539 note->desc.virt_base = bfd_get_32(image, (void*)¬e->desc.virt_base); 1540 note->desc.virt_size = bfd_get_32(image, (void*)¬e->desc.virt_size); 1541 if (head.descsz == sizeof(note->desc)) 1542 note->desc.load_base = bfd_get_32(image, (void*)¬e->desc.load_base); 1543 else 1544 note->desc.load_base = (int32_t)-1; 1545 } 1546 } 1547 1548 1549 static os_emul_data * 1550 emul_chirp_create(device *root, 1551 bfd *image, 1552 const char *name) 1553 { 1554 os_emul_data *chirp; 1555 device *node; 1556 chirp_note note; 1557 int i; 1558 1559 /* Sanity check that this really is the chosen emulation */ 1560 if (name == NULL && image == NULL) 1561 return NULL; 1562 if (name != NULL 1563 && strcmp(name, "ob") != 0 1564 && strcmp(name, "ieee1274") != 0 1565 && strcmp(name, "chrp") != 0 1566 && strcmp(name, "chirp") != 0 1567 && strcmp(name, "openboot") != 0) 1568 return NULL; 1569 1570 /* look for an elf note section, enter its values into the device tree */ 1571 memset(¬e, 0, sizeof(note)); 1572 if (image != NULL) 1573 bfd_map_over_sections(image, map_over_chirp_note, ¬e); 1574 if (name == NULL && image != NULL && note.found == note_missing) 1575 return NULL; 1576 1577 /* Assume that it is a chirp emulation */ 1578 1579 chirp = ZALLOC(os_emul_data); 1580 chirp->root = root; 1581 chirp->services = services; 1582 1583 /* the root node */ 1584 tree_parse(root, "/name \"gpl,clayton"); 1585 1586 /* default options */ 1587 emul_add_tree_options(root, image, "chirp", "oea", 1588 0 /*oea-interrupt-prefix*/); 1589 1590 /* hardware */ 1591 emul_add_tree_hardware(root); 1592 1593 /* basic information */ 1594 chirp->memory_size 1595 = tree_find_integer_property(root, "/openprom/options/oea-memory-size"); 1596 chirp->little_endian 1597 = tree_find_boolean_property(root, "/options/little-endian?"); 1598 chirp->floating_point_available 1599 = tree_find_boolean_property(root, "/openprom/options/floating-point?"); 1600 chirp->interrupt_prefix = 1601 tree_find_integer_property(root, "/openprom/options/oea-interrupt-prefix"); 1602 1603 1604 /* Perform an interum layout of the openboot firmware in memory */ 1605 1606 1607 /* a page for firmware calls */ 1608 chirp->sizeof_code = 4096; 1609 chirp->code_offset = 0x4000; /* possible space for interrupt table */ 1610 1611 /* the stack */ 1612 chirp->sizeof_stack = 32 * 1024; 1613 chirp->stack_offset = chirp->code_offset + chirp->sizeof_code; 1614 1615 /* the hash table */ 1616 if (!note.desc.real_mode) { 1617 chirp->nr_page_table_entry_groups = (chirp->memory_size < 0x800000 1618 ? 1024 /* min allowed */ 1619 : (chirp->memory_size / 4096 / 2)); 1620 chirp->sizeof_htab = chirp->nr_page_table_entry_groups * 64; 1621 } 1622 chirp->htab_offset = chirp->stack_offset + chirp->sizeof_stack; 1623 1624 /* the actual amount of space needed */ 1625 chirp->real_size = chirp->htab_offset + chirp->sizeof_htab; 1626 1627 1628 /* now go through and see if it fits in what is available */ 1629 1630 1631 /* resolve real-mode? */ 1632 if (note.found == note_correct) 1633 chirp->real_mode = note.desc.real_mode; 1634 else if (tree_find_property(root, "/options/real-mode?") != NULL) 1635 chirp->real_mode = tree_find_boolean_property(root, "/options/real-mode?"); 1636 else 1637 chirp->real_mode = 0; 1638 if (tree_find_property(root, "/options/real-mode?") != NULL) { 1639 if (!chirp->real_mode 1640 != !tree_find_boolean_property(root, "/options/real-mode?")) 1641 error("chirp: /options/real-mode? conflicts with note section\n"); 1642 } 1643 else 1644 tree_parse(root, "/options/real-mode? %s", 1645 chirp->real_mode ? "true" : "false"); 1646 1647 /* resolve real-base */ 1648 if (note.found == note_correct 1649 && note.desc.real_base != (int32_t)-1) 1650 chirp->real_base = note.desc.real_base; 1651 else if (tree_find_property(root, "/options/real-base") != NULL) 1652 chirp->real_base = tree_find_integer_property(root, "/options/real-base"); 1653 else 1654 chirp->real_base = chirp->memory_size - chirp->real_size; 1655 if (tree_find_property(root, "/options/real-base") != NULL) { 1656 if (chirp->real_base != tree_find_integer_property(root, "/options/real-base")) 1657 error("chirp: /options/real-base conflicts with note section\n"); 1658 } 1659 else 1660 tree_parse(root, "/options/real-base 0x%lx", 1661 (unsigned long)chirp->real_base); 1662 1663 /* resolve real-size */ 1664 if (note.found == note_correct 1665 && note.desc.real_size != (int32_t)-1 1666 && note.desc.real_size != 0 1667 && chirp->real_size > note.desc.real_size) 1668 error("chirp: insufficient physical memory for firmware\n"); 1669 if (tree_find_property(root, "/options/real-size") != NULL) { 1670 if (chirp->real_size > tree_find_integer_property(root, "/options/real-size")) 1671 error("chirp: /options/real-size conflicts with note section\n"); 1672 } 1673 else 1674 tree_parse(root, "/options/real-size 0x%lx", 1675 (unsigned long)chirp->real_size); 1676 1677 /* resolve virt-base */ 1678 if (chirp->real_mode) 1679 chirp->virt_base = chirp->real_base; 1680 else if (note.found == note_correct && note.desc.virt_base != -1) 1681 chirp->virt_base = note.desc.virt_base; 1682 else if (tree_find_property(root, "/options/virt-base") != NULL) 1683 chirp->virt_base = tree_find_integer_property(root, "/options/virt-base"); 1684 else 1685 chirp->virt_base = CHIRP_START_ADDRESS; 1686 if (tree_find_property(root, "/options/virt-base") != NULL) { 1687 unsigned_word virt_base = tree_find_integer_property(root, "/options/virt-base"); 1688 if (virt_base != -1 && chirp->virt_base != virt_base) 1689 error("chirp: /options/virt-base conflicts with note section\n"); 1690 } 1691 else 1692 tree_parse(root, "/options/virt-base 0x%lx", 1693 chirp->real_mode ? -1 : (unsigned long)chirp->virt_base); 1694 1695 /* resolve virt-size */ 1696 chirp->virt_size = chirp->real_size; 1697 if (note.found == note_correct 1698 && note.desc.virt_size != (int32_t)-1 1699 && note.desc.virt_size != 0 1700 && !chirp->real_mode 1701 && chirp->virt_size > note.desc.virt_size) 1702 error("chirp: insufficent virtual memory for firmware\n"); 1703 if (tree_find_property(root, "/options/virt-size") != NULL) { 1704 if (chirp->virt_size > tree_find_integer_property(root, "/options/virt-size")) 1705 error("chirp: /options/virt-size conflicts with note section\n"); 1706 } 1707 else 1708 tree_parse(root, "/options/virt-size 0x%lx", 1709 chirp->real_mode ? -1 : (unsigned long)chirp->virt_size); 1710 1711 /* resolve load-base */ 1712 if (note.found == note_correct 1713 && note.desc.load_base != (int32_t)-1) 1714 chirp->load_base = note.desc.load_base; 1715 else if (tree_find_property(root, "/options/load-base") != NULL) 1716 chirp->load_base = tree_find_integer_property(root, "/options/load-base"); 1717 else 1718 chirp->load_base = CHIRP_LOAD_BASE; 1719 if (tree_find_property(root, "/options/load-base") != NULL) { 1720 if (chirp->load_base != tree_find_integer_property(root, "/options/load-base")) 1721 error("chirp: /options/load-base conflicts with note section\n"); 1722 } 1723 else 1724 tree_parse(root, "/options/load-base 0x%lx", 1725 (unsigned long)chirp->load_base); 1726 1727 /* now adjust the preliminary firmware addresses to final values */ 1728 chirp->code_ra = chirp->code_offset + chirp->real_base; 1729 chirp->stack_ra = chirp->stack_offset + chirp->real_base; 1730 chirp->htab_ra = chirp->htab_offset + chirp->real_base; 1731 1732 /* the virtual addresses. In real mode these are real addresses. */ 1733 1734 chirp->code_va = chirp->code_offset + chirp->virt_base; 1735 chirp->stack_va = chirp->stack_offset + chirp->virt_base; 1736 chirp->htab_va = chirp->htab_offset + chirp->virt_base; 1737 1738 chirp->code_client_va = chirp->code_va; 1739 chirp->code_client_ra = chirp->code_ra; 1740 1741 chirp->code_callback_va = chirp->code_client_va + 16; 1742 chirp->code_callback_ra = chirp->code_client_ra + 16; 1743 1744 chirp->code_loop_va = chirp->code_callback_va + 16; 1745 chirp->code_loop_ra = chirp->code_callback_ra + 16; 1746 1747 /* initialization */ 1748 1749 tree_parse(root, "/openprom/init"); 1750 tree_parse(root, "/openprom/init/register"); 1751 tree_parse(root, "/openprom/init/register/0.pc 0x%lx", 1752 (unsigned long)bfd_get_start_address(image)); 1753 tree_parse(root, "/openprom/init/register/pc 0x%lx", 1754 (unsigned long)chirp->code_loop_va); 1755 tree_parse(root, "/openprom/init/register/msr 0x%x", 1756 (msr_machine_check_enable 1757 | (chirp->real_mode 1758 ? 0 1759 : (msr_instruction_relocate 1760 | msr_data_relocate)) 1761 | (chirp->little_endian 1762 ? (msr_little_endian_mode 1763 | msr_interrupt_little_endian_mode) 1764 : 0) 1765 | (chirp->floating_point_available 1766 ? msr_floating_point_available 1767 : 0) 1768 | (chirp->interrupt_prefix 1769 ? msr_interrupt_prefix 1770 : 0) 1771 )); 1772 tree_parse(root, "/openprom/init/register/sdr1 0x%lx", 1773 (unsigned long)(chirp->htab_ra 1774 | MASK32(16, 22) 1775 | ((chirp->sizeof_htab - 1) >> 16))); 1776 /* make certain that the segment registers map straight through */ 1777 for (i = 0; i < 16; i++) { 1778 tree_parse(root, "/openprom/init/register/sr%d 0x%lx", 1779 i, (unsigned long)i); 1780 } 1781 1782 /* establish an initial state for all processors */ 1783 1784 1785 /* the client interface address */ 1786 tree_parse(root, "/openprom/init/register/r5 0x%lx", 1787 (unsigned long)chirp->code_client_va); 1788 /* a stack */ 1789 tree_parse(root, "/openprom/init/register/sp 0x%lx", 1790 (unsigned long)(chirp->stack_va + chirp->sizeof_stack - 16)); 1791 /* in chrp mode any arguments end up being concatinated */ 1792 tree_parse(root, "/openprom/init/stack/stack-type chirp"); 1793 1794 1795 /* client interface - emul-call followed by return instruction */ 1796 1797 1798 node = tree_parse(root, "/openprom/init/data@0x%lx", 1799 (unsigned long)chirp->code_client_ra); 1800 tree_parse(node, "./psim,description \"client-interface instruction"); 1801 tree_parse(node, "./real-address 0x%lx", 1802 (unsigned long)chirp->code_client_ra); 1803 tree_parse(node, "./data 0x%lx", 1804 (unsigned long)emul_call_instruction); 1805 1806 node = tree_parse(root, "/openprom/init/data@0x%lx", 1807 (unsigned long)(chirp->code_client_ra + 4)); 1808 tree_parse(node, "./psim,description \"client-interface return instruction"); 1809 tree_parse(node, "./real-address 0x%lx", 1810 (unsigned long)(chirp->code_client_ra + 4)); 1811 tree_parse(node, "./data 0x%lx", 1812 (unsigned long)emul_blr_instruction); 1813 1814 1815 /* return address for client callbacks - an emul-call instruction 1816 that is again followed by a return instruction */ 1817 1818 1819 node = tree_parse(root, "/openprom/init/data@0x%lx", 1820 (unsigned long)chirp->code_callback_ra); 1821 tree_parse(node, "./psim,description \"client-callback instruction"); 1822 tree_parse(node, "./real-address 0x%lx", 1823 (unsigned long)chirp->code_callback_ra); 1824 tree_parse(node, "./data 0x%lx", 1825 (unsigned long)emul_call_instruction); 1826 1827 node = tree_parse(root, "/openprom/init/data@0x%lx", 1828 (unsigned long)(chirp->code_callback_ra + 4)); 1829 tree_parse(node, "./psim,description \"client-callback return instruction"); 1830 tree_parse(node, "./real-address 0x%lx", 1831 (unsigned long)(chirp->code_callback_ra + 4)); 1832 tree_parse(node, "./data 0x%lx", 1833 (unsigned long)emul_blr_instruction); 1834 1835 /* loop to keep other processors busy */ 1836 1837 node = tree_parse(root, "/openprom/init/data@0x%lx", 1838 (unsigned long)chirp->code_loop_ra); 1839 tree_parse(node, "./psim,description \"processor busy loop"); 1840 tree_parse(node, "./real-address 0x%lx", 1841 (unsigned long)chirp->code_loop_ra); 1842 tree_parse(node, "./data 0x%lx", 1843 (unsigned long)emul_loop_instruction); 1844 1845 /* hash table */ 1846 1847 /* create a hash table */ 1848 1849 if (!chirp->real_mode) { 1850 node = tree_parse(root, "/openprom/init/htab@0x%lx", 1851 (unsigned long)chirp->htab_ra); 1852 tree_parse(node, "./claim 0"); 1853 tree_parse(node, "./real-address 0x%lx", 1854 (unsigned long)chirp->htab_ra); 1855 tree_parse(node, "./nr-bytes 0x%lx", 1856 (unsigned long)chirp->sizeof_htab); 1857 } 1858 1859 /* map in the stack */ 1860 1861 if (!chirp->real_mode) { 1862 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", 1863 (unsigned long)chirp->stack_ra); 1864 tree_parse(node, "./psim,description \"map in the stack"); 1865 tree_parse(node, "./claim 1"); 1866 tree_parse(node, "./virtual-address 0x%lx", 1867 (unsigned long)chirp->stack_va); 1868 tree_parse(node, "./real-address 0x%lx", 1869 (unsigned long)chirp->stack_ra); 1870 tree_parse(node, "./nr-bytes 0x%lx", 1871 (unsigned long)chirp->sizeof_stack); 1872 tree_parse(node, "./wimg %d", 0x7); 1873 tree_parse(node, "./pp %d", 0x2); 1874 } 1875 1876 /* map in the chrp openboot callback code */ 1877 1878 if (!chirp->real_mode) { 1879 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", 1880 (unsigned long)chirp->code_ra); 1881 tree_parse(node, "./psim,description \"map in chrp openboot callback code"); 1882 tree_parse(node, "./claim 1"); 1883 tree_parse(node, "./virtual-address 0x%lx", 1884 (unsigned long)chirp->code_va); 1885 tree_parse(node, "./real-address 0x%lx", 1886 (unsigned long)chirp->code_ra); 1887 tree_parse(node, "./nr-bytes 0x%lx", 1888 (unsigned long)chirp->sizeof_code); 1889 tree_parse(node, "./wimg %d", 0x7); 1890 tree_parse(node, "./pp %d", 0x2); 1891 } 1892 1893 /* map in the program to run */ 1894 1895 if (chirp->real_mode) { 1896 node = tree_parse(node, "/openprom/init/load-binary"); 1897 tree_parse(node, "./psim,description \"load the binary"); 1898 tree_parse(node, "./file-name %s", bfd_get_filename(image)); 1899 tree_parse(node, "./claim 1"); 1900 } 1901 else { 1902 node = tree_parse(root, "/openprom/init/htab/pte@0x%lx", 1903 (unsigned long)chirp->load_base); 1904 tree_parse(node, "./psim,description \"load & map the binary"); 1905 tree_parse(node, "./claim 1"); 1906 tree_parse(node, "./file-name \"%s", bfd_get_filename(image)); 1907 tree_parse(node, "./wimg %d", 0x7); 1908 tree_parse(node, "./pp %d", 0x2); 1909 } 1910 1911 /* map in the interrupt vectors */ 1912 1913 if (!chirp->real_mode) { 1914 node = tree_parse(root, "/openprom/init/htab/pte@0x0"); 1915 tree_parse(node, "./psim,description \"map in interrupt vectors"); 1916 tree_parse(node, "./virtual-address 0x0"); 1917 tree_parse(node, "./real-address 0x0"); 1918 tree_parse(node, "./nr-bytes 0x3000"); 1919 tree_parse(node, "./wimg %d", 0x7); 1920 tree_parse(node, "./pp %d", 0x2); 1921 } 1922 1923 return chirp; 1924 } 1925 1926 static void 1927 emul_chirp_init(os_emul_data *emul_data, 1928 int nr_cpus) 1929 { 1930 emul_data->state = serving; 1931 } 1932 1933 static int 1934 emul_chirp_instruction_call(cpu *processor, 1935 unsigned_word cia, 1936 unsigned_word ra, 1937 os_emul_data *emul_data) 1938 { 1939 unsigned_word service_name_addr; 1940 unsigned_word result; 1941 char service_buf[32]; 1942 char *service_name; 1943 chirp_services *service; 1944 1945 switch (emul_data->state) { 1946 1947 case serving: 1948 /* we are waiting on an OpenBoot request from the client program 1949 via the client interface */ 1950 if (cia != emul_data->code_client_va) 1951 return 0; 1952 emul_data->return_address = LR; 1953 emul_data->arguments = cpu_registers(processor)->gpr[3]; 1954 /* try to determine what to do */ 1955 service_name_addr = emul_read_word(cpu_registers(processor)->gpr[3], 1956 processor, cia); 1957 service_name = emul_read_string(service_buf, service_name_addr, 1958 sizeof(service_buf), processor, cia); 1959 emul_data->n_args = emul_read_word(emul_data->arguments + sizeof(unsigned_cell), 1960 processor, cia); 1961 emul_data->n_returns = emul_read_word(emul_data->arguments + 2 * sizeof(unsigned_cell), 1962 processor, cia); 1963 /* verify what was passed */ 1964 if (service_name_addr == 0 1965 || service_name == NULL) { 1966 error("OpenFirmware called with invalid (NULL) service name from 0x%lx with args 0x%lx\n", 1967 (unsigned long)emul_data->return_address, 1968 (unsigned long)emul_data->arguments); 1969 } 1970 if (emul_data->n_args > 6) { /* See iee1275 requirements on nr returns */ 1971 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, too many args (%d)\n", 1972 service_name, 1973 (unsigned long)emul_data->return_address, 1974 (unsigned long)emul_data->arguments, 1975 emul_data->n_returns); 1976 } 1977 if (emul_data->n_returns > 6) { 1978 error("OpenFirmware service %s called from 0x%lx with args 0x%lx, with too many returns (%d)\n", 1979 service_name, 1980 (unsigned long)emul_data->return_address, 1981 (unsigned long)emul_data->arguments, 1982 emul_data->n_args); 1983 } 1984 /* look it up */ 1985 TRACE(trace_os_emul, ("%s called from 0x%lx with args 0x%lx\n", 1986 service_name, 1987 (unsigned long)emul_data->return_address, 1988 (unsigned long)emul_data->arguments)); 1989 service = services; 1990 while (service->name != NULL && strcmp(service->name, service_name) != 0) 1991 service++; 1992 /* found or not? */ 1993 if (service->name == NULL) { 1994 error("OpenBoot service `%s' not found\n", service_name); 1995 TRACE(trace_os_emul, ("%s not found\n", service_name)); 1996 cpu_registers(processor)->gpr[3] = -1; 1997 } 1998 else { 1999 emul_data->service = service; 2000 /* call upon it */ 2001 result = service->handler(emul_data, processor, cia); 2002 if (result != 0) 2003 TRACE(trace_os_emul, ("%s aborted with %ld\n", service_name, (long)result)); 2004 cpu_registers(processor)->gpr[3] = result; 2005 } 2006 break; 2007 2008 default: 2009 error("emul_chirp_instruction_call() unknown internal state\n"); 2010 result = -1; 2011 break; 2012 2013 } 2014 2015 /* return to caller - instruction following this is a function return */ 2016 return 1; 2017 } 2018 2019 const os_emul emul_chirp = { 2020 "chirp", 2021 emul_chirp_create, 2022 emul_chirp_init, 2023 NULL, /*system_call*/ 2024 emul_chirp_instruction_call, 2025 0 /*data*/ 2026 }; 2027 2028 #endif 2029