2
* GRUB -- GRand Unified Bootloader
3
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
5
* GRUB is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* GRUB is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19
#include <grub/machine/memory.h>
20
#include <grub/memory.h>
21
#ifdef GRUB_MACHINE_PCBIOS
22
#include <grub/machine/biosnum.h>
24
#include <grub/multiboot.h>
25
#include <grub/cpu/multiboot.h>
26
#include <grub/cpu/relocator.h>
27
#include <grub/disk.h>
28
#include <grub/device.h>
29
#include <grub/partition.h>
31
#include <grub/misc.h>
33
#include <grub/video.h>
34
#include <grub/file.h>
36
/* The bits in the required part of flags field we don't support. */
37
#define UNSUPPORTED_FLAGS 0x0000fff8
48
struct module *modules, *modules_last;
49
static grub_size_t cmdline_size;
50
static grub_size_t total_modcmd;
51
static unsigned modcnt;
52
static char *cmdline = NULL;
53
static grub_uint32_t bootdev;
54
static int bootdev_set;
57
grub_multiboot_load (grub_file_t file)
61
struct multiboot_header *header;
64
buffer = grub_malloc (MULTIBOOT_SEARCH);
68
len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
72
return grub_error (GRUB_ERR_BAD_OS, "file too small");
75
/* Look for the multiboot header in the buffer. The header should
76
be at least 12 bytes and aligned on a 4-byte boundary. */
77
for (header = (struct multiboot_header *) buffer;
78
((char *) header <= buffer + len - 12) || (header = 0);
79
header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
81
if (header->magic == MULTIBOOT_HEADER_MAGIC
82
&& !(header->magic + header->flags + header->checksum))
89
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
92
if (header->flags & UNSUPPORTED_FLAGS)
95
return grub_error (GRUB_ERR_UNKNOWN_OS,
96
"unsupported flag: 0x%x", header->flags);
99
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
101
int offset = ((char *) header - buffer -
102
(header->header_addr - header->load_addr));
103
int load_size = ((header->load_end_addr == 0) ? file->size - offset :
104
header->load_end_addr - header->load_addr);
105
grub_size_t code_size;
107
if (header->bss_end_addr)
108
code_size = (header->bss_end_addr - header->load_addr);
110
code_size = load_size;
111
grub_multiboot_payload_dest = header->load_addr;
113
grub_multiboot_pure_size += code_size;
115
/* Allocate a bit more to avoid relocations in most cases. */
116
grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536;
117
grub_multiboot_payload_orig
118
= grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi);
120
if (! grub_multiboot_payload_orig)
126
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
132
grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
139
if (header->bss_end_addr)
140
grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
141
header->bss_end_addr - header->load_addr - load_size);
143
grub_multiboot_payload_eip = header->entry_addr;
148
err = grub_multiboot_load_elf (file, buffer);
156
if (header->flags & MULTIBOOT_VIDEO_MODE)
158
switch (header->mode_type)
161
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
162
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
163
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
167
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
168
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
169
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
170
header->width, header->height,
174
err = grub_error (GRUB_ERR_BAD_OS,
175
"unsupported graphical mode type %d",
181
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
182
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
188
grub_multiboot_get_mbi_size (void)
190
return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
191
+ modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
192
+ ALIGN_UP (sizeof(PACKAGE_STRING), 4)
193
+ grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)
194
+ 256 * sizeof (struct multiboot_color);
197
/* Fill previously allocated Multiboot mmap. */
199
grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
201
struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry;
203
auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
204
int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
206
mmap_entry->addr = addr;
207
mmap_entry->len = size;
210
case GRUB_MACHINE_MEMORY_AVAILABLE:
211
mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE;
214
#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE
215
case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE:
216
mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE;
220
#ifdef GRUB_MACHINE_MEMORY_NVS
221
case GRUB_MACHINE_MEMORY_NVS:
222
mmap_entry->type = MULTIBOOT_MEMORY_NVS;
227
mmap_entry->type = MULTIBOOT_MEMORY_RESERVED;
230
mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size);
236
grub_mmap_iterate (hook);
240
retrieve_video_parameters (struct multiboot_info *mbi,
241
grub_uint8_t *ptrorig, grub_uint32_t ptrdest)
244
struct grub_video_mode_info mode_info;
246
grub_video_driver_id_t driv_id;
247
struct grub_video_palette_data palette[256];
249
err = grub_multiboot_set_video_mode ();
253
grub_errno = GRUB_ERR_NONE;
256
grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
258
driv_id = grub_video_get_driver_id ();
259
if (driv_id == GRUB_VIDEO_DRIVER_NONE)
260
return GRUB_ERR_NONE;
262
err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
266
mbi->framebuffer_addr = (grub_addr_t) framebuffer;
267
mbi->framebuffer_pitch = mode_info.pitch;
269
mbi->framebuffer_width = mode_info.width;
270
mbi->framebuffer_height = mode_info.height;
272
mbi->framebuffer_bpp = mode_info.bpp;
274
if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
276
struct multiboot_color *mb_palette;
278
mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
279
mbi->framebuffer_palette_addr = ptrdest;
280
mbi->framebuffer_palette_num_colors = mode_info.number_of_colors;
281
if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
282
mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
283
mb_palette = (struct multiboot_color *) ptrorig;
284
for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
286
mb_palette[i].red = palette[i].r;
287
mb_palette[i].green = palette[i].g;
288
mb_palette[i].blue = palette[i].b;
290
ptrorig += mbi->framebuffer_palette_num_colors
291
* sizeof (struct multiboot_color);
292
ptrdest += mbi->framebuffer_palette_num_colors
293
* sizeof (struct multiboot_color);
297
mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
298
mbi->framebuffer_red_field_position = mode_info.red_field_pos;
299
mbi->framebuffer_red_mask_size = mode_info.red_mask_size;
300
mbi->framebuffer_green_field_position = mode_info.green_field_pos;
301
mbi->framebuffer_green_mask_size = mode_info.green_mask_size;
302
mbi->framebuffer_blue_field_position = mode_info.blue_field_pos;
303
mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size;
306
mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
308
return GRUB_ERR_NONE;
312
grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
315
grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off;
316
grub_uint32_t ptrdest = dest + buf_off;
317
struct multiboot_info *mbi;
318
struct multiboot_mod_list *modlist;
321
grub_size_t mmap_size;
324
if (bufsize < grub_multiboot_get_mbi_size ())
325
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small");
327
mbi = (struct multiboot_info *) ptrorig;
328
ptrorig += sizeof (*mbi);
329
ptrdest += sizeof (*mbi);
330
grub_memset (mbi, 0, sizeof (*mbi));
332
grub_memcpy (ptrorig, cmdline, cmdline_size);
333
mbi->flags |= MULTIBOOT_INFO_CMDLINE;
334
mbi->cmdline = ptrdest;
335
ptrorig += ALIGN_UP (cmdline_size, 4);
336
ptrdest += ALIGN_UP (cmdline_size, 4);
338
grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING));
339
mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
340
mbi->boot_loader_name = ptrdest;
341
ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
342
ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
346
mbi->flags |= MULTIBOOT_INFO_MODS;
347
mbi->mods_addr = ptrdest;
348
mbi->mods_count = modcnt;
349
modlist = (struct multiboot_mod_list *) ptrorig;
350
ptrorig += modcnt * sizeof (struct multiboot_mod_list);
351
ptrdest += modcnt * sizeof (struct multiboot_mod_list);
353
for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next)
355
modlist[i].mod_start = cur->start;
356
modlist[i].mod_end = modlist[i].mod_start + cur->size;
357
modlist[i].cmdline = ptrdest;
358
grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size);
359
ptrorig += ALIGN_UP (cur->cmdline_size, 4);
360
ptrdest += ALIGN_UP (cur->cmdline_size, 4);
369
mmap_size = grub_get_multiboot_mmap_count ()
370
* sizeof (struct multiboot_mmap_entry);
371
grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig);
372
mbi->mmap_length = mmap_size;
373
mbi->mmap_addr = ptrdest;
374
mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
375
ptrorig += mmap_size;
376
ptrdest += mmap_size;
378
/* Convert from bytes to kilobytes. */
379
mbi->mem_lower = grub_mmap_get_lower () / 1024;
380
mbi->mem_upper = grub_mmap_get_upper () / 1024;
381
mbi->flags |= MULTIBOOT_INFO_MEMORY;
385
mbi->boot_device = bootdev;
386
mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
389
err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
393
grub_errno = GRUB_ERR_NONE;
396
return GRUB_ERR_NONE;
400
grub_multiboot_free_mbi (void)
402
struct module *cur, *next;
411
for (cur = modules; cur; cur = next)
414
grub_free (cur->cmdline);
422
grub_multiboot_init_mbi (int argc, char *argv[])
424
grub_ssize_t len = 0;
428
grub_multiboot_free_mbi ();
430
for (i = 0; i < argc; i++)
431
len += grub_strlen (argv[i]) + 1;
435
cmdline = p = grub_malloc (len);
440
for (i = 0; i < argc; i++)
442
p = grub_stpcpy (p, argv[i]);
446
/* Remove the space after the last word. */
451
return GRUB_ERR_NONE;
455
grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
456
int argc, char *argv[])
458
struct module *newmod;
460
grub_ssize_t len = 0;
463
newmod = grub_malloc (sizeof (*newmod));
466
newmod->start = start;
469
for (i = 0; i < argc; i++)
470
len += grub_strlen (argv[i]) + 1;
475
newmod->cmdline = p = grub_malloc (len);
476
if (! newmod->cmdline)
481
newmod->cmdline_size = len;
482
total_modcmd += ALIGN_UP (len, 4);
484
for (i = 0; i < argc; i++)
486
p = grub_stpcpy (p, argv[i]);
490
/* Remove the space after the last word. */
491
if (p != newmod->cmdline)
496
modules_last->next = newmod;
500
modules_last->next = NULL;
502
modules_last = newmod;
506
return GRUB_ERR_NONE;
510
grub_multiboot_set_bootdev (void)
512
grub_uint32_t biosdev, slice = ~0, part = ~0;
515
#ifdef GRUB_MACHINE_PCBIOS
516
biosdev = grub_get_root_biosnumber ();
518
biosdev = 0xffffffff;
521
if (biosdev == 0xffffffff)
524
dev = grub_device_open (0);
525
if (dev && dev->disk && dev->disk->partition)
527
if (dev->disk->partition->parent)
529
part = dev->disk->partition->number;
530
slice = dev->disk->partition->parent->number;
533
slice = dev->disk->partition->number;
536
grub_device_close (dev);
538
bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16)
539
| ((part & 0xff) << 8) | 0xff;