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