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
13static intptr_t (*gCallOpenFirmware)(void *) = 0;
14intptr_t gChosen;
15
16
17status_t
18of_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
30intptr_t
31of_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
74intptr_t
75of_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
124intptr_t
125of_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
176intptr_t
177of_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
197intptr_t
198of_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
218intptr_t
219of_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
239intptr_t
240of_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
257intptr_t
258of_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
277intptr_t
278of_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
295intptr_t
296of_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
316intptr_t
317of_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
338intptr_t
339of_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
357intptr_t
358of_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
377intptr_t
378of_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
400intptr_t
401of_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
418void
419of_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
432intptr_t
433of_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
452intptr_t
453of_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
472intptr_t
473of_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
496intptr_t
497of_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
514intptr_t
515of_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
535intptr_t
536of_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
550void *
551of_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
576intptr_t
577of_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
597intptr_t
598of_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
614void
615of_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