1 /* 2 * Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2019, Adrien Destugues, pulkomandy@pulkomandy.tk 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include <platform/openfirmware/openfirmware.h> 8 9 #include <stdarg.h> 10 11 12 // OpenFirmware entry function 13 static intptr_t (*gCallOpenFirmware)(void *) = 0; 14 intptr_t gChosen; 15 16 17 status_t 18 of_init(intptr_t (*openFirmwareEntry)(void *)) 19 { 20 gCallOpenFirmware = openFirmwareEntry; 21 22 gChosen = of_finddevice("/chosen"); 23 if (gChosen == OF_FAILED) 24 return B_ERROR; 25 26 return B_OK; 27 } 28 29 30 intptr_t 31 of_call_client_function(const char *method, intptr_t numArgs, 32 intptr_t numReturns, ...) 33 { 34 struct { 35 const char *name; 36 intptr_t num_args; 37 intptr_t num_returns; 38 void *args[10]; 39 } args = {method, numArgs, numReturns}; 40 va_list list; 41 int i; 42 43 // iterate over all arguments and copy them into the 44 // structure passed over to the OpenFirmware 45 46 va_start(list, numReturns); 47 for (i = 0; i < numArgs; i++) { 48 // copy args 49 args.args[i] = (void *)va_arg(list, void *); 50 } 51 for (i = numArgs; i < numArgs + numReturns; i++) { 52 // clear return values 53 args.args[i] = NULL; 54 } 55 56 if (gCallOpenFirmware(&args) == OF_FAILED) 57 return OF_FAILED; 58 59 if (numReturns > 0) { 60 // copy return values over to the provided location 61 62 for (i = numArgs; i < numArgs + numReturns; i++) { 63 void **store = va_arg(list, void **); 64 if (store) 65 *store = args.args[i]; 66 } 67 } 68 va_end(list); 69 70 return 0; 71 } 72 73 74 intptr_t 75 of_interpret(const char *command, intptr_t numArgs, intptr_t numReturns, ...) 76 { 77 struct { 78 const char *name; 79 intptr_t num_args; 80 intptr_t num_returns; 81 // "IN: [string] cmd, stack_arg1, ..., stack_argP 82 // OUT: catch-result, stack_result1, ..., stack_resultQ 83 // [...] 84 // An implementation shall allow at least six stack_arg and six 85 // stack_result items." 86 const char *command; 87 void *args[13]; 88 } args = {"interpret", numArgs + 1, numReturns + 1, command}; 89 va_list list; 90 int i; 91 92 // iterate over all arguments and copy them into the 93 // structure passed over to the OpenFirmware 94 95 va_start(list, numReturns); 96 for (i = 0; i < numArgs; i++) { 97 // copy args 98 args.args[i] = (void *)va_arg(list, void *); 99 } 100 for (i = numArgs; i < numArgs + numReturns + 1; i++) { 101 // clear return values 102 args.args[i] = NULL; 103 } 104 105 // args.args[numArgs] is the "catch-result" return value 106 if (gCallOpenFirmware(&args) == OF_FAILED || args.args[numArgs]) 107 return OF_FAILED; 108 109 if (numReturns > 0) { 110 // copy return values over to the provided location 111 112 for (i = numArgs + 1; i < numArgs + 1 + numReturns; i++) { 113 void **store = va_arg(list, void **); 114 if (store) 115 *store = args.args[i]; 116 } 117 } 118 va_end(list); 119 120 return 0; 121 } 122 123 124 intptr_t 125 of_call_method(uint32_t handle, const char *method, intptr_t numArgs, 126 intptr_t numReturns, ...) 127 { 128 struct { 129 const char *name; 130 intptr_t num_args; 131 intptr_t num_returns; 132 // "IN: [string] method, ihandle, stack_arg1, ..., stack_argP 133 // OUT: catch-result, stack_result1, ..., stack_resultQ 134 // [...] 135 // An implementation shall allow at least six stack_arg and six 136 // stack_result items." 137 const char *method; 138 intptr_t handle; 139 void *args[13]; 140 } args = {"call-method", numArgs + 2, numReturns + 1, method, handle}; 141 va_list list; 142 int i; 143 144 // iterate over all arguments and copy them into the 145 // structure passed over to the OpenFirmware 146 147 va_start(list, numReturns); 148 for (i = 0; i < numArgs; i++) { 149 // copy args 150 args.args[i] = (void *)va_arg(list, void *); 151 } 152 for (i = numArgs; i < numArgs + numReturns + 1; i++) { 153 // clear return values 154 args.args[i] = NULL; 155 } 156 157 // args.args[numArgs] is the "catch-result" return value 158 if (gCallOpenFirmware(&args) == OF_FAILED || args.args[numArgs]) 159 return OF_FAILED; 160 161 if (numReturns > 0) { 162 // copy return values over to the provided location 163 164 for (i = numArgs + 1; i < numArgs + 1 + numReturns; i++) { 165 void **store = va_arg(list, void **); 166 if (store) 167 *store = args.args[i]; 168 } 169 } 170 va_end(list); 171 172 return 0; 173 } 174 175 176 intptr_t 177 of_finddevice(const char *device) 178 { 179 struct { 180 const char *name; 181 intptr_t num_args; 182 intptr_t num_returns; 183 const char *device; 184 intptr_t handle; 185 } args = {"finddevice", 1, 1, device, 0}; 186 187 if (gCallOpenFirmware(&args) == OF_FAILED) 188 return OF_FAILED; 189 190 return args.handle; 191 } 192 193 194 /** Returns the first child of the given node 195 */ 196 197 intptr_t 198 of_child(intptr_t node) 199 { 200 struct { 201 const char *name; 202 intptr_t num_args; 203 intptr_t num_returns; 204 intptr_t node; 205 intptr_t child; 206 } args = {"child", 1, 1, node, 0}; 207 208 if (gCallOpenFirmware(&args) == OF_FAILED) 209 return OF_FAILED; 210 211 return args.child; 212 } 213 214 215 /** Returns the next sibling of the given node 216 */ 217 218 intptr_t 219 of_peer(intptr_t node) 220 { 221 struct { 222 const char *name; 223 intptr_t num_args; 224 intptr_t num_returns; 225 intptr_t node; 226 intptr_t next_sibling; 227 } args = {"peer", 1, 1, node, 0}; 228 229 if (gCallOpenFirmware(&args) == OF_FAILED) 230 return OF_FAILED; 231 232 return args.next_sibling; 233 } 234 235 236 /** Returns the parent of the given node 237 */ 238 239 intptr_t 240 of_parent(intptr_t node) 241 { 242 struct { 243 const char *name; 244 intptr_t num_args; 245 intptr_t num_returns; 246 intptr_t node; 247 intptr_t parent; 248 } args = {"parent", 1, 1, node, 0}; 249 250 if (gCallOpenFirmware(&args) == OF_FAILED) 251 return OF_FAILED; 252 253 return args.parent; 254 } 255 256 257 intptr_t 258 of_instance_to_path(uint32_t instance, char *pathBuffer, intptr_t bufferSize) 259 { 260 struct { 261 const char *name; 262 intptr_t num_args; 263 intptr_t num_returns; 264 intptr_t instance; 265 char *path_buffer; 266 intptr_t buffer_size; 267 intptr_t size; 268 } args = {"instance-to-path", 3, 1, instance, pathBuffer, bufferSize, 0}; 269 270 if (gCallOpenFirmware(&args) == OF_FAILED) 271 return OF_FAILED; 272 273 return args.size; 274 } 275 276 277 intptr_t 278 of_instance_to_package(uint32_t instance) 279 { 280 struct { 281 const char *name; 282 intptr_t num_args; 283 intptr_t num_returns; 284 intptr_t instance; 285 intptr_t package; 286 } args = {"instance-to-package", 1, 1, instance, 0}; 287 288 if (gCallOpenFirmware(&args) == OF_FAILED) 289 return OF_FAILED; 290 291 return args.package; 292 } 293 294 295 intptr_t 296 of_getprop(intptr_t package, const char *property, void *buffer, intptr_t bufferSize) 297 { 298 struct { 299 const char *name; 300 intptr_t num_args; 301 intptr_t num_returns; 302 intptr_t package; 303 const char *property; 304 void *buffer; 305 intptr_t buffer_size; 306 intptr_t size; 307 } args = {"getprop", 4, 1, package, property, buffer, bufferSize, 0}; 308 309 if (gCallOpenFirmware(&args) == OF_FAILED) 310 return OF_FAILED; 311 312 return args.size; 313 } 314 315 316 intptr_t 317 of_setprop(intptr_t package, const char *property, const void *buffer, 318 intptr_t bufferSize) 319 { 320 struct { 321 const char *name; 322 intptr_t num_args; 323 intptr_t num_returns; 324 intptr_t package; 325 const char *property; 326 const void *buffer; 327 intptr_t buffer_size; 328 intptr_t size; 329 } args = {"setprop", 4, 1, package, property, buffer, bufferSize, 0}; 330 331 if (gCallOpenFirmware(&args) == OF_FAILED) 332 return OF_FAILED; 333 334 return args.size; 335 } 336 337 338 intptr_t 339 of_getproplen(intptr_t package, const char *property) 340 { 341 struct { 342 const char *name; 343 intptr_t num_args; 344 intptr_t num_returns; 345 intptr_t package; 346 const char *property; 347 intptr_t size; 348 } args = {"getproplen", 2, 1, package, property, 0}; 349 350 if (gCallOpenFirmware(&args) == OF_FAILED) 351 return OF_FAILED; 352 353 return args.size; 354 } 355 356 357 intptr_t 358 of_nextprop(intptr_t package, const char *previousProperty, char *nextProperty) 359 { 360 struct { 361 const char *name; 362 intptr_t num_args; 363 intptr_t num_returns; 364 intptr_t package; 365 const char *previous_property; 366 char *next_property; 367 intptr_t flag; 368 } args = {"nextprop", 3, 1, package, previousProperty, nextProperty, 0}; 369 370 if (gCallOpenFirmware(&args) == OF_FAILED) 371 return OF_FAILED; 372 373 return args.flag; 374 } 375 376 377 intptr_t 378 of_package_to_path(intptr_t package, char *pathBuffer, intptr_t bufferSize) 379 { 380 struct { 381 const char *name; 382 intptr_t num_args; 383 intptr_t num_returns; 384 intptr_t package; 385 char *path_buffer; 386 intptr_t buffer_size; 387 intptr_t size; 388 } args = {"package-to-path", 3, 1, package, pathBuffer, bufferSize, 0}; 389 390 if (gCallOpenFirmware(&args) == OF_FAILED) 391 return OF_FAILED; 392 393 return args.size; 394 } 395 396 397 // I/O functions 398 399 400 intptr_t 401 of_open(const char *nodeName) 402 { 403 struct { 404 const char *name; 405 intptr_t num_args; 406 intptr_t num_returns; 407 const char *node_name; 408 intptr_t handle; 409 } args = {"open", 1, 1, nodeName, 0}; 410 411 if (gCallOpenFirmware(&args) == OF_FAILED || args.handle == 0) 412 return OF_FAILED; 413 414 return args.handle; 415 } 416 417 418 void 419 of_close(intptr_t handle) 420 { 421 struct { 422 const char *name; 423 intptr_t num_args; 424 intptr_t num_returns; 425 intptr_t handle; 426 } args = {"close", 1, 0, handle}; 427 428 gCallOpenFirmware(&args); 429 } 430 431 432 intptr_t 433 of_read(intptr_t handle, void *buffer, intptr_t bufferSize) 434 { 435 struct { 436 const char *name; 437 intptr_t num_args; 438 intptr_t num_returns; 439 intptr_t handle; 440 void *buffer; 441 intptr_t buffer_size; 442 intptr_t size; 443 } args = {"read", 3, 1, handle, buffer, bufferSize, 0}; 444 445 if (gCallOpenFirmware(&args) == OF_FAILED) 446 return OF_FAILED; 447 448 return args.size; 449 } 450 451 452 intptr_t 453 of_write(intptr_t handle, const void *buffer, intptr_t bufferSize) 454 { 455 struct { 456 const char *name; 457 intptr_t num_args; 458 intptr_t num_returns; 459 intptr_t handle; 460 const void *buffer; 461 intptr_t buffer_size; 462 intptr_t size; 463 } args = {"write", 3, 1, handle, buffer, bufferSize, 0}; 464 465 if (gCallOpenFirmware(&args) == OF_FAILED) 466 return OF_FAILED; 467 468 return args.size; 469 } 470 471 472 intptr_t 473 of_seek(intptr_t handle, off_t pos) 474 { 475 intptr_t pos_hi = 0; 476 if (sizeof(off_t) > sizeof(intptr_t)) 477 pos_hi = pos >> ((sizeof(off_t) - sizeof(intptr_t)) * CHAR_BIT); 478 479 struct { 480 const char *name; 481 intptr_t num_args; 482 intptr_t num_returns; 483 intptr_t handle; 484 intptr_t pos_hi; 485 intptr_t pos; 486 intptr_t status; 487 } args = {"seek", 3, 1, handle, pos_hi, pos, 0}; 488 489 if (gCallOpenFirmware(&args) == OF_FAILED) 490 return OF_FAILED; 491 492 return args.status; 493 } 494 495 496 intptr_t 497 of_blocks(intptr_t handle) 498 { 499 struct { 500 const char *name; 501 intptr_t num_args; 502 intptr_t num_returns; 503 intptr_t handle; 504 intptr_t result; 505 intptr_t blocks; 506 } args = {"#blocks", 2, 1, handle, 0, 0}; 507 508 if (gCallOpenFirmware(&args) == OF_FAILED) 509 return OF_FAILED; 510 return args.blocks; 511 } 512 513 514 intptr_t 515 of_block_size(intptr_t handle) 516 { 517 struct { 518 const char *name; 519 intptr_t num_args; 520 intptr_t num_returns; 521 intptr_t handle; 522 intptr_t result; 523 intptr_t size; 524 } args = {"block-size", 2, 1, handle, 0, 0}; 525 526 if (gCallOpenFirmware(&args) == OF_FAILED) 527 return OF_FAILED; 528 return args.size; 529 } 530 531 532 // memory functions 533 534 535 intptr_t 536 of_release(void *virtualAddress, intptr_t size) 537 { 538 struct { 539 const char *name; 540 intptr_t num_args; 541 intptr_t num_returns; 542 void *virtualAddress; 543 intptr_t size; 544 } args = {"release", 2, 0, virtualAddress, size}; 545 546 return gCallOpenFirmware(&args); 547 } 548 549 550 void * 551 of_claim(void *virtualAddress, intptr_t size, intptr_t align) 552 { 553 struct { 554 const char *name; 555 intptr_t num_args; 556 intptr_t num_returns; 557 void *virtualAddress; 558 intptr_t size; 559 intptr_t align; 560 void *address; 561 } args = {"claim", 3, 1, virtualAddress, size, align}; 562 563 if (gCallOpenFirmware(&args) == OF_FAILED) 564 return NULL; 565 566 return args.address; 567 } 568 569 570 // misc functions 571 572 573 /** tests if the given service is missing 574 */ 575 576 intptr_t 577 of_test(const char *service) 578 { 579 struct { 580 const char *name; 581 intptr_t num_args; 582 intptr_t num_returns; 583 const char *service; 584 intptr_t missing; 585 } args = {"test", 1, 1, service, 0}; 586 587 if (gCallOpenFirmware(&args) == OF_FAILED) 588 return OF_FAILED; 589 590 return args.missing; 591 } 592 593 594 /** Returns the millisecond counter 595 */ 596 597 intptr_t 598 of_milliseconds(void) 599 { 600 struct { 601 const char *name; 602 intptr_t num_args; 603 intptr_t num_returns; 604 intptr_t milliseconds; 605 } args = {"milliseconds", 0, 1, 0}; 606 607 if (gCallOpenFirmware(&args) == OF_FAILED) 608 return OF_FAILED; 609 610 return args.milliseconds; 611 } 612 613 614 void 615 of_exit(void) 616 { 617 struct { 618 const char *name; 619 intptr_t num_args; 620 intptr_t num_returns; 621 } args = {"exit", 0, 0}; 622 623 gCallOpenFirmware(&args); 624 } 625 626