]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/ci.subproj/ci.c
BootX-81.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 * 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 *
25 * Copyright (c) 1998-2002 Apple Computer, Inc.
26 *
27 * DRI: Josh de Cesare
28 */
29
30 #include <sl.h>
31
32 static ClientInterfacePtr gCIPtr;
33
34 long InitCI(ClientInterfacePtr ciPtr)
35 {
36 gCIPtr = ciPtr;
37
38 return 0;
39 }
40
41 long 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.
54 CICell 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.
75 CICell 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.
96 CICell 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.
117 CICell 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.
139 CICell 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.
162 CICell 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.
186 CICell 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 {
205 ret = CallMethod(3, 1, SLWordsIH, "slw_pwd", phandle,
206 (CICell)buf, buflen, &length);
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.
220 CICell 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.
243 CICell 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.
270 CICell 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.
294 CICell 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.
321 CICell Open(char *devSpec)
322 {
323 CIArgs ciArgs;
324 CICell ihandle;
325 long ret;
326
327 // intercept software RAID's virtual devices
328 if(isRAIDPath(devSpec))
329 return (CICell)RAIDOpen(devSpec);
330
331 ciArgs.service = "open";
332 ciArgs.nArgs = 1;
333 ciArgs.nReturns = 1;
334 ciArgs.args.open.devSpec = devSpec;
335
336 ret = CallCI(&ciArgs);
337 if (ret != 0) return 0;
338
339 ihandle = ciArgs.args.open.ihandle;
340
341 return ihandle;
342 }
343
344 // Close takes an iHandle and closes the device.
345 void Close(CICell ihandle)
346 {
347 CIArgs ciArgs;
348
349 if(isRAIDDevice((void*)ihandle)) {
350 RAIDClose((RAIDDevicePtr)ihandle);
351 return;
352 }
353
354 ciArgs.service = "close";
355 ciArgs.nArgs = 1;
356 ciArgs.nReturns = 0;
357 ciArgs.args.close.ihandle = ihandle;
358
359 CallCI(&ciArgs);
360 }
361
362 // Read takes an iHandle, an address and a length and return the actual
363 // Length read. Returns -1 if the operaction failed.
364 CICell Read(CICell ihandle, long addr, long length)
365 {
366 CIArgs ciArgs;
367 long actual;
368 long ret;
369
370 if(isRAIDDevice((void*)ihandle))
371 return RAIDRead((RAIDDevicePtr)ihandle, addr, length, -1);
372
373 ciArgs.service = "read";
374 ciArgs.nArgs = 3;
375 ciArgs.nReturns = 1;
376 ciArgs.args.read.ihandle = ihandle;
377 ciArgs.args.read.addr = addr;
378 ciArgs.args.read.length = length;
379
380 ret = CallCI(&ciArgs);
381 if (ret != 0) return kCIError;
382
383 actual = ciArgs.args.read.actual;
384
385 // Spin the wait cursor.
386 Spin();
387
388 return actual;
389 }
390
391 // Write takes an iHandle, an address and a length and return the actual
392 // Length written. Returns -1 if the operaction failed.
393 CICell Write(CICell ihandle, long addr, long length)
394 {
395 CIArgs ciArgs;
396 long actual;
397 long ret;
398
399 if(isRAIDDevice((void*)ihandle)) {
400 printf("who's trying to write to RAID?!\n");
401 return -1;
402 }
403
404 ciArgs.service = "write";
405 ciArgs.nArgs = 3;
406 ciArgs.nReturns = 1;
407 ciArgs.args.write.ihandle = ihandle;
408 ciArgs.args.write.addr = addr;
409 ciArgs.args.write.length = length;
410
411 ret = CallCI(&ciArgs);
412 if (ret != 0) return kCIError;
413
414 actual = ciArgs.args.write.actual;
415
416 return actual;
417 }
418
419 // Seek takes an iHandle, and a 64 bit position
420 // and moves to that address in file.
421 // returns seeks result, or -1 if seek is not supported.
422 CICell Seek(CICell ihandle, long long position)
423 {
424 CIArgs ciArgs;
425 long ret;
426
427 if(isRAIDDevice((void*)ihandle))
428 return RAIDSeek((RAIDDevicePtr)ihandle, position);
429
430 ciArgs.service = "seek";
431 ciArgs.nArgs = 3;
432 ciArgs.nReturns = 1;
433 ciArgs.args.seek.ihandle = ihandle;
434 ciArgs.args.seek.pos_high = position >> 32;
435 ciArgs.args.seek.pos_low = position & 0x00000000FFFFFFFFULL;
436
437 ret = CallCI(&ciArgs);
438 if (ret != 0) return kCIError;
439
440 ret = ciArgs.args.seek.result;
441
442 return ret;
443 }
444
445
446 // Other Device Method Invocation
447
448 // Call the specified method on the given iHandle with the listed arguments.
449 long CallMethod(long args, long rets, CICell iHandle, const char *method, ...)
450 {
451 va_list argList;
452 CIArgs ciArgs;
453 long ret, cnt, error = kCINoError;
454
455 va_start(argList, method);
456
457 ciArgs.service = "call-method";
458 ciArgs.nArgs = args + 2;
459 ciArgs.nReturns = rets + 1;
460 ciArgs.args.callMethod.iHandle = iHandle;
461 ciArgs.args.callMethod.method = method;
462
463 for (cnt = 0; cnt < args; cnt++) {
464 ciArgs.args.callMethod.cells[args - cnt - 1] = va_arg(argList, CICell);
465 }
466
467 ret = CallCI(&ciArgs);
468 if (ret != 0) error = kCIError;
469 else if (ciArgs.args.callMethod.cells[args] != 0) error = kCICatch;
470
471 if (error == kCINoError) {
472 for (cnt = 0; cnt < rets; cnt++) {
473 *(va_arg(argList, CICell *)) =
474 ciArgs.args.callMethod.cells[args + rets - cnt];
475 }
476 }
477
478 va_end(argList);
479
480 return error;
481 }
482
483
484 // Memory
485
486 // Claim takes a virt address, a size, and an alignment.
487 // It return baseaddr or -1 for claim failed.
488 CICell Claim(CICell virt, CICell size, CICell align)
489 {
490 CIArgs ciArgs;
491 CICell baseaddr;
492 long ret;
493
494 if (gOFVersion >= kOFVersion2x) {
495 // Claim actually works, so use it.
496 ciArgs.service = "claim";
497 ciArgs.nArgs = 3;
498 ciArgs.nReturns = 1;
499 ciArgs.args.claim.virt = virt;
500 ciArgs.args.claim.size = size;
501 ciArgs.args.claim.align = align;
502
503 ret = CallCI(&ciArgs);
504 if (ret != 0) return kCIError;
505
506 baseaddr = ciArgs.args.claim.baseaddr;
507 } else {
508 // Claim does not work. Do it by hand.
509 if ((gMMUIH == 0) || (gMMUIH == 0)) return kCIError;
510
511 // Get the physical memory
512 ret = CallMethod(3, 1, gMemoryIH, "claim", virt, size, 0, &baseaddr);
513 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
514
515 // Get the logical memory
516 ret = CallMethod(3, 1, gMMUIH, "claim", virt, size, 0, &baseaddr);
517 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
518
519 // Map them together.
520 ret = CallMethod(4, 0, gMMUIH, "map", virt, virt, size, 0);
521 if (ret != kCINoError) return kCIError;
522 }
523
524 return baseaddr;
525 }
526
527 // Release takes a virt address, a size
528 void Release(CICell virt, CICell size)
529 {
530 CIArgs ciArgs;
531
532 ciArgs.service = "release";
533 ciArgs.nArgs = 2;
534 ciArgs.nReturns = 0;
535 ciArgs.args.claim.virt = virt;
536 ciArgs.args.claim.size = size;
537
538 CallCI(&ciArgs);
539 }
540
541
542 // Control Transfer
543
544 // Boot trys to boot the bootspec
545 void Boot(char *bootspec)
546 {
547 CIArgs ciArgs;
548
549 ciArgs.service = "boot";
550 ciArgs.nArgs = 1;
551 ciArgs.nReturns = 0;
552 ciArgs.args.boot.bootspec = bootspec;
553
554 CallCI(&ciArgs);
555 }
556
557 // Enter the user interface.
558 // Executing the 'go' command returns to the client.
559 void Enter(void)
560 {
561 CIArgs ciArgs;
562
563 ciArgs.service = "enter";
564 ciArgs.nArgs = 0;
565 ciArgs.nReturns = 0;
566
567 CallCI(&ciArgs);
568 }
569
570 // Exit the client program.
571 void Exit(void)
572 {
573 CIArgs ciArgs;
574
575 ciArgs.service = "exit";
576 ciArgs.nArgs = 0;
577 ciArgs.nReturns = 0;
578
579 CallCI(&ciArgs);
580 }
581
582 // Clain
583
584 // Quiesce stops any async tasks in Open Firmware.
585 void Quiesce(void)
586 {
587 CIArgs ciArgs;
588
589 ciArgs.service = "quiesce";
590 ciArgs.nArgs = 0;
591 ciArgs.nReturns = 0;
592
593 CallCI(&ciArgs);
594 }
595
596
597 // User Interface
598
599 // Interpret the given forth string with the listed arguments.
600 long Interpret(long args, long rets, const char *forthString, ...)
601 {
602 va_list argList;
603 CIArgs ciArgs;
604 long ret, cnt, error = kCINoError;
605
606 va_start(argList, forthString);
607
608 ciArgs.service = "interpret";
609 ciArgs.nArgs = args + 1;
610 ciArgs.nReturns = rets + 1;
611 ciArgs.args.interpret.forth = forthString;
612
613 for (cnt = 0; cnt < args; cnt++) {
614 ciArgs.args.interpret.cells[args - cnt - 1] = va_arg(argList, CICell);
615 }
616
617 ret = CallCI(&ciArgs);
618 if (ret != 0) error = kCIError;
619 else if (ciArgs.args.interpret.cells[args] != 0) error = kCICatch;
620
621 if (error == kCINoError) {
622 for (cnt = 0; cnt < rets; cnt++) {
623 *(va_arg(argList, CICell *)) =
624 ciArgs.args.interpret.cells[args + rets - cnt];
625 }
626 }
627
628 va_end(argList);
629
630 return error;
631 }