Merge branch 'makefile' into haiku
[grub2/phcoder.git] / kern / ieee1275 / openfw.c
blob20ef730e09bcd5bb4fff12c6094aa66af1450d20
1 /* openfw.c -- Open firmware support functions. */
2 /*
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>
21 #include <grub/err.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/machine/kernel.h>
25 #include <grub/ieee1275/ieee1275.h>
27 enum grub_ieee1275_parse_type
29 GRUB_PARSE_FILENAME,
30 GRUB_PARSE_PARTITION,
33 /* Walk children of 'devpath', calling hook for each. */
34 int
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;
42 int ret = 0;
44 if (grub_ieee1275_finddevice (devpath, &dev))
45 return 0;
47 if (grub_ieee1275_child (dev, &child))
48 return 0;
50 childtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
51 if (!childtype)
52 return 0;
53 childpath = grub_malloc (IEEE1275_MAX_PATH_LEN);
54 if (!childpath)
56 grub_free (childtype);
57 return 0;
59 childname = grub_malloc (IEEE1275_MAX_PROP_LEN);
60 if (!childname)
62 grub_free (childpath);
63 grub_free (childtype);
64 return 0;
66 fullname = grub_malloc (IEEE1275_MAX_PATH_LEN);
67 if (!fullname)
69 grub_free (childname);
70 grub_free (childpath);
71 grub_free (childtype);
72 return 0;
77 struct grub_ieee1275_devalias alias;
78 grub_ssize_t actual;
80 if (grub_ieee1275_get_property (child, "device_type", childtype,
81 IEEE1275_MAX_PROP_LEN, &actual))
82 continue;
84 if (grub_ieee1275_package_to_path (child, childpath,
85 IEEE1275_MAX_PATH_LEN, &actual))
86 continue;
88 if (grub_ieee1275_get_property (child, "name", childname,
89 IEEE1275_MAX_PROP_LEN, &actual))
90 continue;
92 grub_sprintf (fullname, "%s/%s", devpath, childname);
94 alias.type = childtype;
95 alias.path = childpath;
96 alias.name = fullname;
97 ret = hook (&alias);
98 if (ret)
99 break;
101 while (grub_ieee1275_peer (child, &child));
103 grub_free (fullname);
104 grub_free (childname);
105 grub_free (childpath);
106 grub_free (childtype);
108 return ret;
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;
118 grub_ssize_t actual;
119 struct grub_ieee1275_devalias alias;
120 int ret = 0;
122 if (grub_ieee1275_finddevice ("/aliases", &aliases))
123 return 0;
125 aliasname = grub_malloc (IEEE1275_MAX_PROP_LEN);
126 if (!aliasname)
127 return 0;
128 devtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
129 if (!devtype)
131 grub_free (aliasname);
132 return 0;
135 /* Find the first property. */
136 aliasname[0] = '\0';
138 while (grub_ieee1275_next_property (aliases, aliasname, aliasname))
140 grub_ieee1275_phandle_t dev;
141 grub_ssize_t pathlen;
142 char *devpath;
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"))
150 continue;
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. */
154 pathlen += 1;
156 devpath = grub_malloc (pathlen);
157 if (! devpath)
159 grub_free (devtype);
160 grub_free (aliasname);
161 return 0;
164 if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen,
165 &actual))
167 grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
168 goto nextprop;
170 devpath [actual] = '\0';
172 if (grub_ieee1275_finddevice (devpath, &dev))
174 grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath);
175 goto nextprop;
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. */
182 devtype[0] = 0;
185 alias.name = aliasname;
186 alias.path = devpath;
187 alias.type = devtype;
188 ret = hook (&alias);
190 nextprop:
191 grub_free (devpath);
192 if (ret)
193 break;
196 grub_free (devtype);
197 grub_free (aliasname);
198 return ret;
201 /* Call the "map" method of /chosen/mmu. */
202 static int
203 grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size,
204 grub_uint8_t mode)
206 struct map_args {
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;
215 } args;
217 INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
218 args.method = (grub_ieee1275_cell_t) "map";
219 args.ihandle = grub_ieee1275_mmu;
220 args.phys = phys;
221 args.virt = virt;
222 args.size = size;
223 args.mode = mode; /* Format is WIMG0PP. */
225 if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
226 return -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))
235 return -1;
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);
243 return -1;
246 return 0;
249 /* Get the device arguments of the Open Firmware node name `path'. */
250 static char *
251 grub_ieee1275_get_devargs (const char *path)
253 char *colon = grub_strchr (path, ':');
255 if (! colon)
256 return 0;
258 return grub_strdup (colon + 1);
261 /* Get the device path of the Open Firmware node name `path'. */
262 static char *
263 grub_ieee1275_get_devname (const char *path)
265 char *colon = grub_strchr (path, ':');
266 char *newpath = 0;
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);
276 return 1;
279 return 0;
282 if (colon)
283 pathlen = (int)(colon - path);
285 /* Try to find an alias for this device. */
286 grub_devalias_iterate (match_alias);
288 if (! newpath)
289 newpath = grub_strndup (path, pathlen);
291 return newpath;
294 static char *
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);
300 char *ret = 0;
301 grub_ieee1275_phandle_t dev;
303 if (!args)
304 /* Shouldn't happen. */
305 return 0;
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);
312 goto fail;
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);
318 goto fail;
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)
329 if (comma)
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);
337 else
338 grub_strcpy (ret, filepath);
341 else if (ptype == GRUB_PARSE_PARTITION)
343 if (!comma)
344 ret = grub_strdup (args);
345 else
346 ret = grub_strndup (args, (grub_size_t)(comma - args));
349 else
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);
358 fail:
359 grub_free (device);
360 grub_free (args);
361 return ret;
364 char *
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. */
371 char *
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);
376 char *encoding;
378 if (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. */
384 partno++;
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);
390 else
392 encoding = grub_malloc (grub_strlen (device) + 2);
393 grub_sprintf (encoding, "(%s)", device);
396 grub_free (partition);
397 grub_free (device);
399 return encoding;
402 void
403 grub_reboot (void)
405 grub_ieee1275_interpret ("reset-all", 0);
408 void
409 grub_halt (void)
411 /* Not standardized. We try both known commands. */
413 grub_ieee1275_interpret ("shut-down", 0);
414 grub_ieee1275_interpret ("power-off", 0);