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

« back to all changes in this revision

Viewing changes to loader/i386/multiboot.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
 
/* multiboot.c - boot a multiboot OS image. */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  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
 
/*
21
 
 *  FIXME: The following features from the Multiboot specification still
22
 
 *         need to be implemented:
23
 
 *  - VBE support
24
 
 *  - symbol table
25
 
 *  - drives table
26
 
 *  - ROM configuration table
27
 
 *  - APM table
28
 
 */
29
 
 
30
 
/* The bits in the required part of flags field we don't support.  */
31
 
#define UNSUPPORTED_FLAGS                       0x0000fff8
32
 
 
33
 
#include <grub/loader.h>
34
 
#include <grub/multiboot.h>
35
 
#include <grub/elf.h>
36
 
#include <grub/aout.h>
37
 
#include <grub/file.h>
38
 
#include <grub/err.h>
39
 
#include <grub/dl.h>
40
 
#include <grub/mm.h>
41
 
#include <grub/misc.h>
42
 
#include <grub/gzio.h>
43
 
#include <grub/env.h>
44
 
#include <grub/i386/relocator.h>
45
 
#include <grub/video.h>
46
 
 
47
 
#ifdef GRUB_MACHINE_EFI
48
 
#include <grub/efi/efi.h>
49
 
#endif
50
 
 
51
 
extern grub_dl_t my_mod;
52
 
static grub_size_t code_size, alloc_mbi;
53
 
 
54
 
char *grub_multiboot_payload_orig;
55
 
grub_addr_t grub_multiboot_payload_dest;
56
 
grub_size_t grub_multiboot_pure_size;
57
 
grub_uint32_t grub_multiboot_payload_eip;
58
 
 
59
 
static grub_err_t
60
 
grub_multiboot_boot (void)
61
 
{
62
 
  grub_size_t mbi_size;
63
 
  grub_err_t err;
64
 
  struct grub_relocator32_state state =
65
 
    {
66
 
      .eax = MULTIBOOT_BOOTLOADER_MAGIC,
67
 
      .ecx = 0,
68
 
      .edx = 0,
69
 
      .eip = grub_multiboot_payload_eip,
70
 
      /* Set esp to some random location in low memory to avoid breaking
71
 
         non-compliant kernels.  */
72
 
      .esp = 0x7ff00
73
 
    };
74
 
 
75
 
  mbi_size = grub_multiboot_get_mbi_size ();
76
 
  if (alloc_mbi < mbi_size)
77
 
    {
78
 
      grub_multiboot_payload_orig
79
 
        = grub_relocator32_realloc (grub_multiboot_payload_orig,
80
 
                                    grub_multiboot_pure_size + mbi_size);
81
 
      if (!grub_multiboot_payload_orig)
82
 
        return grub_errno;
83
 
      alloc_mbi = mbi_size;
84
 
    }
85
 
 
86
 
  state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size;
87
 
  err = grub_multiboot_make_mbi (grub_multiboot_payload_orig,
88
 
                                 grub_multiboot_payload_dest,
89
 
                                 grub_multiboot_pure_size, mbi_size);
90
 
  if (err)
91
 
    return err;
92
 
 
93
 
#ifdef GRUB_MACHINE_EFI
94
 
  if (! grub_efi_finish_boot_services ())
95
 
     grub_fatal ("cannot exit boot services");
96
 
#endif
97
 
 
98
 
  grub_relocator32_boot (grub_multiboot_payload_orig,
99
 
                         grub_multiboot_payload_dest,
100
 
                         state);
101
 
 
102
 
  /* Not reached.  */
103
 
  return GRUB_ERR_NONE;
104
 
}
105
 
 
106
 
static grub_err_t
107
 
grub_multiboot_unload (void)
108
 
{
109
 
  grub_multiboot_free_mbi ();
110
 
 
111
 
  grub_relocator32_free (grub_multiboot_payload_orig);
112
 
 
113
 
  alloc_mbi = 0;
114
 
 
115
 
  grub_multiboot_payload_orig = NULL;
116
 
  grub_dl_unref (my_mod);
117
 
 
118
 
  return GRUB_ERR_NONE;
119
 
}
120
 
 
121
 
#define MULTIBOOT_LOAD_ELF64
122
 
#include "multiboot_elfxx.c"
123
 
#undef MULTIBOOT_LOAD_ELF64
124
 
 
125
 
#define MULTIBOOT_LOAD_ELF32
126
 
#include "multiboot_elfxx.c"
127
 
#undef MULTIBOOT_LOAD_ELF32
128
 
 
129
 
/* Load ELF32 or ELF64.  */
130
 
static grub_err_t
131
 
grub_multiboot_load_elf (grub_file_t file, void *buffer)
132
 
{
133
 
  if (grub_multiboot_is_elf32 (buffer))
134
 
    return grub_multiboot_load_elf32 (file, buffer);
135
 
  else if (grub_multiboot_is_elf64 (buffer))
136
 
    return grub_multiboot_load_elf64 (file, buffer);
137
 
 
138
 
  return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
139
 
}
140
 
 
141
 
void
142
 
grub_multiboot (int argc, char *argv[])
143
 
{
144
 
  grub_file_t file = 0;
145
 
  char buffer[MULTIBOOT_SEARCH];
146
 
  struct multiboot_header *header;
147
 
  grub_ssize_t len;
148
 
 
149
 
  grub_loader_unset ();
150
 
 
151
 
  if (argc == 0)
152
 
    {
153
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
154
 
      goto fail;
155
 
    }
156
 
 
157
 
  file = grub_gzfile_open (argv[0], 1);
158
 
  if (! file)
159
 
    {
160
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
161
 
      goto fail;
162
 
    }
163
 
 
164
 
  len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
165
 
  if (len < 32)
166
 
    {
167
 
      grub_error (GRUB_ERR_BAD_OS, "file too small");
168
 
      goto fail;
169
 
    }
170
 
 
171
 
  /* Look for the multiboot header in the buffer.  The header should
172
 
     be at least 12 bytes and aligned on a 4-byte boundary.  */
173
 
  for (header = (struct multiboot_header *) buffer;
174
 
       ((char *) header <= buffer + len - 12) || (header = 0);
175
 
       header = (struct multiboot_header *) ((char *) header + 4))
176
 
    {
177
 
      if (header->magic == MULTIBOOT_HEADER_MAGIC
178
 
          && !(header->magic + header->flags + header->checksum))
179
 
        break;
180
 
    }
181
 
 
182
 
  if (header == 0)
183
 
    {
184
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
185
 
      goto fail;
186
 
    }
187
 
 
188
 
  if (header->flags & UNSUPPORTED_FLAGS)
189
 
    {
190
 
      grub_error (GRUB_ERR_UNKNOWN_OS,
191
 
                  "unsupported flag: 0x%x", header->flags);
192
 
      goto fail;
193
 
    }
194
 
 
195
 
  grub_relocator32_free (grub_multiboot_payload_orig);
196
 
  grub_multiboot_payload_orig = NULL;
197
 
 
198
 
  /* Skip filename.  */
199
 
  grub_multiboot_init_mbi (argc - 1, argv + 1);
200
 
 
201
 
  if (header->flags & MULTIBOOT_AOUT_KLUDGE)
202
 
    {
203
 
      int offset = ((char *) header - buffer -
204
 
                    (header->header_addr - header->load_addr));
205
 
      int load_size = ((header->load_end_addr == 0) ? file->size - offset :
206
 
                       header->load_end_addr - header->load_addr);
207
 
 
208
 
      if (header->bss_end_addr)
209
 
        code_size = (header->bss_end_addr - header->load_addr);
210
 
      else
211
 
        code_size = load_size;
212
 
      grub_multiboot_payload_dest = header->load_addr;
213
 
 
214
 
      grub_multiboot_pure_size += code_size;
215
 
 
216
 
      /* Allocate a bit more to avoid relocations in most cases.  */
217
 
      alloc_mbi = grub_multiboot_get_mbi_size () + 65536;
218
 
      grub_multiboot_payload_orig
219
 
        = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi);
220
 
 
221
 
      if (! grub_multiboot_payload_orig)
222
 
        goto fail;
223
 
 
224
 
      if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
225
 
        goto fail;
226
 
 
227
 
      grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
228
 
      if (grub_errno)
229
 
        goto fail;
230
 
 
231
 
      if (header->bss_end_addr)
232
 
        grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
233
 
                     header->bss_end_addr - header->load_addr - load_size);
234
 
 
235
 
      grub_multiboot_payload_eip = header->entry_addr;
236
 
 
237
 
    }
238
 
  else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
239
 
    goto fail;
240
 
 
241
 
  if (header->flags & MULTIBOOT_VIDEO_MODE)
242
 
    {
243
 
      switch (header->mode_type)
244
 
        {
245
 
        case 1:
246
 
          grub_env_set ("gfxpayload", "text");
247
 
          break;
248
 
 
249
 
        case 0:
250
 
          {
251
 
            char *buf;
252
 
            if (header->depth && header->width && header->height)
253
 
              buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", header->width,
254
 
                                   header->height, header->depth, header->width,
255
 
                                   header->height);
256
 
            else if (header->width && header->height)
257
 
              buf = grub_xasprintf ("%dx%d,auto", header->width, header->height);
258
 
            else
259
 
              buf = grub_strdup ("auto");
260
 
 
261
 
            if (!buf)
262
 
              goto fail;
263
 
            grub_env_set ("gfxpayload", buf);
264
 
            grub_free (buf);
265
 
            break;
266
 
          }
267
 
        }
268
 
    }
269
 
 
270
 
  grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE));
271
 
 
272
 
  grub_multiboot_set_bootdev ();
273
 
 
274
 
  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
275
 
 
276
 
 fail:
277
 
  if (file)
278
 
    grub_file_close (file);
279
 
 
280
 
  if (grub_errno != GRUB_ERR_NONE)
281
 
    {
282
 
      grub_relocator32_free (grub_multiboot_payload_orig);
283
 
      grub_dl_unref (my_mod);
284
 
    }
285
 
}
286
 
 
287
 
void
288
 
grub_module  (int argc, char *argv[])
289
 
{
290
 
  grub_file_t file = 0;
291
 
  grub_ssize_t size;
292
 
  char *module = 0;
293
 
  grub_err_t err;
294
 
 
295
 
  if (argc == 0)
296
 
    {
297
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
298
 
      goto fail;
299
 
    }
300
 
 
301
 
  if (!grub_multiboot_payload_orig)
302
 
    {
303
 
      grub_error (GRUB_ERR_BAD_ARGUMENT,
304
 
                  "you need to load the multiboot kernel first");
305
 
      goto fail;
306
 
    }
307
 
 
308
 
  file = grub_gzfile_open (argv[0], 1);
309
 
  if (! file)
310
 
    goto fail;
311
 
 
312
 
  size = grub_file_size (file);
313
 
  module = grub_memalign (MULTIBOOT_MOD_ALIGN, size);
314
 
  if (! module)
315
 
    goto fail;
316
 
 
317
 
  err = grub_multiboot_add_module ((grub_addr_t) module, size,
318
 
                                   argc - 1, argv + 1);
319
 
  if (err)
320
 
    goto fail;
321
 
 
322
 
  if (grub_file_read (file, module, size) != size)
323
 
    {
324
 
      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
325
 
      goto fail;
326
 
    }
327
 
 
328
 
 fail:
329
 
  if (file)
330
 
    grub_file_close (file);
331
 
}
332