]> git.saurik.com Git - apple/bootx.git/blame - bootx.tproj/ci.subproj/ci.c
BootX-74.1.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 *
8be739c0
A
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.
04fee52e 11 *
8be739c0
A
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
04fee52e
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
8be739c0
A
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.
04fee52e
A
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
8be739c0
A
327 // intercept software RAID's virtual devices
328 if(isRAIDPath(devSpec))
329 return (CICell)RAIDOpen(devSpec);
330
04fee52e
A
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.
345void Close(CICell ihandle)
346{
347 CIArgs ciArgs;
348
8be739c0
A
349 if(isRAIDDevice((void*)ihandle)) {
350 RAIDClose((RAIDDevicePtr)ihandle);
351 return;
352 }
353
04fee52e
A
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.
364CICell Read(CICell ihandle, long addr, long length)
365{
366 CIArgs ciArgs;
367 long actual;
368 long ret;
369
8be739c0
A
370 if(isRAIDDevice((void*)ihandle))
371 return RAIDRead((RAIDDevicePtr)ihandle, addr, length, -1);
372
04fee52e
A
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.
393CICell Write(CICell ihandle, long addr, long length)
394{
395 CIArgs ciArgs;
396 long actual;
397 long ret;
8be739c0
A
398
399 if(isRAIDDevice((void*)ihandle)) {
400 printf("who's trying to write to RAID?!\n");
401 return -1;
402 }
04fee52e
A
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.
422CICell Seek(CICell ihandle, long long position)
423{
424 CIArgs ciArgs;
425 long ret;
426
8be739c0
A
427 if(isRAIDDevice((void*)ihandle))
428 return RAIDSeek((RAIDDevicePtr)ihandle, position);
429
04fee52e
A
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
366defd1
A
448// Call the specified method on the given iHandle with the listed arguments.
449long CallMethod(long args, long rets, CICell iHandle, const char *method, ...)
04fee52e 450{
366defd1
A
451 va_list argList;
452 CIArgs ciArgs;
453 long ret, cnt, error = kCINoError;
04fee52e 454
366defd1 455 va_start(argList, method);
04fee52e
A
456
457 ciArgs.service = "call-method";
366defd1
A
458 ciArgs.nArgs = args + 2;
459 ciArgs.nReturns = rets + 1;
460 ciArgs.args.callMethod.iHandle = iHandle;
461 ciArgs.args.callMethod.method = method;
04fee52e 462
366defd1
A
463 for (cnt = 0; cnt < args; cnt++) {
464 ciArgs.args.callMethod.cells[args - cnt - 1] = va_arg(argList, CICell);
465 }
04fee52e
A
466
467 ret = CallCI(&ciArgs);
366defd1
A
468 if (ret != 0) error = kCIError;
469 else if (ciArgs.args.callMethod.cells[args] != 0) error = kCICatch;
04fee52e 470
366defd1
A
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 }
04fee52e 477
366defd1 478 va_end(argList);
04fee52e 479
366defd1 480 return error;
04fee52e
A
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.
488CICell 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
366defd1 512 ret = CallMethod(3, 1, gMemoryIH, "claim", virt, size, 0, &baseaddr);
04fee52e
A
513 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
514
515 // Get the logical memory
366defd1 516 ret = CallMethod(3, 1, gMMUIH, "claim", virt, size, 0, &baseaddr);
04fee52e
A
517 if ((ret != kCINoError) || (virt != baseaddr)) return kCIError;
518
519 // Map them together.
366defd1 520 ret = CallMethod(4, 0, gMMUIH, "map", virt, virt, size, 0);
04fee52e
A
521 if (ret != kCINoError) return kCIError;
522 }
523
524 return baseaddr;
525}
526
527// Release takes a virt address, a size
528void 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
545void 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.
559void 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.
571void 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.
585void 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
366defd1
A
599// Interpret the given forth string with the listed arguments.
600long Interpret(long args, long rets, const char *forthString, ...)
04fee52e 601{
366defd1
A
602 va_list argList;
603 CIArgs ciArgs;
604 long ret, cnt, error = kCINoError;
04fee52e 605
366defd1 606 va_start(argList, forthString);
04fee52e
A
607
608 ciArgs.service = "interpret";
366defd1
A
609 ciArgs.nArgs = args + 1;
610 ciArgs.nReturns = rets + 1;
611 ciArgs.args.interpret.forth = forthString;
04fee52e 612
366defd1
A
613 for (cnt = 0; cnt < args; cnt++) {
614 ciArgs.args.interpret.cells[args - cnt - 1] = va_arg(argList, CICell);
615 }
04fee52e
A
616
617 ret = CallCI(&ciArgs);
366defd1
A
618 if (ret != 0) error = kCIError;
619 else if (ciArgs.args.interpret.cells[args] != 0) error = kCICatch;
04fee52e 620
366defd1
A
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 }
04fee52e 627
366defd1 628 va_end(argList);
04fee52e 629
366defd1 630 return error;
04fee52e 631}