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

« back to all changes in this revision

Viewing changes to loader/i386/pc/multiboot.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2008-05-27 11:32:41 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20080527113241-033nau9g4yfsr5ps
Tags: 1.96+20080512-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Adjust debian/default/grub for default Ubuntu boot options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* multiboot.c - boot a multiboot OS image. */
2
2
/*
3
3
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2003,2004,2005,2007  Free Software Foundation, Inc.
 
4
 *  Copyright (C) 2003,2004,2005,2007,2008  Free Software Foundation, Inc.
5
5
 *
6
6
 *  GRUB is free software: you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
17
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
18
 */
19
19
 
20
 
/* 
 
20
/*
21
21
 *  FIXME: The following features from the Multiboot specification still
22
22
 *         need to be implemented:
23
23
 *  - VBE support
36
36
#include <grub/machine/init.h>
37
37
#include <grub/machine/memory.h>
38
38
#include <grub/elf.h>
 
39
#include <grub/aout.h>
39
40
#include <grub/file.h>
40
41
#include <grub/err.h>
41
42
#include <grub/rescue.h>
43
44
#include <grub/mm.h>
44
45
#include <grub/misc.h>
45
46
#include <grub/gzio.h>
 
47
#include <grub/env.h>
46
48
 
47
49
extern grub_dl_t my_mod;
48
50
static struct grub_multiboot_info *mbi;
87
89
grub_multiboot_is_elf32 (void *buffer)
88
90
{
89
91
  Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
90
 
  
 
92
 
91
93
  return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
92
94
}
93
95
 
96
98
{
97
99
  Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
98
100
  Elf32_Phdr *phdr;
 
101
  grub_addr_t physical_entry_addr = 0;
99
102
  int i;
100
103
 
101
104
  if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
102
105
    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
103
 
  
 
106
 
104
107
  if (grub_dl_check_header (ehdr, sizeof(Elf32_Ehdr)))
105
108
    return grub_error (GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
106
 
  
 
109
 
107
110
  if (ehdr->e_type != ET_EXEC)
108
111
    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
109
 
  
 
112
 
110
113
  /* FIXME: Should we support program headers at strange locations?  */
111
114
  if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
112
115
    return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
113
 
  
 
116
 
114
117
  entry = ehdr->e_entry;
115
 
  
 
118
 
116
119
  /* Load every loadable segment in memory.  */
117
120
  for (i = 0; i < ehdr->e_phnum; i++)
118
121
    {
135
138
              == (grub_off_t) -1)
136
139
            return grub_error (GRUB_ERR_BAD_OS,
137
140
                               "invalid offset in program header");
138
 
          
 
141
 
139
142
          if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz)
140
143
              != (grub_ssize_t) phdr->p_filesz)
141
144
            return grub_error (GRUB_ERR_BAD_OS,
144
147
          if (phdr->p_filesz < phdr->p_memsz)
145
148
            grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0,
146
149
                         phdr->p_memsz - phdr->p_filesz);
 
150
 
 
151
          if ((entry >= phdr->p_vaddr) &&
 
152
              (entry < phdr->p_vaddr + phdr->p_memsz))
 
153
            physical_entry_addr = entry + phdr->p_paddr - phdr->p_vaddr;
147
154
        }
148
155
    }
149
 
  
 
156
 
 
157
  if (physical_entry_addr)
 
158
    entry = physical_entry_addr;
 
159
 
150
160
  return grub_errno;
151
161
}
152
162
 
155
165
grub_multiboot_is_elf64 (void *buffer)
156
166
{
157
167
  Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
158
 
  
 
168
 
159
169
  return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
160
170
}
161
171
 
164
174
{
165
175
  Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
166
176
  Elf64_Phdr *phdr;
 
177
  grub_addr_t physical_entry_addr = 0;
167
178
  int i;
168
179
 
169
180
  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
209
220
                               "segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
210
221
                               phdr->p_paddr + phdr->p_memsz,
211
222
                               (grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size);
212
 
          
 
223
 
213
224
          if (grub_file_seek (file, (grub_off_t) phdr->p_offset)
214
225
              == (grub_off_t) -1)
215
226
            return grub_error (GRUB_ERR_BAD_OS,
220
231
              != (grub_ssize_t) phdr->p_filesz)
221
232
            return grub_error (GRUB_ERR_BAD_OS,
222
233
                               "couldn't read segment from file");
223
 
          
 
234
 
224
235
          if (phdr->p_filesz < phdr->p_memsz)
225
236
            grub_memset (((char *) ((grub_uint32_t) phdr->p_paddr)
226
237
                          + phdr->p_filesz),
227
238
                         0,
228
239
                         phdr->p_memsz - phdr->p_filesz);
 
240
 
 
241
          if ((entry >= phdr->p_vaddr) &&
 
242
              (entry < phdr->p_vaddr + phdr->p_memsz))
 
243
            physical_entry_addr = entry + phdr->p_paddr - phdr->p_vaddr;
229
244
        }
230
245
    }
231
 
  
 
246
 
 
247
  if (physical_entry_addr)
 
248
    entry = physical_entry_addr;
 
249
 
232
250
  return grub_errno;
233
251
}
234
252
 
240
258
    return grub_multiboot_load_elf32 (file, buffer);
241
259
  else if (grub_multiboot_is_elf64 (buffer))
242
260
    return grub_multiboot_load_elf64 (file, buffer);
243
 
  
 
261
 
244
262
  return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
245
263
}
246
264
 
 
265
static int
 
266
grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 
267
{
 
268
  char *p;
 
269
 
 
270
  p = grub_env_get ("root");
 
271
  if ((p) && ((p[0] == 'h') || (p[0] == 'f')) && (p[1] == 'd') &&
 
272
      (p[2] >= '0') && (p[2] <= '9'))
 
273
    {
 
274
      grub_uint32_t bd;
 
275
 
 
276
      bd = (p[0] == 'h') ? 0x80 : 0;
 
277
      bd += grub_strtoul (p + 2, &p, 0);
 
278
      bd <<= 24;
 
279
 
 
280
      if ((p) && (p[0] == ','))
 
281
        {
 
282
          if ((p[1] >= '0') && (p[1] <= '9'))
 
283
            {
 
284
 
 
285
              bd += ((grub_strtoul (p + 1, &p, 0) - 1) & 0xFF) << 16;
 
286
 
 
287
              if ((p) && (p[0] == ','))
 
288
                p++;
 
289
            }
 
290
          else
 
291
            bd += 0xFF0000;
 
292
 
 
293
          if ((p[0] >= 'a') && (p[0] <= 'z'))
 
294
            bd += (p[0] - 'a') << 8;
 
295
          else
 
296
            bd += 0xFF00;
 
297
        }
 
298
      else
 
299
        bd += 0xFFFF00;
 
300
 
 
301
      bd += 0xFF;
 
302
 
 
303
      *bootdev = bd;
 
304
      return 1;
 
305
    }
 
306
 
 
307
  return 0;
 
308
}
 
309
 
247
310
void
248
311
grub_multiboot (int argc, char *argv[])
249
312
{
254
317
  int i;
255
318
 
256
319
  grub_loader_unset ();
257
 
    
 
320
 
258
321
  if (argc == 0)
259
322
    {
260
323
      grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified");
277
340
 
278
341
  /* Look for the multiboot header in the buffer.  The header should
279
342
     be at least 12 bytes and aligned on a 4-byte boundary.  */
280
 
  for (header = (struct grub_multiboot_header *) buffer; 
 
343
  for (header = (struct grub_multiboot_header *) buffer;
281
344
       ((char *) header <= buffer + len - 12) || (header = 0);
282
345
       header = (struct grub_multiboot_header *) ((char *) header + 4))
283
346
    {
284
 
      if (header->magic == MULTIBOOT_MAGIC 
 
347
      if (header->magic == MULTIBOOT_MAGIC
285
348
          && !(header->magic + header->flags + header->checksum))
286
349
        break;
287
350
    }
288
 
  
 
351
 
289
352
  if (header == 0)
290
353
    {
291
354
      grub_error (GRUB_ERR_BAD_ARGUMENT, "No multiboot header found");
299
362
      goto fail;
300
363
    }
301
364
 
302
 
  if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
 
365
  if (header->flags & MULTIBOOT_AOUT_KLUDGE)
 
366
    {
 
367
      int ofs;
 
368
 
 
369
      ofs = (char *) header - buffer -
 
370
            (header->header_addr - header->load_addr);
 
371
      if ((grub_aout_load (file, ofs, header->load_addr,
 
372
                           ((header->load_end_addr == 0) ? 0 :
 
373
                            header->load_end_addr - header->load_addr),
 
374
                           header->bss_end_addr))
 
375
          !=GRUB_ERR_NONE)
 
376
        goto fail;
 
377
 
 
378
      entry = header->entry_addr;
 
379
    }
 
380
  else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
303
381
    goto fail;
304
 
  
 
382
 
305
383
  mbi = grub_malloc (sizeof (struct grub_multiboot_info));
306
384
  if (! mbi)
307
385
    goto fail;
308
386
 
 
387
  grub_memset (mbi, 0, sizeof (struct grub_multiboot_info));
 
388
 
309
389
  mbi->flags = MULTIBOOT_INFO_MEMORY;
310
390
 
311
391
  /* Convert from bytes to kilobytes.  */
314
394
 
315
395
  for (i = 0, len = 0; i < argc; i++)
316
396
    len += grub_strlen (argv[i]) + 1;
317
 
  
 
397
 
318
398
  cmdline = p = grub_malloc (len);
319
399
  if (! cmdline)
320
400
    goto fail;
321
 
  
 
401
 
322
402
  for (i = 0; i < argc; i++)
323
403
    {
324
404
      p = grub_stpcpy (p, argv[i]);
325
405
      *(p++) = ' ';
326
406
    }
327
 
  
 
407
 
328
408
  /* Remove the space after the last word.  */
329
409
  *(--p) = '\0';
330
 
  
 
410
 
331
411
  mbi->flags |= MULTIBOOT_INFO_CMDLINE;
332
412
  mbi->cmdline = (grub_uint32_t) cmdline;
333
413
 
334
414
  mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
335
415
  mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING);
336
416
 
 
417
  if (grub_multiboot_get_bootdev (&mbi->boot_device))
 
418
    mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
 
419
 
337
420
  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
338
421
 
339
422
 fail:
365
448
 
366
449
  if (!mbi)
367
450
    {
368
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, 
 
451
      grub_error (GRUB_ERR_BAD_ARGUMENT,
369
452
                  "You need to load the multiboot kernel first");
370
453
      goto fail;
371
454
    }
384
467
      grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
385
468
      goto fail;
386
469
    }
387
 
  
 
470
 
388
471
  for (i = 0; i < argc; i++)
389
472
    len += grub_strlen (argv[i]) + 1;
390
 
  
 
473
 
391
474
  cmdline = p = grub_malloc (len);
392
475
  if (! cmdline)
393
476
    goto fail;
394
 
  
 
477
 
395
478
  for (i = 0; i < argc; i++)
396
479
    {
397
480
      p = grub_stpcpy (p, argv[i]);
398
481
      *(p++) = ' ';
399
482
    }
400
 
  
 
483
 
401
484
  /* Remove the space after the last word.  */
402
485
  *(--p) = '\0';
403
486
 
405
488
    {
406
489
      struct grub_mod_list *modlist = (struct grub_mod_list *) mbi->mods_addr;
407
490
 
408
 
      modlist = grub_realloc (modlist, (mbi->mods_count + 1) 
 
491
      modlist = grub_realloc (modlist, (mbi->mods_count + 1)
409
492
                                       * sizeof (struct grub_mod_list));
410
493
      if (! modlist)
411
494
        goto fail;