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/>.
21 #include <grub/types.h>
23 #include <grub/misc.h>
25 #include <grub/machine/kernel.h>
26 #include <grub/ieee1275/ieee1275.h>
28 enum grub_ieee1275_parse_type
34 /* Walk children of 'devpath', calling hook for each. */
36 grub_children_iterate (char *devpath
,
37 int (*hook
) (struct grub_ieee1275_devalias
*alias
))
39 grub_ieee1275_phandle_t dev
;
40 grub_ieee1275_phandle_t child
;
42 if (grub_ieee1275_finddevice (devpath
, &dev
))
43 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Unknown device");
45 if (grub_ieee1275_child (dev
, &child
))
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 if (grub_ieee1275_get_property (child
, "device_type", &childtype
,
59 sizeof childtype
, &actual
))
62 if (grub_ieee1275_package_to_path (child
, childpath
, sizeof childpath
,
66 if (grub_ieee1275_get_property (child
, "name", &childname
,
67 sizeof childname
, &actual
))
70 grub_sprintf (fullname
, "%s/%s", devpath
, childname
);
72 alias
.type
= childtype
;
73 alias
.path
= childpath
;
74 alias
.name
= fullname
;
77 while (grub_ieee1275_peer (child
, &child
));
82 /* Iterate through all device aliases. This function can be used to
83 find a device of a specific type. */
85 grub_devalias_iterate (int (*hook
) (struct grub_ieee1275_devalias
*alias
))
87 grub_ieee1275_phandle_t aliases
;
90 struct grub_ieee1275_devalias alias
;
92 if (grub_ieee1275_finddevice ("/aliases", &aliases
))
95 /* Find the first property. */
98 while (grub_ieee1275_next_property (aliases
, aliasname
, aliasname
))
100 grub_ieee1275_phandle_t dev
;
101 grub_ssize_t pathlen
;
103 /* XXX: This should be large enough for any possible case. */
106 grub_dprintf ("devalias", "devalias name = %s\n", aliasname
);
108 grub_ieee1275_get_property_length (aliases
, aliasname
, &pathlen
);
110 /* The property `name' is a special case we should skip. */
111 if (!grub_strcmp (aliasname
, "name"))
114 devpath
= grub_malloc (pathlen
);
118 if (grub_ieee1275_get_property (aliases
, aliasname
, devpath
, pathlen
,
121 grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname
);
125 if (grub_ieee1275_finddevice (devpath
, &dev
))
127 grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath
);
131 if (grub_ieee1275_get_property (dev
, "device_type", devtype
,
132 sizeof devtype
, &actual
))
134 /* NAND device don't have device_type property. */
138 alias
.name
= aliasname
;
139 alias
.path
= devpath
;
140 alias
.type
= devtype
;
150 grub_err_t
grub_available_iterate (int NESTED_FUNC_ATTR (*hook
) (grub_uint64_t
, grub_uint64_t
))
152 grub_ieee1275_phandle_t root
;
153 grub_ieee1275_phandle_t memory
;
154 grub_uint32_t available
[32];
155 grub_ssize_t available_size
;
156 grub_uint32_t address_cells
= 1;
157 grub_uint32_t size_cells
= 1;
160 /* Determine the format of each entry in `available'. */
161 grub_ieee1275_finddevice ("/", &root
);
162 grub_ieee1275_get_integer_property (root
, "#address-cells", &address_cells
,
163 sizeof address_cells
, 0);
164 grub_ieee1275_get_integer_property (root
, "#size-cells", &size_cells
,
165 sizeof size_cells
, 0);
167 /* Load `/memory/available'. */
168 if (grub_ieee1275_finddevice ("/memory", &memory
))
169 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
170 "Couldn't find /memory node");
171 if (grub_ieee1275_get_integer_property (memory
, "available", available
,
172 sizeof available
, &available_size
))
173 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
174 "Couldn't examine /memory/available property");
176 /* Decode each entry and call `hook'. */
178 available_size
/= sizeof (grub_uint32_t
);
179 while (i
< available_size
)
181 grub_uint64_t address
;
184 address
= available
[i
++];
185 if (address_cells
== 2)
186 address
= (address
<< 32) | available
[i
++];
188 size
= available
[i
++];
190 size
= (size
<< 32) | available
[i
++];
192 if (hook (address
, size
))
199 /* Call the "map" method of /chosen/mmu. */
201 grub_map (grub_addr_t phys
, grub_addr_t virt
, grub_uint32_t size
,
205 struct grub_ieee1275_common_hdr common
;
207 grub_ieee1275_ihandle_t ihandle
;
215 INIT_IEEE1275_COMMON (&args
.common
, "call-method", 6, 1);
217 args
.ihandle
= grub_ieee1275_mmu
;
221 args
.mode
= mode
; /* Format is WIMG0PP. */
223 if (IEEE1275_CALL_ENTRY_FN (&args
) == -1)
226 return args
.catch_result
;
230 grub_claimmap (grub_addr_t addr
, grub_size_t size
)
232 if (grub_ieee1275_claim (addr
, size
, 0, 0))
235 if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE
)
236 && grub_map (addr
, addr
, size
, 0x00))
238 grub_printf ("map failed: address 0x%x, size 0x%x\n", addr
, size
);
239 grub_ieee1275_release (addr
, size
);
246 /* Get the device arguments of the Open Firmware node name `path'. */
248 grub_ieee1275_get_devargs (const char *path
)
250 char *colon
= grub_strchr (path
, ':');
255 return grub_strdup (colon
+ 1);
258 /* Get the device path of the Open Firmware node name `path'. */
260 grub_ieee1275_get_devname (const char *path
)
262 char *colon
= grub_strchr (path
, ':');
264 int pathlen
= grub_strlen (path
);
265 auto int match_alias (struct grub_ieee1275_devalias
*alias
);
267 int match_alias (struct grub_ieee1275_devalias
*curalias
)
269 /* briQ firmware can change capitalization in /chosen/bootpath. */
270 if (! grub_strncasecmp (curalias
->path
, path
, pathlen
))
272 newpath
= grub_strdup (curalias
->name
);
280 pathlen
= (int)(colon
- path
);
282 /* Try to find an alias for this device. */
283 grub_devalias_iterate (match_alias
);
286 newpath
= grub_strndup (path
, pathlen
);
292 grub_ieee1275_parse_args (const char *path
, enum grub_ieee1275_parse_type ptype
)
294 char type
[64]; /* XXX check size. */
295 char *device
= grub_ieee1275_get_devname (path
);
296 char *args
= grub_ieee1275_get_devargs (path
);
298 grub_ieee1275_phandle_t dev
;
301 /* Shouldn't happen. */
304 /* We need to know what type of device it is in order to parse the full
305 file path properly. */
306 if (grub_ieee1275_finddevice (device
, &dev
))
308 grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Device %s not found\n", device
);
311 if (grub_ieee1275_get_property (dev
, "device_type", &type
, sizeof type
, 0))
313 grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
314 "Device %s lacks a device_type property\n", device
);
318 if (!grub_strcmp ("block", type
))
320 /* The syntax of the device arguments is defined in the CHRP and PReP
321 IEEE1275 bindings: "[partition][,[filename]]". */
322 char *comma
= grub_strchr (args
, ',');
324 if (ptype
== GRUB_PARSE_FILENAME
)
328 char *filepath
= comma
+ 1;
330 ret
= grub_malloc (grub_strlen (filepath
) + 1);
331 /* Make sure filepath has leading backslash. */
332 if (filepath
[0] != '\\')
333 grub_sprintf (ret
, "\\%s", filepath
);
335 grub_strcpy (ret
, filepath
);
338 else if (ptype
== GRUB_PARSE_PARTITION
)
341 ret
= grub_strdup (args
);
343 ret
= grub_strndup (args
, (grub_size_t
)(comma
- args
));
348 /* XXX Handle net devices by configuring & registering a grub_net_dev
349 here, then return its name?
350 Example path: "net:<server ip>,<file name>,<client ip>,<gateway
351 ip>,<bootp retries>,<tftp retries>". */
352 grub_printf ("Unsupported type %s for device %s\n", type
, device
);
362 grub_ieee1275_get_filename (const char *path
)
364 return grub_ieee1275_parse_args (path
, GRUB_PARSE_FILENAME
);
367 /* Convert a device name from IEEE1275 syntax to GRUB syntax. */
369 grub_ieee1275_encode_devname (const char *path
)
371 char *device
= grub_ieee1275_get_devname (path
);
372 char *partition
= grub_ieee1275_parse_args (path
, GRUB_PARSE_PARTITION
);
377 unsigned int partno
= grub_strtoul (partition
, 0, 0);
379 if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS
))
380 /* GRUB partition 1 is OF partition 0. */
383 /* Assume partno will require less than five bytes to encode. */
384 encoding
= grub_malloc (grub_strlen (device
) + 3 + 5);
385 grub_sprintf (encoding
, "(%s,%d)", device
, partno
);
389 encoding
= grub_malloc (grub_strlen (device
) + 2);
390 grub_sprintf (encoding
, "(%s)", device
);
393 grub_free (partition
);
402 grub_ieee1275_interpret ("reset-all", 0);
408 /* Not standarized. We try both known commands. */
410 grub_ieee1275_interpret ("shut-down", 0);
411 grub_ieee1275_interpret ("power-off", 0);