Add a few new files.
[grub2/phcoder/solaris.git] / kern / ieee1275 / openfw.c
blobac97a59206043f77e327b5b2a3a841b0ab8e9588
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 <alloca.h>
21 #include <grub/types.h>
22 #include <grub/err.h>
23 #include <grub/misc.h>
24 #include <grub/mm.h>
25 #include <grub/machine/kernel.h>
26 #include <grub/ieee1275/ieee1275.h>
28 enum grub_ieee1275_parse_type
30 GRUB_PARSE_FILENAME,
31 GRUB_PARSE_PARTITION,
34 /* Walk children of 'devpath', calling hook for each. */
35 grub_err_t
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. */
51 char childtype[64];
52 char childpath[64];
53 char childname[64];
54 char fullname[64];
55 struct grub_ieee1275_devalias alias;
56 int actual;
58 if (grub_ieee1275_get_property (child, "device_type", &childtype,
59 sizeof childtype, &actual))
60 continue;
62 if (grub_ieee1275_package_to_path (child, childpath, sizeof childpath,
63 &actual))
64 continue;
66 if (grub_ieee1275_get_property (child, "name", &childname,
67 sizeof childname, &actual))
68 continue;
70 grub_sprintf (fullname, "%s/%s", devpath, childname);
72 alias.type = childtype;
73 alias.path = childpath;
74 alias.name = fullname;
75 hook (&alias);
77 while (grub_ieee1275_peer (child, &child));
79 return 0;
82 /* Iterate through all device aliases. This function can be used to
83 find a device of a specific type. */
84 grub_err_t
85 grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
87 grub_ieee1275_phandle_t aliases;
88 char aliasname[32];
89 int actual;
90 struct grub_ieee1275_devalias alias;
92 if (grub_ieee1275_finddevice ("/aliases", &aliases))
93 return -1;
95 /* Find the first property. */
96 aliasname[0] = '\0';
98 while (grub_ieee1275_next_property (aliases, aliasname, aliasname))
100 grub_ieee1275_phandle_t dev;
101 grub_ssize_t pathlen;
102 char *devpath;
103 /* XXX: This should be large enough for any possible case. */
104 char devtype[64];
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"))
112 continue;
114 devpath = grub_malloc (pathlen);
115 if (! devpath)
116 return grub_errno;
118 if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen,
119 &actual))
121 grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
122 goto nextprop;
125 if (grub_ieee1275_finddevice (devpath, &dev))
127 grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath);
128 goto nextprop;
131 if (grub_ieee1275_get_property (dev, "device_type", devtype,
132 sizeof devtype, &actual))
134 /* NAND device don't have device_type property. */
135 devtype[0] = 0;
138 alias.name = aliasname;
139 alias.path = devpath;
140 alias.type = devtype;
141 hook (&alias);
143 nextprop:
144 grub_free (devpath);
147 return 0;
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;
158 int i;
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'. */
177 i = 0;
178 available_size /= sizeof (grub_uint32_t);
179 while (i < available_size)
181 grub_uint64_t address;
182 grub_uint64_t size;
184 address = available[i++];
185 if (address_cells == 2)
186 address = (address << 32) | available[i++];
188 size = available[i++];
189 if (size_cells == 2)
190 size = (size << 32) | available[i++];
192 if (hook (address, size))
193 break;
196 return grub_errno;
199 /* Call the "map" method of /chosen/mmu. */
200 static int
201 grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size,
202 grub_uint8_t mode)
204 struct map_args {
205 struct grub_ieee1275_common_hdr common;
206 char *method;
207 grub_ieee1275_ihandle_t ihandle;
208 grub_uint32_t mode;
209 grub_uint32_t size;
210 grub_uint32_t virt;
211 grub_uint32_t phys;
212 int catch_result;
213 } args;
215 INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
216 args.method = "map";
217 args.ihandle = grub_ieee1275_mmu;
218 args.phys = phys;
219 args.virt = virt;
220 args.size = size;
221 args.mode = mode; /* Format is WIMG0PP. */
223 if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
224 return -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))
233 return -1;
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);
240 return -1;
243 return 0;
246 /* Get the device arguments of the Open Firmware node name `path'. */
247 static char *
248 grub_ieee1275_get_devargs (const char *path)
250 char *colon = grub_strchr (path, ':');
252 if (! colon)
253 return 0;
255 return grub_strdup (colon + 1);
258 /* Get the device path of the Open Firmware node name `path'. */
259 static char *
260 grub_ieee1275_get_devname (const char *path)
262 char *colon = grub_strchr (path, ':');
263 char *newpath = 0;
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);
273 return 1;
276 return 0;
279 if (colon)
280 pathlen = (int)(colon - path);
282 /* Try to find an alias for this device. */
283 grub_devalias_iterate (match_alias);
285 if (! newpath)
286 newpath = grub_strndup (path, pathlen);
288 return newpath;
291 static char *
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);
297 char *ret = 0;
298 grub_ieee1275_phandle_t dev;
300 if (!args)
301 /* Shouldn't happen. */
302 return 0;
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);
309 goto fail;
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);
315 goto fail;
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)
326 if (comma)
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);
334 else
335 grub_strcpy (ret, filepath);
338 else if (ptype == GRUB_PARSE_PARTITION)
340 if (!comma)
341 ret = grub_strdup (args);
342 else
343 ret = grub_strndup (args, (grub_size_t)(comma - args));
346 else
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);
355 fail:
356 grub_free (device);
357 grub_free (args);
358 return ret;
361 char *
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. */
368 char *
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);
373 char *encoding;
375 if (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. */
381 partno++;
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);
387 else
389 encoding = grub_malloc (grub_strlen (device) + 2);
390 grub_sprintf (encoding, "(%s)", device);
393 grub_free (partition);
394 grub_free (device);
396 return encoding;
399 void
400 grub_reboot (void)
402 grub_ieee1275_interpret ("reset-all", 0);
405 void
406 grub_halt (void)
408 /* Not standarized. We try both known commands. */
410 grub_ieee1275_interpret ("shut-down", 0);
411 grub_ieee1275_interpret ("power-off", 0);