1 /* openfw.c -- Open firmware support functions. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/types.h>
22 #include <grub/misc.h>
24 #include <grub/machine/kernel.h>
25 #include <grub/ieee1275/ieee1275.h>
27 enum grub_ieee1275_parse_type
33 /* Walk children of 'devpath', calling hook for each. */
35 grub_children_iterate (char *devpath
,
36 int (*hook
) (struct grub_ieee1275_devalias
*alias
))
38 grub_ieee1275_phandle_t dev
;
39 grub_ieee1275_phandle_t child
;
40 char *childtype
, *childpath
;
41 char *childname
, *fullname
;
44 if (grub_ieee1275_finddevice (devpath
, &dev
))
47 if (grub_ieee1275_child (dev
, &child
))
50 childtype
= grub_malloc (IEEE1275_MAX_PROP_LEN
);
53 childpath
= grub_malloc (IEEE1275_MAX_PATH_LEN
);
56 grub_free (childtype
);
59 childname
= grub_malloc (IEEE1275_MAX_PROP_LEN
);
62 grub_free (childpath
);
63 grub_free (childtype
);
66 fullname
= grub_malloc (IEEE1275_MAX_PATH_LEN
);
69 grub_free (childname
);
70 grub_free (childpath
);
71 grub_free (childtype
);
77 struct grub_ieee1275_devalias alias
;
80 if (grub_ieee1275_get_property (child
, "device_type", childtype
,
81 IEEE1275_MAX_PROP_LEN
, &actual
))
84 if (grub_ieee1275_package_to_path (child
, childpath
,
85 IEEE1275_MAX_PATH_LEN
, &actual
))
88 if (grub_ieee1275_get_property (child
, "name", childname
,
89 IEEE1275_MAX_PROP_LEN
, &actual
))
92 grub_sprintf (fullname
, "%s/%s", devpath
, childname
);
94 alias
.type
= childtype
;
95 alias
.path
= childpath
;
96 alias
.name
= fullname
;
101 while (grub_ieee1275_peer (child
, &child
));
103 grub_free (fullname
);
104 grub_free (childname
);
105 grub_free (childpath
);
106 grub_free (childtype
);
111 /* Iterate through all device aliases. This function can be used to
112 find a device of a specific type. */
114 grub_devalias_iterate (int (*hook
) (struct grub_ieee1275_devalias
*alias
))
116 grub_ieee1275_phandle_t aliases
;
117 char *aliasname
, *devtype
;
119 struct grub_ieee1275_devalias alias
;
122 if (grub_ieee1275_finddevice ("/aliases", &aliases
))
125 aliasname
= grub_malloc (IEEE1275_MAX_PROP_LEN
);
128 devtype
= grub_malloc (IEEE1275_MAX_PROP_LEN
);
131 grub_free (aliasname
);
135 /* Find the first property. */
138 while (grub_ieee1275_next_property (aliases
, aliasname
, aliasname
))
140 grub_ieee1275_phandle_t dev
;
141 grub_ssize_t pathlen
;
144 grub_dprintf ("devalias", "devalias name = %s\n", aliasname
);
146 grub_ieee1275_get_property_length (aliases
, aliasname
, &pathlen
);
148 /* The property `name' is a special case we should skip. */
149 if (!grub_strcmp (aliasname
, "name"))
152 /* Sun's OpenBoot often doesn't zero terminate the device alias
153 strings, so we will add a NULL byte at the end explicitly. */
156 devpath
= grub_malloc (pathlen
);
160 grub_free (aliasname
);
164 if (grub_ieee1275_get_property (aliases
, aliasname
, devpath
, pathlen
,
167 grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname
);
170 devpath
[actual
] = '\0';
172 if (grub_ieee1275_finddevice (devpath
, &dev
))
174 grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath
);
178 if (grub_ieee1275_get_property (dev
, "device_type", devtype
,
179 IEEE1275_MAX_PROP_LEN
, &actual
))
181 /* NAND device don't have device_type property. */
185 alias
.name
= aliasname
;
186 alias
.path
= devpath
;
187 alias
.type
= devtype
;
197 grub_free (aliasname
);
201 /* Call the "map" method of /chosen/mmu. */
203 grub_map (grub_addr_t phys
, grub_addr_t virt
, grub_uint32_t size
,
207 struct grub_ieee1275_common_hdr common
;
208 grub_ieee1275_cell_t method
;
209 grub_ieee1275_cell_t ihandle
;
210 grub_ieee1275_cell_t mode
;
211 grub_ieee1275_cell_t size
;
212 grub_ieee1275_cell_t virt
;
213 grub_ieee1275_cell_t phys
;
214 grub_ieee1275_cell_t catch_result
;
217 INIT_IEEE1275_COMMON (&args
.common
, "call-method", 6, 1);
218 args
.method
= (grub_ieee1275_cell_t
) "map";
219 args
.ihandle
= grub_ieee1275_mmu
;
223 args
.mode
= mode
; /* Format is WIMG0PP. */
225 if (IEEE1275_CALL_ENTRY_FN (&args
) == -1)
228 return args
.catch_result
;
232 grub_claimmap (grub_addr_t addr
, grub_size_t size
)
234 if (grub_ieee1275_claim (addr
, size
, 0, 0))
237 if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE
)
238 && grub_map (addr
, addr
, size
, 0x00))
240 grub_printf ("map failed: address 0x%llx, size 0x%llx\n",
241 (long long) addr
, (long long) size
);
242 grub_ieee1275_release (addr
, size
);
249 /* Get the device arguments of the Open Firmware node name `path'. */
251 grub_ieee1275_get_devargs (const char *path
)
253 char *colon
= grub_strchr (path
, ':');
258 return grub_strdup (colon
+ 1);
261 /* Get the device path of the Open Firmware node name `path'. */
263 grub_ieee1275_get_devname (const char *path
)
265 char *colon
= grub_strchr (path
, ':');
267 int pathlen
= grub_strlen (path
);
268 auto int match_alias (struct grub_ieee1275_devalias
*alias
);
270 int match_alias (struct grub_ieee1275_devalias
*curalias
)
272 /* briQ firmware can change capitalization in /chosen/bootpath. */
273 if (! grub_strncasecmp (curalias
->path
, path
, pathlen
))
275 newpath
= grub_strdup (curalias
->name
);
283 pathlen
= (int)(colon
- path
);
285 /* Try to find an alias for this device. */
286 grub_devalias_iterate (match_alias
);
289 newpath
= grub_strndup (path
, pathlen
);
295 grub_ieee1275_parse_args (const char *path
, enum grub_ieee1275_parse_type ptype
)
297 char type
[64]; /* XXX check size. */
298 char *device
= grub_ieee1275_get_devname (path
);
299 char *args
= grub_ieee1275_get_devargs (path
);
301 grub_ieee1275_phandle_t dev
;
304 /* Shouldn't happen. */
307 /* We need to know what type of device it is in order to parse the full
308 file path properly. */
309 if (grub_ieee1275_finddevice (device
, &dev
))
311 grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Device %s not found\n", device
);
314 if (grub_ieee1275_get_property (dev
, "device_type", &type
, sizeof type
, 0))
316 grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
317 "Device %s lacks a device_type property\n", device
);
321 if (!grub_strcmp ("block", type
))
323 /* The syntax of the device arguments is defined in the CHRP and PReP
324 IEEE1275 bindings: "[partition][,[filename]]". */
325 char *comma
= grub_strchr (args
, ',');
327 if (ptype
== GRUB_PARSE_FILENAME
)
331 char *filepath
= comma
+ 1;
333 ret
= grub_malloc (grub_strlen (filepath
) + 1);
334 /* Make sure filepath has leading backslash. */
335 if (filepath
[0] != '\\')
336 grub_sprintf (ret
, "\\%s", filepath
);
338 grub_strcpy (ret
, filepath
);
341 else if (ptype
== GRUB_PARSE_PARTITION
)
344 ret
= grub_strdup (args
);
346 ret
= grub_strndup (args
, (grub_size_t
)(comma
- args
));
351 /* XXX Handle net devices by configuring & registering a grub_net_dev
352 here, then return its name?
353 Example path: "net:<server ip>,<file name>,<client ip>,<gateway
354 ip>,<bootp retries>,<tftp retries>". */
355 grub_printf ("Unsupported type %s for device %s\n", type
, device
);
365 grub_ieee1275_get_filename (const char *path
)
367 return grub_ieee1275_parse_args (path
, GRUB_PARSE_FILENAME
);
370 /* Convert a device name from IEEE1275 syntax to GRUB syntax. */
372 grub_ieee1275_encode_devname (const char *path
)
374 char *device
= grub_ieee1275_get_devname (path
);
375 char *partition
= grub_ieee1275_parse_args (path
, GRUB_PARSE_PARTITION
);
380 unsigned int partno
= grub_strtoul (partition
, 0, 0);
382 if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS
))
383 /* GRUB partition 1 is OF partition 0. */
386 /* Assume partno will require less than five bytes to encode. */
387 encoding
= grub_malloc (grub_strlen (device
) + 3 + 5);
388 grub_sprintf (encoding
, "(%s,%d)", device
, partno
);
392 encoding
= grub_malloc (grub_strlen (device
) + 2);
393 grub_sprintf (encoding
, "(%s)", device
);
396 grub_free (partition
);
405 grub_ieee1275_interpret ("reset-all", 0);
411 /* Not standardized. We try both known commands. */
413 grub_ieee1275_interpret ("shut-down", 0);
414 grub_ieee1275_interpret ("power-off", 0);