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_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_multiboot_load (grub_file_t file);
|
||||
/* Load ELF32 or ELF64. */
|
||||
|
|
|
@ -62,6 +62,8 @@
|
|||
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||
#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_INFORMATION_REQUEST 1
|
||||
|
@ -74,6 +76,9 @@
|
|||
#define GRUB_MULTIBOOT_ARCHITECTURE_I386 0
|
||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
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_uint32_t grub_multiboot_payload_eip;
|
||||
static int accepts_video;
|
||||
static int accepts_ega_text;
|
||||
static int console_required;
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
|
||||
|
@ -245,8 +247,23 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer)
|
|||
|
||||
grub_err_t
|
||||
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)
|
||||
{
|
||||
char *buf;
|
||||
|
@ -267,6 +284,7 @@ grub_multiboot_set_console (int console_type, int accepted_consoles,
|
|||
grub_env_set ("gfxpayload", "text");
|
||||
|
||||
accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER);
|
||||
accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT);
|
||||
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,
|
||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
||||
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||
0, 0, 0);
|
||||
0, 0, 0, 0);
|
||||
break;
|
||||
case 0:
|
||||
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
|
||||
| GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
|
||||
header->width, header->height,
|
||||
header->depth);
|
||||
header->depth, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||
GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
|
||||
0, 0, 0);
|
||||
0, 0, 0, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
#include <grub/multiboot.h>
|
||||
#include <grub/cpu/multiboot.h>
|
||||
#include <grub/cpu/relocator.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/partition.h>
|
||||
|
@ -59,6 +60,201 @@ static char *cmdline = NULL;
|
|||
static int bootdev_set;
|
||||
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_multiboot_get_mbi_size (void)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue