~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to kern/ieee1275/openfw.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  openfw.c -- Open firmware support functions.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
5
 
 *
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.
10
 
 *
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.
15
 
 *
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/>.
18
 
 */
19
 
 
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>
26
 
 
27
 
enum grub_ieee1275_parse_type
28
 
{
29
 
  GRUB_PARSE_FILENAME,
30
 
  GRUB_PARSE_PARTITION,
31
 
};
32
 
 
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))
37
 
{
38
 
  grub_ieee1275_phandle_t dev;
39
 
  grub_ieee1275_phandle_t child;
40
 
  char *childtype, *childpath;
41
 
  char *childname;
42
 
  int ret = 0;
43
 
 
44
 
  if (grub_ieee1275_finddevice (devpath, &dev))
45
 
    return 0;
46
 
 
47
 
  if (grub_ieee1275_child (dev, &child))
48
 
    return 0;
49
 
 
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)
55
 
    {
56
 
      grub_free (childtype);
57
 
      return 0;
58
 
    }
59
 
  childname = grub_malloc (IEEE1275_MAX_PROP_LEN);
60
 
  if (!childname)
61
 
    {
62
 
      grub_free (childpath);
63
 
      grub_free (childtype);
64
 
      return 0;
65
 
    }
66
 
 
67
 
  do
68
 
    {
69
 
      struct grub_ieee1275_devalias alias;
70
 
      grub_ssize_t actual;
71
 
      char *fullname;
72
 
 
73
 
      if (grub_ieee1275_get_property (child, "device_type", childtype,
74
 
                                      IEEE1275_MAX_PROP_LEN, &actual))
75
 
        continue;
76
 
 
77
 
      if (grub_ieee1275_package_to_path (child, childpath,
78
 
                                         IEEE1275_MAX_PATH_LEN, &actual))
79
 
        continue;
80
 
 
81
 
      if (grub_ieee1275_get_property (child, "name", childname,
82
 
                                      IEEE1275_MAX_PROP_LEN, &actual))
83
 
        continue;
84
 
 
85
 
      fullname = grub_xasprintf ("%s/%s", devpath, childname);
86
 
      if (!fullname)
87
 
        {
88
 
          grub_free (childname);
89
 
          grub_free (childpath);
90
 
          grub_free (childtype);
91
 
          return 0;
92
 
        }
93
 
 
94
 
      alias.type = childtype;
95
 
      alias.path = childpath;
96
 
      alias.name = fullname;
97
 
      ret = hook (&alias);
98
 
      grub_free (fullname);
99
 
      if (ret)
100
 
        break;
101
 
    }
102
 
  while (grub_ieee1275_peer (child, &child));
103
 
 
104
 
  grub_free (childname);
105
 
  grub_free (childpath);
106
 
  grub_free (childtype);
107
 
 
108
 
  return ret;
109
 
}
110
 
 
111
 
/* Iterate through all device aliases.  This function can be used to
112
 
   find a device of a specific type.  */
113
 
int
114
 
grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
115
 
{
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;
121
 
 
122
 
  if (grub_ieee1275_finddevice ("/aliases", &aliases))
123
 
    return 0;
124
 
 
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)
130
 
    {
131
 
      grub_free (aliasname);
132
 
      return 0;
133
 
    }
134
 
 
135
 
  /* Find the first property.  */
136
 
  aliasname[0] = '\0';
137
 
 
138
 
  while (grub_ieee1275_next_property (aliases, aliasname, aliasname))
139
 
    {
140
 
      grub_ieee1275_phandle_t dev;
141
 
      grub_ssize_t pathlen;
142
 
      char *devpath;
143
 
 
144
 
      grub_dprintf ("devalias", "devalias name = %s\n", aliasname);
145
 
 
146
 
      grub_ieee1275_get_property_length (aliases, aliasname, &pathlen);
147
 
 
148
 
      /* The property `name' is a special case we should skip.  */
149
 
      if (!grub_strcmp (aliasname, "name"))
150
 
        continue;
151
 
 
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;
155
 
 
156
 
      devpath = grub_malloc (pathlen);
157
 
      if (! devpath)
158
 
        {
159
 
          grub_free (devtype);
160
 
          grub_free (aliasname);
161
 
          return 0;
162
 
        }
163
 
 
164
 
      if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen,
165
 
                                      &actual))
166
 
        {
167
 
          grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
168
 
          goto nextprop;
169
 
        }
170
 
      devpath [actual] = '\0';
171
 
 
172
 
      if (grub_ieee1275_finddevice (devpath, &dev))
173
 
        {
174
 
          grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath);
175
 
          goto nextprop;
176
 
        }
177
 
 
178
 
      if (grub_ieee1275_get_property (dev, "device_type", devtype,
179
 
                                      IEEE1275_MAX_PROP_LEN, &actual))
180
 
        {
181
 
          /* NAND device don't have device_type property.  */
182
 
          devtype[0] = 0;
183
 
        }
184
 
 
185
 
      alias.name = aliasname;
186
 
      alias.path = devpath;
187
 
      alias.type = devtype;
188
 
      ret = hook (&alias);
189
 
 
190
 
nextprop:
191
 
      grub_free (devpath);
192
 
      if (ret)
193
 
        break;
194
 
    }
195
 
 
196
 
  grub_free (devtype);
197
 
  grub_free (aliasname);
198
 
  return ret;
199
 
}
200
 
 
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)
205
 
{
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;
216
 
 
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.  */
224
 
 
225
 
  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
226
 
    return -1;
227
 
 
228
 
  return args.catch_result;
229
 
}
230
 
 
231
 
int
232
 
grub_claimmap (grub_addr_t addr, grub_size_t size)
233
 
{
234
 
  if (grub_ieee1275_claim (addr, size, 0, 0))
235
 
    return -1;
236
 
 
237
 
  if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE)
238
 
      && grub_map (addr, addr, size, 0x00))
239
 
    {
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;
244
 
    }
245
 
 
246
 
  return 0;
247
 
}
248
 
 
249
 
/* Get the device arguments of the Open Firmware node name `path'.  */
250
 
static char *
251
 
grub_ieee1275_get_devargs (const char *path)
252
 
{
253
 
  char *colon = grub_strchr (path, ':');
254
 
 
255
 
  if (! colon)
256
 
    return 0;
257
 
 
258
 
  return grub_strdup (colon + 1);
259
 
}
260
 
 
261
 
/* Get the device path of the Open Firmware node name `path'.  */
262
 
static char *
263
 
grub_ieee1275_get_devname (const char *path)
264
 
{
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);
269
 
 
270
 
  int match_alias (struct grub_ieee1275_devalias *curalias)
271
 
    {
272
 
      /* briQ firmware can change capitalization in /chosen/bootpath.  */
273
 
      if (! grub_strncasecmp (curalias->path, path, pathlen))
274
 
        {
275
 
          newpath = grub_strdup (curalias->name);
276
 
          return 1;
277
 
        }
278
 
 
279
 
      return 0;
280
 
    }
281
 
 
282
 
  if (colon)
283
 
    pathlen = (int)(colon - path);
284
 
 
285
 
  /* Try to find an alias for this device.  */
286
 
  grub_devalias_iterate (match_alias);
287
 
 
288
 
  if (! newpath)
289
 
    newpath = grub_strndup (path, pathlen);
290
 
 
291
 
  return newpath;
292
 
}
293
 
 
294
 
static char *
295
 
grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
296
 
{
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;
302
 
 
303
 
  if (!args)
304
 
    /* Shouldn't happen.  */
305
 
    return 0;
306
 
 
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))
310
 
    {
311
 
      grub_error (GRUB_ERR_UNKNOWN_DEVICE, "device %s not found", device);
312
 
      goto fail;
313
 
    }
314
 
  if (grub_ieee1275_get_property (dev, "device_type", &type, sizeof type, 0))
315
 
    {
316
 
      grub_error (GRUB_ERR_UNKNOWN_DEVICE,
317
 
                  "device %s lacks a device_type property", device);
318
 
      goto fail;
319
 
    }
320
 
 
321
 
  if (!grub_strcmp ("block", type))
322
 
    {
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, ',');
326
 
 
327
 
      if (ptype == GRUB_PARSE_FILENAME)
328
 
        {
329
 
          if (comma)
330
 
            {
331
 
              char *filepath = comma + 1;
332
 
 
333
 
              /* Make sure filepath has leading backslash.  */
334
 
              if (filepath[0] != '\\')
335
 
                ret = grub_xasprintf ("\\%s", filepath);
336
 
              else
337
 
                ret = grub_strdup (filepath);
338
 
            }
339
 
        }
340
 
      else if (ptype == GRUB_PARSE_PARTITION)
341
 
        {
342
 
          if (!comma)
343
 
            ret = grub_strdup (args);
344
 
          else
345
 
            ret = grub_strndup (args, (grub_size_t)(comma - args));
346
 
        }
347
 
    }
348
 
  else
349
 
    {
350
 
      /* XXX Handle net devices by configuring & registering a grub_net_dev
351
 
         here, then return its name?
352
 
         Example path: "net:<server ip>,<file name>,<client ip>,<gateway
353
 
         ip>,<bootp retries>,<tftp retries>".  */
354
 
      grub_printf ("Unsupported type %s for device %s\n", type, device);
355
 
    }
356
 
 
357
 
fail:
358
 
  grub_free (device);
359
 
  grub_free (args);
360
 
  return ret;
361
 
}
362
 
 
363
 
char *
364
 
grub_ieee1275_get_filename (const char *path)
365
 
{
366
 
  return grub_ieee1275_parse_args (path, GRUB_PARSE_FILENAME);
367
 
}
368
 
 
369
 
/* Convert a device name from IEEE1275 syntax to GRUB syntax.  */
370
 
char *
371
 
grub_ieee1275_encode_devname (const char *path)
372
 
{
373
 
  char *device = grub_ieee1275_get_devname (path);
374
 
  char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION);
375
 
  char *encoding;
376
 
 
377
 
  if (partition)
378
 
    {
379
 
      unsigned int partno = grub_strtoul (partition, 0, 0);
380
 
 
381
 
      if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS))
382
 
        /* GRUB partition 1 is OF partition 0.  */
383
 
        partno++;
384
 
 
385
 
      encoding = grub_xasprintf ("(%s,%d)", device, partno);
386
 
    }
387
 
  else
388
 
    encoding = grub_xasprintf ("(%s)", device);
389
 
 
390
 
  grub_free (partition);
391
 
  grub_free (device);
392
 
 
393
 
  return encoding;
394
 
}
395
 
 
396
 
/* On i386, a firmware-independant grub_reboot() is provided by realmode.S.  */
397
 
#ifndef __i386__
398
 
void
399
 
grub_reboot (void)
400
 
{
401
 
  grub_ieee1275_interpret ("reset-all", 0);
402
 
}
403
 
#endif
404
 
 
405
 
void
406
 
grub_halt (void)
407
 
{
408
 
  /* Not standardized.  We try both known commands.  */
409
 
 
410
 
  grub_ieee1275_interpret ("shut-down", 0);
411
 
  grub_ieee1275_interpret ("power-off", 0);
412
 
}