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