]> git.saurik.com Git - apple/bootx.git/blame - bootx.tproj/ci.subproj/ci.c
BootX-45.tar.gz
[apple/bootx.git] / bootx.tproj / ci.subproj / ci.c
CommitLineData
04fee52e
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * ci.c - Functions for accessing Open Firmware's Client Interface
24 *
366defd1 25 * Copyright (c) 1998-2002 Apple Computer, Inc.
04fee52e
A
26 *
27 * DRI: Josh de Cesare
28 */
29
30#include <sl.h>
31
32static ClientInterfacePtr gCIPtr;
33
34long InitCI(ClientInterfacePtr ciPtr)
35{
36 gCIPtr = ciPtr;
37
38 return 0;
39}
40
41long CallCI(CIArgs *ciArgsPtr)
42{
43 long ret;
44
45 ret = (*gCIPtr)(ciArgsPtr);
46 return ret;
47}
48
49
50// Device Tree
51
52// Peer take a phandle and returns the next peer.
53// It returns zero of there are no more peers.
54CICell Peer(CICell phandle)
55{
56 CIArgs ciArgs;
57 CICell peer_ph;
58 long ret;
59
60 ciArgs.service = "peer";
61 ciArgs.nArgs = 1;
62 ciArgs.nReturns = 1;
63 ciArgs.args.peer.phandle = phandle;
64
65 ret = CallCI(&ciArgs);
66 if (ret != 0) return kCIError;
67
68 peer_ph = ciArgs.args.peer.peerPhandle;
69
70 return peer_ph;
71}
72
73// Child take a phandle and returns the first child.
74// It returns zero of there in no child.
75CICell Child(CICell phandle)
76{
77 CIArgs ciArgs;
78 CICell child_ph;
79 long ret;
80
81 ciArgs.service = "child";
82 ciArgs.nArgs = 1;
83 ciArgs.nReturns = 1;
84 ciArgs.args.child.phandle = phandle;
85
86 ret = CallCI(&ciArgs);
87 if (ret != 0) return kCIError;
88
89 child_ph = ciArgs.args.child.childPhandle;
90
91 return child_ph;
92}
93
94// Parent take a phandle and returns the parent node.
95// It returns zero of if the phandle is the root node.
96CICell Parent(CICell phandle)
97{
98 CIArgs ciArgs;
99 CICell parent_ph;
100 long ret;
101
102 ciArgs.service = "parent";
103 ciArgs.nArgs = 1;
104 ciArgs.nReturns = 1;
105 ciArgs.args.parent.childPhandle = phandle;
106
107 ret = CallCI(&ciArgs);
108 if (ret != 0) return kCIError;
109
110 parent_ph = ciArgs.args.parent.parentPhandle;
111
112 return parent_ph;
113}
114
115// FindDevice take a device spec and returns the phandle.
116// It returns zero of if the device was not found.
117CICell FindDevice(char *devSpec)
118{
119 CIArgs ciArgs;
120 CICell phandle;
121 long ret;
122
123 ciArgs.service = "finddevice";
124 ciArgs.nArgs = 1;
125 ciArgs.nReturns = 1;
126 ciArgs.args.finddevice.devSpec = devSpec;
127
128 ret = CallCI(&ciArgs);
129 if (ret != 0) return kCIError;
130
131 phandle = ciArgs.args.finddevice.phandle;
132
133 return phandle;
134}
135
136// InstanceToPath take an ihandle, buf and buflen. Set the device path
137// to the package in buf upto buflen characters and returns the length
138// Length will be -1 if the ihandle is invalid.
139CICell InstanceToPath(CICell ihandle, char *buf, long buflen)
140{
141 CIArgs ciArgs;
142 CICell length;
143 long ret;
144
145 ciArgs.service = "instance-to-path";
146 ciArgs.nArgs = 3;
147 ciArgs.nReturns = 1;
148 ciArgs.args.instanceToPath.ihandle = ihandle;
149 ciArgs.args.instanceToPath.buf = buf;
150 ciArgs.args.instanceToPath.buflen = buflen;
151
152 ret = CallCI(&ciArgs);
153 if (ret != 0) return kCIError;
154
155 length = ciArgs.args.instanceToPath.length;
156
157 return length;
158}
159
160// InstanceToPackage take an ihandle and returns the phandle for it.
161// returns -1 if the phandle can't be found.
162CICell InstanceToPackage(CICell ihandle)
163{
164 CIArgs ciArgs;
165 CICell phandle;
166 long ret;
167
168 ciArgs.service = "instance-to-package";
169 ciArgs.nArgs = 1;
170 ciArgs.nReturns = 1;
171 ciArgs.args.instanceToPackage.ihandle = ihandle;
172
173 ret = CallCI(&ciArgs);
174 if (ret != 0) return kCIError;
175
176 phandle = ciArgs.args.instanceToPackage.phandle;
177
178 return phandle;
179}
180
181// InstanceToPackages
182
183// PackageToPath take a phandle, buf and buflen. Set the device path
184// to the package in buf upto buflen characters and returns the length
185// Length will be -1 if the phandle is invalid.
186CICell PackageToPath(CICell phandle, char *buf, long buflen)
187{
188 CIArgs ciArgs;
189 CICell length;
190 long ret;
191
192 if (gOFVersion >= kOFVersion2x) {
193 ciArgs.service = "package-to-path";
194 ciArgs.nArgs = 3;
195 ciArgs.nReturns = 1;
196 ciArgs.args.packageToPath.phandle = phandle;
197 ciArgs.args.packageToPath.buf = buf;
198 ciArgs.args.packageToPath.buflen = buflen;
199
200 ret = CallCI(&ciArgs);
201 if (ret != 0) return kCIError;
202
203 length = ciArgs.args.packageToPath.length;
204 } else {
366defd1
A
205 ret = CallMethod(3, 1, SLWordsIH, "slw_pwd", phandle,
206 (CICell)buf, buflen, &length);
04fee52e
A
207 if (ret != 0) return kCIError;
208
209 buf[length] = '\0';
210 }
211
212 return length;
213}
214
215// Canon
216
217// GetPropLen takes a phandle and prop name
218// and returns the size of the property
219// or -1 if the property is not valid.
220CICell GetPropLen(CICell phandle, char *name)
221{
222 CIArgs ciArgs;
223 CICell size;
224 long ret;
225
226 ciArgs.service = "getproplen";
227 ciArgs.nArgs = 2;
228 ciArgs.nReturns = 1;
229 ciArgs.args.getproplen.phandle = phandle;
230 ciArgs.args.getproplen.name = name;
231
232 ret = CallCI(&ciArgs);
233 if (ret != 0) return kCIError;
234
235 size = ciArgs.args.getproplen.size;
236
237 return size;
238}
239
240// GetProp takes a phandle, prop name, buffer and length
241// and copied the property value in to the buffer.
242// returns -1 if the property is not valid.
243CICell GetProp(CICell phandle, char *name, char *buf, long buflen)
244{
245 CIArgs ciArgs;
246 CICell size;
247 long ret;
248
249 ciArgs.service = "getprop";
250 ciArgs.nArgs = 4;
251 ciArgs.nReturns = 1;
252 ciArgs.args.getprop.phandle = phandle;
253 ciArgs.args.getprop.name = name;
254 ciArgs.args.getprop.buf = buf;
255 ciArgs.args.getprop.buflen = buflen;
256
257 ret = CallCI(&ciArgs);
258 if (ret != 0) return kCIError;
259
260 size = ciArgs.args.getprop.size;
261
262 return size;
263}
264
265// NextProp takes a phandle, prev name, and a buffer
266// and copied the next property name in to the buffer.
267// returns -1 if the property is not valid.
268// returns 0 if the prev was the last property.
269// returns 1 otherwise.
270CICell NextProp(CICell phandle, char *previous, char *buf)
271{
272 CIArgs ciArgs;
273 CICell flag;
274 long ret;
275
276 ciArgs.service = "nextprop";
277 ciArgs.nArgs = 3;
278 ciArgs.nReturns = 1;
279 ciArgs.args.nextprop.phandle = phandle;
280 ciArgs.args.nextprop.previous = previous;
281 ciArgs.args.nextprop.buf = buf;
282
283 ret = CallCI(&ciArgs);
284 if (ret != 0) return kCIError;
285
286 flag = ciArgs.args.nextprop.flag;
287
288 return flag;
289}
290
291// SetProp takes a phandle, prop name, buffer and length
292// and copied the buffer in to the property value.
293// returns -1 if the property could not be set or created.
294CICell SetProp(CICell phandle, char *name, char *buf, long buflen)
295{
296 CIArgs ciArgs;
297 CICell size;
298 long ret;
299
300 ciArgs.service = "setprop";
301 ciArgs.nArgs = 4;
302 ciArgs.nReturns = 1;
303 ciArgs.args.setprop.phandle = phandle;
304 ciArgs.args.setprop.name = name;
305 ciArgs.args.setprop.buf = buf;
306 ciArgs.args.setprop.buflen = buflen;
307
308 ret = CallCI(&ciArgs);
309 if (ret != 0) return kCIError;
310
311 size = ciArgs.args.setprop.size;
312
313 return size;
314}
315
316
317// Device I/O
318
319// Open takes a device specifier and returns an iHandle
320// It returns zero if the device can not be found or opened.
321CICell Open(char *devSpec)
322{
323 CIArgs ciArgs;
324 CICell ihandle;
325 long ret;
326
327 ciArgs.service = "open";
328 ciArgs.nArgs = 1;
329 ciArgs.nReturns = 1;
330 ciArgs.args.open.devSpec = devSpec;
331
332 ret = CallCI(&ciArgs);
333 if (ret != 0) return 0;
334
335 ihandle = ciArgs.args.open.ihandle;
336
337 return ihandle;
338}
339
340// Close takes an iHandle and closes the device.
341void Close(CICell ihandle)
342{
343 CIArgs ciArgs;
344
345 ciArgs.service = "close";
346 ciArgs.nArgs = 1;
347 ciArgs.nReturns = 0;
348 ciArgs.args.close.ihandle = ihandle;
349
350 CallCI(&ciArgs);
351}
352
353// Read takes an iHandle, an address and a length and return the actual
354// Length read. Returns -1 if the operaction failed.
355CICell Read(CICell ihandle, long addr, long length)
356{
357 CIArgs ciArgs;
358 long actual;
359 long ret;
360
361 ciArgs.service = "read";
362 ciArgs.nArgs = 3;
363 ciArgs.nReturns = 1;
364 ciArgs.args.read.ihandle = ihandle;
365 ciArgs.args.read.addr = addr;
366 ciArgs.args.read.length = length;
367
368 ret = CallCI(&ciArgs);
369 if (ret != 0) return kCIError;
370
371 actual = ciArgs.args.read.actual;
372
373 // Spin the wait cursor.
374 Spin();
375
376 return actual;
377}
378
379// Write takes an iHandle, an address and a length and return the actual
380// Length written. Returns -1 if the operaction failed.
381CICell Write(CICell ihandle, long addr, long length)
382{
383 CIArgs ciArgs;
384 long actual;
385 long ret;
386
387 ciArgs.service = "write";
388 ciArgs.nArgs = 3;
389 ciArgs.nReturns = 1;
390 ciArgs.args.write.ihandle = ihandle;
391 ciArgs.args.write.addr = addr;
392 ciArgs.args.write.length = length;
393
394 ret = CallCI(&ciArgs);
395 if (ret != 0) return kCIError;
396
397 actual = ciArgs.args.write.actual;
398
399 return actual;
400}
401
402// Seek takes an iHandle, and a 64 bit position
403// and moves to that address in file.
404// returns seeks result, or -1 if seek is not supported.
405CICell Seek(CICell ihandle, long long position)
406{
407 CIArgs ciArgs;
408 long ret;
409
410 ciArgs.service = "seek";
411 ciArgs.nArgs = 3;
412 ciArgs.nReturns = 1;
413 ciArgs.args.seek.ihandle = ihandle;
414 ciArgs.args.seek.pos_high = position >> 32;
415 ciArgs.args.seek.pos_low = position & 0x00000000FFFFFFFFULL;
416
417 ret = CallCI(&ciArgs);
418 if (ret != 0) return kCIError;
419
420 ret = ciArgs.args.seek.result;
421
422 return ret;
423}
424
425
426// Other Device Method Invocation
427
366defd1
A
428// Call the specified method on the given iHandle with the listed arguments.
429long CallMethod(long args, long rets, CICell iHandle, const char *method, ...)
04fee52e 430{
366defd1
A
431 va_list argList;
432 CIArgs ciArgs;
433 long ret, cnt, error = kCINoError;
04fee52e 434
366defd1 435 va_start(argList, method);
04fee52e
A
436
437 ciArgs.service = "call-method";
366defd1
A
438 ciArgs.nArgs = args + 2;
439 ciArgs.nReturns = rets + 1;
440 ciArgs.args.callMethod.iHandle = iHandle;
441 ciArgs.args.callMethod.method = method;
04fee52e 442
366defd1
A
443 for (cnt = 0; cnt < args; cnt++) {
444 ciArgs.args.callMethod.cells[args - cnt - 1] = va_arg(argList, CICell);
445 }
04fee52e
A
446
447 ret = CallCI(&ciArgs);
366defd1
A
448 if (ret != 0) error = kCIError;
449 else if (ciArgs.args.callMethod.cells[args] != 0) error = kCICatch;
04fee52e 450
366defd1
A
451 if (error == kCINoError) {
452 for (cnt = 0; cnt < rets; cnt++) {
453 *(va_arg(argList, CICell *)) =
454 ciArgs.args.callMethod.cells[args + rets - cnt];
455 }
456 }
04fee52e 457
366defd1 458 va_end(argList);
04fee52e 459
366defd1 460 return error;
04fee52e
A
461}
462
463
464// Memory
465
466// Claim takes a virt address, a size, and an alignment.
467// It return baseaddr or -1 for claim failed.
468CICell Claim(CICell virt, CICell size, CICell align)
469{
470 CIArgs ciArgs;
471 CICell baseaddr;
472 long ret;
473
474 if (gOFVersion >= kOFVersion2x) {
475 // Claim actually works, so use it.
476 ciArgs.service = "claim";
477 ciArgs.nArgs = 3;
478 ciArgs.nReturns = 1;
479 ciArgs.args.claim.virt = virt;
480 ciArgs.args.claim.size = size;
481 ciArgs.args.claim.align = align;
482
483 ret = CallCI(&ciArgs);
484 if (ret != 0) return kCIError;
485
486 baseaddr = ciArgs.args.claim.baseaddr;
487 } else {
488 // Claim does not work. Do it by hand.
489 if ((gMMUIH == 0) || (gMMUIH == 0)) return kCIError;
490
491 // Get the physical memory
366defd1 492 ret = CallMethod(3, 1, gMemoryIH, "claim", virt, size, 0, &baseaddr);
04fee52e
A
493 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
494
495 // Get the logical memory
366defd1 496 ret = CallMethod(3, 1, gMMUIH, "claim", virt, size, 0, &baseaddr);
04fee52e
A
497 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
498
499 // Map them together.
366defd1 500 ret = CallMethod(4, 0, gMMUIH, "map", virt, virt, size, 0);
04fee52e
A
501 if (ret != kCINoError) return kCIError;
502 }
503
504 return baseaddr;
505}
506
507// Release takes a virt address, a size
508void Release(CICell virt, CICell size)
509{
510 CIArgs ciArgs;
511
512 ciArgs.service = "release";
513 ciArgs.nArgs = 2;
514 ciArgs.nReturns = 0;
515 ciArgs.args.claim.virt = virt;
516 ciArgs.args.claim.size = size;
517
518 CallCI(&ciArgs);
519}
520
521
522// Control Transfer
523
524// Boot trys to boot the bootspec
525void Boot(char *bootspec)
526{
527 CIArgs ciArgs;
528
529 ciArgs.service = "boot";
530 ciArgs.nArgs = 1;
531 ciArgs.nReturns = 0;
532 ciArgs.args.boot.bootspec = bootspec;
533
534 CallCI(&ciArgs);
535}
536
537// Enter the user interface.
538// Executing the 'go' command returns to the client.
539void Enter(void)
540{
541 CIArgs ciArgs;
542
543 ciArgs.service = "enter";
544 ciArgs.nArgs = 0;
545 ciArgs.nReturns = 0;
546
547 CallCI(&ciArgs);
548}
549
550// Exit the client program.
551void Exit(void)
552{
553 CIArgs ciArgs;
554
555 ciArgs.service = "exit";
556 ciArgs.nArgs = 0;
557 ciArgs.nReturns = 0;
558
559 CallCI(&ciArgs);
560}
561
562// Clain
563
564// Quiesce stops any async tasks in Open Firmware.
565void Quiesce(void)
566{
567 CIArgs ciArgs;
568
569 ciArgs.service = "quiesce";
570 ciArgs.nArgs = 0;
571 ciArgs.nReturns = 0;
572
573 CallCI(&ciArgs);
574}
575
576
577// User Interface
578
366defd1
A
579// Interpret the given forth string with the listed arguments.
580long Interpret(long args, long rets, const char *forthString, ...)
04fee52e 581{
366defd1
A
582 va_list argList;
583 CIArgs ciArgs;
584 long ret, cnt, error = kCINoError;
04fee52e 585
366defd1 586 va_start(argList, forthString);
04fee52e
A
587
588 ciArgs.service = "interpret";
366defd1
A
589 ciArgs.nArgs = args + 1;
590 ciArgs.nReturns = rets + 1;
591 ciArgs.args.interpret.forth = forthString;
04fee52e 592
366defd1
A
593 for (cnt = 0; cnt < args; cnt++) {
594 ciArgs.args.interpret.cells[args - cnt - 1] = va_arg(argList, CICell);
595 }
04fee52e
A
596
597 ret = CallCI(&ciArgs);
366defd1
A
598 if (ret != 0) error = kCIError;
599 else if (ciArgs.args.interpret.cells[args] != 0) error = kCICatch;
04fee52e 600
366defd1
A
601 if (error == kCINoError) {
602 for (cnt = 0; cnt < rets; cnt++) {
603 *(va_arg(argList, CICell *)) =
604 ciArgs.args.interpret.cells[args + rets - cnt];
605 }
606 }
04fee52e 607
366defd1 608 va_end(argList);
04fee52e 609
366defd1 610 return error;
04fee52e 611}