1 /* openfw.c -- Open firmware support functions. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,2005,2007 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/>.
21 #include <grub/misc.h>
23 #include <grub/machine/kernel.h> /* Needed ? */
24 #include <grub/ieee1275/ieee1275.h>
26 enum grub_ieee1275_parse_type
32 /* Walk children of 'devpath', calling hook for each. */
34 grub_children_iterate (char *devpath
,
35 int (*hook
) (struct grub_ieee1275_devalias
*alias
))
37 grub_ieee1275_phandle_t dev
;
38 grub_ieee1275_phandle_t child
;
40 grub_ieee1275_finddevice (devpath
, &dev
);
41 if (((signed) dev
) == -1)
42 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Unknown device");
44 grub_ieee1275_child (dev
, &child
);
45 if (((signed) child
) == -1)
46 return grub_error (GRUB_ERR_BAD_DEVICE
, "Device has no children");
50 /* XXX: Don't use hardcoded path lengths. */
55 struct grub_ieee1275_devalias alias
;
58 grub_ieee1275_get_property (child
, "device_type", childtype
,
59 sizeof childtype
, &actual
);
63 grub_ieee1275_package_to_path (child
, childpath
, sizeof childpath
,
68 grub_ieee1275_get_property (child
, "name", childname
,
69 sizeof childname
, &actual
);
73 grub_sprintf (fullname
, "%s/%s", devpath
, childname
);
75 alias
.type
= childtype
;
76 alias
.path
= childpath
;
77 alias
.name
= fullname
;
80 while (grub_ieee1275_peer (child
, &child
));
85 /* Iterate through all device aliases. This function can be used to
86 find a device of a specific type. */
88 grub_devalias_iterate (int (*hook
) (struct grub_ieee1275_devalias
*alias
))
90 grub_ieee1275_phandle_t devalias
;
93 grub_ieee1275_cell_t flags
;
94 struct grub_ieee1275_devalias alias
;
96 if (grub_ieee1275_finddevice ("/aliases", &devalias
))
101 while (grub_ieee1275_next_property (devalias
, aliasname
, aliasname
, &flags
) != -1
102 && ((signed) flags
) != -1 )
104 grub_ieee1275_phandle_t dev
;
105 grub_ssize_t pathlen
, typelen
;
106 char *devpath
, *devtype
;
108 grub_dprintf ("devalias", "devalias name = %s\n", aliasname
);
110 /* The property `name' is a special case we should skip. */
111 if (!grub_strcmp (aliasname
, "name"))
114 grub_ieee1275_get_property_length (devalias
, aliasname
, &pathlen
);
115 devpath
= grub_malloc (pathlen
);
119 if (grub_ieee1275_get_property (devalias
, aliasname
, devpath
, pathlen
,
122 grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname
);
127 if (grub_ieee1275_finddevice (devpath
, &dev
) || ((signed) dev
) == -1)
129 grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath
);
134 grub_ieee1275_get_property_length (dev
, "device_type", &typelen
);
135 devtype
= grub_malloc (typelen
);
141 if (grub_ieee1275_get_property (dev
, "device_type", devtype
, typelen
, &actual
))
143 grub_dprintf ("devalias", "get device type failed\n");
149 alias
.name
= aliasname
;
151 alias
.type
= devtype
;
166 /* FIXME (sparc64) */
168 /* Call the "map" method of /chosen/mmu. */
170 grub_map (grub_addr_t phys
, grub_addr_t virt
, grub_uint32_t size
,
174 struct grub_ieee1275_common_hdr common
;
176 grub_ieee1275_ihandle_t ihandle
;
183 grub_ieee1275_ihandle_t mmu
;
186 grub_ieee1275_get_integer_property (grub_ieee1275_chosen
, "mmu", &mmu
, sizeof mmu
,
188 if (len
!= sizeof mmu
)
191 INIT_IEEE1275_COMMON (&args
.common
, "call-method", 6, 1);
197 args
.mode
= mode
; /* Format is WIMG0PP. */
199 if (IEEE1275_CALL_ENTRY_FN (&args
) == -1)
202 return args
.catch_result
;
207 grub_claimmap (grub_addr_t addr
, grub_size_t size
)
209 if (grub_ieee1275_claim (addr
, size
, 0, 0))
214 /* Get the device arguments of the Open Firmware node name `path'. */
216 grub_ieee1275_get_devargs (const char *path
)
218 char *colon
= grub_strchr (path
, ':');
223 return grub_strdup (colon
+ 1);
226 /* Get the device path of the Open Firmware node name `path'. */
228 grub_ieee1275_get_devname (const char *path
)
230 char *colon
= grub_strchr (path
, ':');
232 int pathlen
= grub_strlen (path
);
233 auto int match_alias (struct grub_ieee1275_devalias
*alias
);
235 int match_alias (struct grub_ieee1275_devalias
*curalias
)
237 /* briQ firmware can change capitalization in /chosen/bootpath. */
238 if (! grub_strncasecmp (curalias
->path
, path
, pathlen
))
240 newpath
= grub_strndup (curalias
->name
, grub_strlen (curalias
->name
));
248 pathlen
= (int)(colon
- path
);
250 /* Try to find an alias for this device. */
251 grub_devalias_iterate (match_alias
);
254 newpath
= grub_strdup (path
);
260 grub_ieee1275_parse_args (const char *path
, enum grub_ieee1275_parse_type ptype
)
262 char type
[64]; /* XXX check size. */
263 char *device
= grub_ieee1275_get_devname (path
);
264 char *args
= grub_ieee1275_get_devargs (path
);
266 grub_ieee1275_phandle_t dev
;
269 /* Shouldn't happen. */
272 /* We need to know what type of device it is in order to parse the full
273 file path properly. */
274 if (grub_ieee1275_finddevice (device
, &dev
))
276 grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Device %s not found\n", device
);
279 if (grub_ieee1275_get_property (dev
, "device_type", type
, sizeof type
, 0))
281 grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
282 "Device %s lacks a device_type property\n", device
);
286 if (!grub_strcmp ("block", type
))
288 /* The syntax of the device arguments is defined in the CHRP and PReP
289 IEEE1275 bindings: "[partition][,[filename]]". */
290 char *comma
= grub_strchr (args
, ',');
292 if (ptype
== GRUB_PARSE_FILENAME
)
296 char *filepath
= comma
+ 1;
298 ret
= grub_malloc (grub_strlen (filepath
) + 1);
299 /* Make sure filepath has leading backslash. */
300 if (filepath
[0] != '\\')
301 grub_sprintf (ret
, "\\%s", filepath
);
303 grub_strcpy (ret
, filepath
);
306 else if (ptype
== GRUB_PARSE_PARTITION
)
309 ret
= grub_strdup (args
);
311 ret
= grub_strndup (args
, (grub_size_t
)(comma
- args
));
316 /* XXX Handle net devices by configuring & registering a grub_net_dev
317 here, then return its name?
318 Example path: "net:<server ip>,<file name>,<client ip>,<gateway
319 ip>,<bootp retries>,<tftp retries>". */
320 grub_printf ("Unsupported type %s for device %s\n", type
, device
);
330 grub_ieee1275_get_filename (const char *path
)
332 return grub_ieee1275_parse_args (path
, GRUB_PARSE_FILENAME
);
335 /* Convert a device name from IEEE1275 syntax to GRUB syntax. */
337 grub_ieee1275_encode_devname (const char *path
)
339 char *device
= grub_ieee1275_get_devname (path
);
340 char *partition
= grub_ieee1275_parse_args (path
, GRUB_PARSE_PARTITION
);
345 unsigned int partno
= grub_strtoul (partition
, 0, 0);
347 /* Assume partno will require less than five bytes to encode. */
348 encoding
= grub_malloc (grub_strlen (device
) + 3 + 5);
349 grub_sprintf (encoding
, "(%s,%d)", device
, partno
);
353 encoding
= grub_malloc (grub_strlen (device
) + 2);
354 grub_sprintf (encoding
, "(%s)", device
);
357 grub_free (partition
);
366 grub_ieee1275_interpret ("reset-all", 0);
372 grub_ieee1275_interpret ("power-off", 0);