xref: /haiku/src/system/kernel/platform/openfirmware/openfirmware.cpp (revision 7eab6b486ebadb54ca3c306601f4b04dd92359fa)
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