Tagged header support
This commit is contained in:
parent
b1f6f35ae9
commit
c3a8dfc8b7
5 changed files with 225 additions and 5 deletions
|
@ -70,7 +70,8 @@ grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info,
|
||||||
|
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_multiboot_set_console (int console_type, int accepted_consoles,
|
grub_multiboot_set_console (int console_type, int accepted_consoles,
|
||||||
int width, int height, int depth);
|
int width, int height, int depth,
|
||||||
|
int console_required);
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_multiboot_load (grub_file_t file);
|
grub_multiboot_load (grub_file_t file);
|
||||||
/* Load ELF32 or ELF64. */
|
/* Load ELF32 or ELF64. */
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||||
#define MULTIBOOT_TAG_TYPE_VBE 7
|
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||||
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
||||||
|
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
|
||||||
|
#define MULTIBOOT_TAG_TYPE_APM 10
|
||||||
|
|
||||||
#define MULTIBOOT_HEADER_TAG_END 0
|
#define MULTIBOOT_HEADER_TAG_END 0
|
||||||
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||||
|
@ -74,6 +76,9 @@
|
||||||
#define GRUB_MULTIBOOT_ARCHITECTURE_I386 0
|
#define GRUB_MULTIBOOT_ARCHITECTURE_I386 0
|
||||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||||
|
|
||||||
|
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||||
|
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||||
|
|
||||||
#ifndef ASM_FILE
|
#ifndef ASM_FILE
|
||||||
|
|
||||||
typedef unsigned char multiboot_uint8_t;
|
typedef unsigned char multiboot_uint8_t;
|
||||||
|
|
|
@ -62,6 +62,8 @@ grub_addr_t grub_multiboot_payload_dest;
|
||||||
grub_size_t grub_multiboot_pure_size;
|
grub_size_t grub_multiboot_pure_size;
|
||||||
grub_uint32_t grub_multiboot_payload_eip;
|
grub_uint32_t grub_multiboot_payload_eip;
|
||||||
static int accepts_video;
|
static int accepts_video;
|
||||||
|
static int accepts_ega_text;
|
||||||
|
static int console_required;
|
||||||
static grub_dl_t my_mod;
|
static grub_dl_t my_mod;
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,8 +247,23 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer)
|
||||||
|
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_multiboot_set_console (int console_type, int accepted_consoles,
|
grub_multiboot_set_console (int console_type, int accepted_consoles,
|
||||||
int width, int height, int depth)
|
int width, int height, int depth,
|
||||||
|
int console_req)
|
||||||
{
|
{
|
||||||
|
console_required = console_req;
|
||||||
|
if (!(accepted_consoles
|
||||||
|
& (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER
|
||||||
|
| (GRUB_MACHINE_HAS_VGA_TEXT ? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT : 0))))
|
||||||
|
{
|
||||||
|
if (console_required)
|
||||||
|
return grub_error (GRUB_ERR_BAD_OS,
|
||||||
|
"OS requires a console but none is available");
|
||||||
|
grub_printf ("WARNING: no console will be available to OS");
|
||||||
|
accepts_video = 0;
|
||||||
|
accepts_ega_text = 0;
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER)
|
if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
|
@ -267,6 +284,7 @@ grub_multiboot_set_console (int console_type, int accepted_consoles,
|
||||||
grub_env_set ("gfxpayload", "text");
|
grub_env_set ("gfxpayload", "text");
|
||||||
|
|
||||||
accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER);
|
accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER);
|
||||||
|
accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,21 +161,21 @@ grub_multiboot_load (grub_file_t file)
|
||||||
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
||||||
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||||
0, 0, 0);
|
0, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
||||||
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||||
header->width, header->height,
|
header->width, header->height,
|
||||||
header->depth);
|
header->depth, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||||
0, 0, 0);
|
0, 0, 0, 0);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include <grub/multiboot.h>
|
#include <grub/multiboot.h>
|
||||||
#include <grub/cpu/multiboot.h>
|
#include <grub/cpu/multiboot.h>
|
||||||
|
#include <grub/cpu/relocator.h>
|
||||||
#include <grub/disk.h>
|
#include <grub/disk.h>
|
||||||
#include <grub/device.h>
|
#include <grub/device.h>
|
||||||
#include <grub/partition.h>
|
#include <grub/partition.h>
|
||||||
|
@ -59,6 +60,201 @@ static char *cmdline = NULL;
|
||||||
static int bootdev_set;
|
static int bootdev_set;
|
||||||
static grub_uint32_t biosdev, slice, part;
|
static grub_uint32_t biosdev, slice, part;
|
||||||
|
|
||||||
|
grub_err_t
|
||||||
|
grub_multiboot_load (grub_file_t file)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
grub_ssize_t len;
|
||||||
|
struct multiboot_header *header;
|
||||||
|
grub_err_t err;
|
||||||
|
struct multiboot_header_tag *tag;
|
||||||
|
struct multiboot_header_tag_address *addr_tag = NULL;
|
||||||
|
int entry_specified = 0;
|
||||||
|
grub_addr_t entry = 0;
|
||||||
|
grub_uint32_t console_required = 0;
|
||||||
|
struct multiboot_header_tag_framebuffer *fbtag = NULL;
|
||||||
|
int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
|
||||||
|
|
||||||
|
buffer = grub_malloc (MULTIBOOT_SEARCH);
|
||||||
|
if (!buffer)
|
||||||
|
return grub_errno;
|
||||||
|
|
||||||
|
len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
|
||||||
|
if (len < 32)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_error (GRUB_ERR_BAD_OS, "file too small");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for the multiboot header in the buffer. The header should
|
||||||
|
be at least 12 bytes and aligned on a 4-byte boundary. */
|
||||||
|
for (header = (struct multiboot_header *) buffer;
|
||||||
|
((char *) header <= buffer + len - 12) || (header = 0);
|
||||||
|
header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
|
||||||
|
{
|
||||||
|
if (header->magic == MULTIBOOT_HEADER_MAGIC
|
||||||
|
&& !(header->magic + header->architecture
|
||||||
|
+ header->header_length + header->checksum))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header == 0)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tag = (struct multiboot_header_tag *) (header + 1);
|
||||||
|
tag->type != MULTIBOOT_TAG_TYPE_END;
|
||||||
|
tag = (struct multiboot_header_tag *) ((char *) tag + tag->size))
|
||||||
|
switch (tag->type)
|
||||||
|
{
|
||||||
|
case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
struct multiboot_header_tag_information_request *request_tag
|
||||||
|
= (struct multiboot_header_tag_information_request *) tag;
|
||||||
|
if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
|
||||||
|
break;
|
||||||
|
for (i = 0; i < (request_tag->size - sizeof (request_tag))
|
||||||
|
/ sizeof (request_tag->requests[0]); i++)
|
||||||
|
switch (request_tag->requests[i])
|
||||||
|
{
|
||||||
|
case MULTIBOOT_TAG_TYPE_END:
|
||||||
|
case MULTIBOOT_TAG_TYPE_CMDLINE:
|
||||||
|
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
|
||||||
|
case MULTIBOOT_TAG_TYPE_MODULE:
|
||||||
|
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
|
||||||
|
case MULTIBOOT_TAG_TYPE_BOOTDEV:
|
||||||
|
case MULTIBOOT_TAG_TYPE_MMAP:
|
||||||
|
case MULTIBOOT_TAG_TYPE_VBE:
|
||||||
|
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
|
||||||
|
case MULTIBOOT_TAG_TYPE_APM:
|
||||||
|
default:
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_error (GRUB_ERR_UNKNOWN_OS,
|
||||||
|
"unsupported information tag: 0x%x",
|
||||||
|
request_tag->requests[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MULTIBOOT_HEADER_TAG_ADDRESS:
|
||||||
|
addr_tag = (struct multiboot_header_tag_address *) tag;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
|
||||||
|
entry_specified = 1;
|
||||||
|
entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
|
||||||
|
if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
|
||||||
|
& MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
|
||||||
|
accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
|
||||||
|
if (((struct multiboot_header_tag_console_flags *) tag)->console_flags
|
||||||
|
& MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED)
|
||||||
|
console_required = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
|
||||||
|
fbtag = (struct multiboot_header_tag_framebuffer *) tag;
|
||||||
|
accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* GRUB always page-aligns modules. */
|
||||||
|
case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL))
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_error (GRUB_ERR_UNKNOWN_OS,
|
||||||
|
"unsupported tag: 0x%x", tag->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_tag && !entry_specified)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_error (GRUB_ERR_UNKNOWN_OS,
|
||||||
|
"load address tag without entry address tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_tag)
|
||||||
|
{
|
||||||
|
int offset = ((char *) header - buffer -
|
||||||
|
(addr_tag->header_addr - addr_tag->load_addr));
|
||||||
|
int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset :
|
||||||
|
addr_tag->load_end_addr - addr_tag->load_addr);
|
||||||
|
grub_size_t code_size;
|
||||||
|
|
||||||
|
if (addr_tag->bss_end_addr)
|
||||||
|
code_size = (addr_tag->bss_end_addr - addr_tag->load_addr);
|
||||||
|
else
|
||||||
|
code_size = load_size;
|
||||||
|
grub_multiboot_payload_dest = addr_tag->load_addr;
|
||||||
|
|
||||||
|
grub_multiboot_pure_size += code_size;
|
||||||
|
|
||||||
|
/* Allocate a bit more to avoid relocations in most cases. */
|
||||||
|
grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536;
|
||||||
|
grub_multiboot_payload_orig
|
||||||
|
= grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi);
|
||||||
|
|
||||||
|
if (! grub_multiboot_payload_orig)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
|
||||||
|
if (grub_errno)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_tag->bss_end_addr)
|
||||||
|
grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
|
||||||
|
addr_tag->bss_end_addr - addr_tag->load_addr - load_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = grub_multiboot_load_elf (file, buffer);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
grub_free (buffer);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry_specified)
|
||||||
|
grub_multiboot_payload_eip = entry;
|
||||||
|
|
||||||
|
if (fbtag)
|
||||||
|
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||||
|
accepted_consoles,
|
||||||
|
fbtag->width, fbtag->height,
|
||||||
|
fbtag->depth, console_required);
|
||||||
|
else
|
||||||
|
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||||
|
accepted_consoles,
|
||||||
|
0, 0, 0, console_required);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
grub_size_t
|
grub_size_t
|
||||||
grub_multiboot_get_mbi_size (void)
|
grub_multiboot_get_mbi_size (void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue