98217029f458dcef3a5b227b300762ff14cf8c52
[grub.git] / grub-core / kern / ieee1275 / ieee1275.c
1 /* of.c - Access the Open Firmware client interface.  */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 2003,2004,2005,2007,2008,2009  Free Software Foundation, Inc.
5  *
6  *  GRUB is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  GRUB is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <grub/ieee1275/ieee1275.h>
21 #include <grub/types.h>
22
23 #define IEEE1275_PHANDLE_INVALID  ((grub_ieee1275_cell_t) -1)
24 #define IEEE1275_IHANDLE_INVALID  ((grub_ieee1275_cell_t) 0)
25 #define IEEE1275_CELL_INVALID     ((grub_ieee1275_cell_t) -1)
26
27 \f
28
29 int
30 grub_ieee1275_finddevice (const char *name, grub_ieee1275_phandle_t *phandlep)
31 {
32   struct find_device_args
33   {
34     struct grub_ieee1275_common_hdr common;
35     grub_ieee1275_cell_t device;
36     grub_ieee1275_cell_t phandle;
37   }
38   args;
39
40   INIT_IEEE1275_COMMON (&args.common, "finddevice", 1, 1);
41   args.device = (grub_ieee1275_cell_t) name;
42
43   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
44     return -1;
45   *phandlep = args.phandle;
46   if (args.phandle == IEEE1275_PHANDLE_INVALID)
47     return -1;
48   return 0;
49 }
50
51 int
52 grub_ieee1275_get_property (grub_ieee1275_phandle_t phandle,
53                             const char *property, void *buf,
54                             grub_size_t size, grub_ssize_t *actual)
55 {
56   struct get_property_args
57   {
58     struct grub_ieee1275_common_hdr common;
59     grub_ieee1275_cell_t phandle;
60     grub_ieee1275_cell_t prop;
61     grub_ieee1275_cell_t buf;
62     grub_ieee1275_cell_t buflen;
63     grub_ieee1275_cell_t size;
64   }
65   args;
66
67   INIT_IEEE1275_COMMON (&args.common, "getprop", 4, 1);
68   args.phandle = phandle;
69   args.prop = (grub_ieee1275_cell_t) property;
70   args.buf = (grub_ieee1275_cell_t) buf;
71   args.buflen = (grub_ieee1275_cell_t) size;
72
73   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
74     return -1;
75   if (actual)
76     *actual = (grub_ssize_t) args.size;
77   if (args.size == IEEE1275_CELL_INVALID)
78     return -1;
79   return 0;
80 }
81
82 int
83 grub_ieee1275_get_integer_property (grub_ieee1275_phandle_t phandle,
84                                     const char *property, grub_uint32_t *buf,
85                                     grub_size_t size, grub_ssize_t *actual)
86 {
87   int ret;
88   ret = grub_ieee1275_get_property (phandle, property, (void *) buf, size, actual);
89 #ifndef GRUB_CPU_WORDS_BIGENDIAN
90   /* Integer properties are always in big endian.  */
91   if (ret == 0)
92     {
93       unsigned int i;
94       size /= sizeof (grub_uint32_t);
95       for (i = 0; i < size; i++)
96         buf[i] = grub_be_to_cpu32 (buf[i]);
97     }
98 #endif
99   return ret;
100 }
101
102 int
103 grub_ieee1275_next_property (grub_ieee1275_phandle_t phandle, char *prev_prop,
104                              char *prop)
105 {
106   struct get_property_args
107   {
108     struct grub_ieee1275_common_hdr common;
109     grub_ieee1275_cell_t phandle;
110     grub_ieee1275_cell_t prev_prop;
111     grub_ieee1275_cell_t next_prop;
112     grub_ieee1275_cell_t flags;
113   }
114   args;
115
116   INIT_IEEE1275_COMMON (&args.common, "nextprop", 3, 1);
117   args.phandle = phandle;
118   args.prev_prop = (grub_ieee1275_cell_t) prev_prop;
119   args.next_prop = (grub_ieee1275_cell_t) prop;
120   args.flags = (grub_ieee1275_cell_t) -1;
121
122   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
123     return -1;
124   return (int) args.flags;
125 }
126
127 int
128 grub_ieee1275_get_property_length (grub_ieee1275_phandle_t phandle,
129                                    const char *prop, grub_ssize_t *length)
130 {
131   struct get_property_args
132   {
133     struct grub_ieee1275_common_hdr common;
134     grub_ieee1275_cell_t phandle;
135     grub_ieee1275_cell_t prop;
136     grub_ieee1275_cell_t length;
137   }
138   args;
139
140   INIT_IEEE1275_COMMON (&args.common, "getproplen", 2, 1);
141   args.phandle = phandle;
142   args.prop = (grub_ieee1275_cell_t) prop;
143   args.length = (grub_ieee1275_cell_t) -1;
144
145   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
146     return -1;
147   *length = args.length;
148   if (args.length == IEEE1275_CELL_INVALID)
149     return -1;
150   return 0;
151 }
152
153 int
154 grub_ieee1275_instance_to_package (grub_ieee1275_ihandle_t ihandle,
155                                    grub_ieee1275_phandle_t *phandlep)
156 {
157   struct instance_to_package_args
158   {
159     struct grub_ieee1275_common_hdr common;
160     grub_ieee1275_cell_t ihandle;
161     grub_ieee1275_cell_t phandle;
162   }
163   args;
164
165   INIT_IEEE1275_COMMON (&args.common, "instance-to-package", 1, 1);
166   args.ihandle = ihandle;
167
168   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
169     return -1;
170   *phandlep = args.phandle;
171   if (args.phandle == IEEE1275_PHANDLE_INVALID)
172     return -1;
173   return 0;
174 }
175
176 int
177 grub_ieee1275_package_to_path (grub_ieee1275_phandle_t phandle,
178                                char *path, grub_size_t len,
179                                grub_ssize_t *actual)
180 {
181   struct instance_to_package_args
182   {
183     struct grub_ieee1275_common_hdr common;
184     grub_ieee1275_cell_t phandle;
185     grub_ieee1275_cell_t buf;
186     grub_ieee1275_cell_t buflen;
187     grub_ieee1275_cell_t actual;
188   }
189   args;
190
191   INIT_IEEE1275_COMMON (&args.common, "package-to-path", 3, 1);
192   args.phandle = phandle;
193   args.buf = (grub_ieee1275_cell_t) path;
194   args.buflen = (grub_ieee1275_cell_t) len;
195
196   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
197     return -1;
198   if (actual)
199     *actual = args.actual;
200   if (args.actual == IEEE1275_CELL_INVALID)
201     return -1;
202   return 0;
203 }
204
205 int
206 grub_ieee1275_instance_to_path (grub_ieee1275_ihandle_t ihandle,
207                                 char *path, grub_size_t len,
208                                 grub_ssize_t *actual)
209 {
210   struct instance_to_path_args
211   {
212     struct grub_ieee1275_common_hdr common;
213     grub_ieee1275_cell_t ihandle;
214     grub_ieee1275_cell_t buf;
215     grub_ieee1275_cell_t buflen;
216     grub_ieee1275_cell_t actual;
217   }
218   args;
219
220   INIT_IEEE1275_COMMON (&args.common, "instance-to-path", 3, 1);
221   args.ihandle = ihandle;
222   args.buf = (grub_ieee1275_cell_t) path;
223   args.buflen = (grub_ieee1275_cell_t) len;
224
225   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
226     return -1;
227   if (actual)
228     *actual = args.actual;
229   if (args.actual == IEEE1275_CELL_INVALID)
230     return -1;
231   return 0;
232 }
233
234 int
235 grub_ieee1275_write (grub_ieee1275_ihandle_t ihandle, const void *buffer,
236                      grub_size_t len, grub_ssize_t *actualp)
237 {
238   struct write_args
239   {
240     struct grub_ieee1275_common_hdr common;
241     grub_ieee1275_cell_t ihandle;
242     grub_ieee1275_cell_t buf;
243     grub_ieee1275_cell_t len;
244     grub_ieee1275_cell_t actual;
245   }
246   args;
247
248   INIT_IEEE1275_COMMON (&args.common, "write", 3, 1);
249   args.ihandle = ihandle;
250   args.buf = (grub_ieee1275_cell_t) buffer;
251   args.len = (grub_ieee1275_cell_t) len;
252
253   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
254     return -1;
255   if (actualp)
256     *actualp = args.actual;
257   return 0;
258 }
259
260 int
261 grub_ieee1275_read (grub_ieee1275_ihandle_t ihandle, void *buffer,
262                     grub_size_t len, grub_ssize_t *actualp)
263 {
264   struct write_args
265   {
266     struct grub_ieee1275_common_hdr common;
267     grub_ieee1275_cell_t ihandle;
268     grub_ieee1275_cell_t buf;
269     grub_ieee1275_cell_t len;
270     grub_ieee1275_cell_t actual;
271   }
272   args;
273
274   INIT_IEEE1275_COMMON (&args.common, "read", 3, 1);
275   args.ihandle = ihandle;
276   args.buf = (grub_ieee1275_cell_t) buffer;
277   args.len = (grub_ieee1275_cell_t) len;
278
279   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
280     return -1;
281   if (actualp)
282     *actualp = args.actual;
283   return 0;
284 }
285
286 int
287 grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, grub_disk_addr_t pos,
288                     grub_ssize_t *result)
289 {
290   struct write_args
291   {
292     struct grub_ieee1275_common_hdr common;
293     grub_ieee1275_cell_t ihandle;
294     grub_ieee1275_cell_t pos_hi;
295     grub_ieee1275_cell_t pos_lo;
296     grub_ieee1275_cell_t result;
297   }
298   args;
299
300   INIT_IEEE1275_COMMON (&args.common, "seek", 3, 1);
301   args.ihandle = ihandle;
302   /* To prevent stupid gcc warning.  */
303 #if GRUB_IEEE1275_CELL_SIZEOF >= 8
304   args.pos_hi = 0;
305   args.pos_lo = pos;
306 #else
307   args.pos_hi = (grub_ieee1275_cell_t) (pos >> (8 * GRUB_IEEE1275_CELL_SIZEOF));
308   args.pos_lo = (grub_ieee1275_cell_t) 
309     (pos & ((1ULL << (8 * GRUB_IEEE1275_CELL_SIZEOF)) - 1));
310 #endif
311
312   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
313     return -1;
314
315   if (result)
316     *result = args.result;
317   return 0;
318 }
319
320 int
321 grub_ieee1275_peer (grub_ieee1275_phandle_t node,
322                     grub_ieee1275_phandle_t *result)
323 {
324   struct peer_args
325   {
326     struct grub_ieee1275_common_hdr common;
327     grub_ieee1275_cell_t node;
328     grub_ieee1275_cell_t result;
329   }
330   args;
331
332   INIT_IEEE1275_COMMON (&args.common, "peer", 1, 1);
333   args.node = node;
334
335   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
336     return -1;
337   *result = args.result;
338   if (args.result == 0)
339     return -1;
340   return 0;
341 }
342
343 int
344 grub_ieee1275_child (grub_ieee1275_phandle_t node,
345                      grub_ieee1275_phandle_t *result)
346 {
347   struct child_args
348   {
349     struct grub_ieee1275_common_hdr common;
350     grub_ieee1275_cell_t node;
351     grub_ieee1275_cell_t result;
352   }
353   args;
354
355   INIT_IEEE1275_COMMON (&args.common, "child", 1, 1);
356   args.node = node;
357   args.result = IEEE1275_PHANDLE_INVALID;
358
359   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
360     return -1;
361   *result = args.result;
362   if (args.result == 0)
363     return -1;
364   return 0;
365 }
366
367 int
368 grub_ieee1275_parent (grub_ieee1275_phandle_t node,
369                       grub_ieee1275_phandle_t *result)
370 {
371   struct parent_args
372   {
373     struct grub_ieee1275_common_hdr common;
374     grub_ieee1275_cell_t node;
375     grub_ieee1275_cell_t result;
376   }
377   args;
378
379   INIT_IEEE1275_COMMON (&args.common, "parent", 1, 1);
380   args.node = node;
381   args.result = IEEE1275_PHANDLE_INVALID;
382
383   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
384     return -1;
385   *result = args.result;
386   return 0;
387 }
388
389 int
390 grub_ieee1275_interpret (const char *command, grub_ieee1275_cell_t *catch)
391 {
392   struct enter_args
393   {
394     struct grub_ieee1275_common_hdr common;
395     grub_ieee1275_cell_t command;
396     grub_ieee1275_cell_t catch;
397   }
398   args;
399
400   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
401     return -1;
402
403   INIT_IEEE1275_COMMON (&args.common, "interpret", 1, 1);
404   args.command = (grub_ieee1275_cell_t) command;
405
406   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
407     return -1;
408   if (catch)
409     *catch = args.catch;
410   return 0;
411 }
412
413 int
414 grub_ieee1275_enter (void)
415 {
416   struct enter_args
417   {
418     struct grub_ieee1275_common_hdr common;
419   }
420   args;
421
422   INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0);
423
424   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
425     return -1;
426   return 0;
427 }
428
429 void
430 grub_ieee1275_exit (void)
431 {
432   struct exit_args
433   {
434     struct grub_ieee1275_common_hdr common;
435   }
436   args;
437
438   INIT_IEEE1275_COMMON (&args.common, "exit", 0, 0);
439
440   IEEE1275_CALL_ENTRY_FN (&args);
441   for (;;) ;
442 }
443
444 int
445 grub_ieee1275_open (const char *path, grub_ieee1275_ihandle_t *result)
446 {
447   struct open_args
448   {
449     struct grub_ieee1275_common_hdr common;
450     grub_ieee1275_cell_t path;
451     grub_ieee1275_cell_t result;
452   }
453   args;
454
455   INIT_IEEE1275_COMMON (&args.common, "open", 1, 1);
456   args.path = (grub_ieee1275_cell_t) path;
457
458   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
459     return -1;
460   *result = args.result;
461   if (args.result == IEEE1275_IHANDLE_INVALID)
462     return -1;
463   return 0;
464 }
465
466 int
467 grub_ieee1275_close (grub_ieee1275_ihandle_t ihandle)
468 {
469   struct close_args
470   {
471     struct grub_ieee1275_common_hdr common;
472     grub_ieee1275_cell_t ihandle;
473   }
474   args;
475
476   INIT_IEEE1275_COMMON (&args.common, "close", 1, 0);
477   args.ihandle = ihandle;
478
479   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
480     return -1;
481
482   return 0;
483 }
484
485 int
486 grub_ieee1275_claim (grub_addr_t addr, grub_size_t size, unsigned int align,
487                      grub_addr_t *result)
488 {
489   struct claim_args
490   {
491     struct grub_ieee1275_common_hdr common;
492     grub_ieee1275_cell_t addr;
493     grub_ieee1275_cell_t size;
494     grub_ieee1275_cell_t align;
495     grub_ieee1275_cell_t base;
496   }
497   args;
498
499   INIT_IEEE1275_COMMON (&args.common, "claim", 3, 1);
500   args.addr = (grub_ieee1275_cell_t) addr;
501   args.size = (grub_ieee1275_cell_t) size;
502   args.align = (grub_ieee1275_cell_t) align;
503
504   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
505     return -1;
506   if (result)
507     *result = args.base;
508   if (args.base == IEEE1275_CELL_INVALID)
509     return -1;
510   return 0;
511 }
512
513 int
514 grub_ieee1275_release (grub_addr_t addr, grub_size_t size)
515 {
516  struct release_args
517  {
518     struct grub_ieee1275_common_hdr common;
519     grub_ieee1275_cell_t addr;
520     grub_ieee1275_cell_t size;
521  }
522  args;
523
524   INIT_IEEE1275_COMMON (&args.common, "release", 2, 0);
525   args.addr = addr;
526   args.size = size;
527
528   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
529     return -1;
530   return 0;
531 }
532
533 int
534 grub_ieee1275_set_property (grub_ieee1275_phandle_t phandle,
535                             const char *propname, const void *buf,
536                             grub_size_t size, grub_ssize_t *actual)
537 {
538   struct set_property_args
539   {
540     struct grub_ieee1275_common_hdr common;
541     grub_ieee1275_cell_t phandle;
542     grub_ieee1275_cell_t propname;
543     grub_ieee1275_cell_t buf;
544     grub_ieee1275_cell_t size;
545     grub_ieee1275_cell_t actual;
546   }
547   args;
548
549   INIT_IEEE1275_COMMON (&args.common, "setprop", 4, 1);
550   args.size = (grub_ieee1275_cell_t) size;
551   args.buf = (grub_ieee1275_cell_t) buf;
552   args.propname = (grub_ieee1275_cell_t) propname;
553   args.phandle = (grub_ieee1275_cell_t) phandle;
554
555   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
556     return -1;
557   *actual = args.actual;
558   if ((args.actual == IEEE1275_CELL_INVALID) || (args.actual != args.size))
559     return -1;
560   return 0;
561 }
562
563 int
564 grub_ieee1275_set_color (grub_ieee1275_ihandle_t ihandle,
565                          int index, int r, int g, int b)
566 {
567   struct set_color_args
568   {
569     struct grub_ieee1275_common_hdr common;
570     grub_ieee1275_cell_t method;
571     grub_ieee1275_cell_t ihandle;
572     grub_ieee1275_cell_t index;
573     grub_ieee1275_cell_t b;
574     grub_ieee1275_cell_t g;
575     grub_ieee1275_cell_t r;
576     grub_ieee1275_cell_t catch_result;
577   }
578   args;
579
580   INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
581   args.method = (grub_ieee1275_cell_t) "color!";
582   args.ihandle = ihandle;
583   args.index = index;
584   args.r = r;
585   args.g = g;
586   args.b = b;
587
588   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
589     return -1;
590   return args.catch_result;
591 }
592
593 int
594 grub_ieee1275_milliseconds (grub_uint32_t *msecs)
595 {
596   struct milliseconds_args
597   {
598     struct grub_ieee1275_common_hdr common;
599     grub_ieee1275_cell_t msecs;
600   }
601   args;
602
603   INIT_IEEE1275_COMMON (&args.common, "milliseconds", 0, 1);
604
605   if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
606     return -1;
607   *msecs = args.msecs;
608   return 0;
609 }