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
of_init(intptr_t (* openFirmwareEntry)(void *))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
of_call_client_function(const char * method,intptr_t numArgs,intptr_t numReturns,...)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
of_interpret(const char * command,intptr_t numArgs,intptr_t numReturns,...)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
of_call_method(uint32_t handle,const char * method,intptr_t numArgs,intptr_t numReturns,...)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
of_finddevice(const char * device)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
of_child(intptr_t node)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
of_peer(intptr_t node)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
of_parent(intptr_t node)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
of_instance_to_path(uint32_t instance,char * pathBuffer,intptr_t bufferSize)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
of_instance_to_package(uint32_t instance)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
of_getprop(intptr_t package,const char * property,void * buffer,intptr_t bufferSize)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
of_setprop(intptr_t package,const char * property,const void * buffer,intptr_t bufferSize)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
of_getproplen(intptr_t package,const char * property)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
of_nextprop(intptr_t package,const char * previousProperty,char * nextProperty)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
of_package_to_path(intptr_t package,char * pathBuffer,intptr_t bufferSize)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
of_open(const char * nodeName)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
of_close(intptr_t handle)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
of_read(intptr_t handle,void * buffer,intptr_t bufferSize)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
of_write(intptr_t handle,const void * buffer,intptr_t bufferSize)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
of_seek(intptr_t handle,off_t pos)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
of_blocks(intptr_t handle)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
of_block_size(intptr_t handle)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
of_release(void * virtualAddress,intptr_t size)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 *
of_claim(void * virtualAddress,intptr_t size,intptr_t align)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
of_test(const char * service)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
of_milliseconds(void)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
of_exit(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