Merge i386/efi/linux.c into i386/linux.c
This commit is contained in:
parent
ca732b36c1
commit
c8142599fc
2 changed files with 162 additions and 28 deletions
|
@ -79,9 +79,9 @@ struct grub_e820_mmap
|
|||
grub_uint32_t type;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define GRUB_VIDEO_TYPE_TEXT 0x01
|
||||
#define GRUB_VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
|
||||
#define GRUB_VIDEO_TYPE_EFI 0x70
|
||||
#define GRUB_VIDEO_LINUX_TYPE_EGA_TEXT 0x01
|
||||
#define GRUB_VIDEO_LINUX_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
|
||||
#define GRUB_VIDEO_LINUX_TYPE_SIMPLE_LFB 0x70 /* Linear framebuffer without any additional functions. */
|
||||
|
||||
/* For the Linux/i386 boot protocol version 2.03. */
|
||||
struct linux_kernel_header
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <grub/loader.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/memory.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
|
@ -31,11 +32,20 @@
|
|||
#include <grub/video.h>
|
||||
#include <grub/video_fb.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i386/pc/vbe.h>
|
||||
#include <grub/i386/pc/console.h>
|
||||
#include <grub/i386/relocator.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
#include <grub/efi/efi.h>
|
||||
#define HAS_VGA_TEXT 0
|
||||
#define DEFAULT_VIDEO_MODE "800x600"
|
||||
#else
|
||||
#include <grub/i386/pc/vbe.h>
|
||||
#include <grub/i386/pc/console.h>
|
||||
#define HAS_VGA_TEXT 1
|
||||
#define DEFAULT_VIDEO_MODE "text"
|
||||
#endif
|
||||
|
||||
#define GRUB_LINUX_CL_OFFSET 0x1000
|
||||
#define GRUB_LINUX_CL_END_OFFSET 0x2000
|
||||
|
||||
|
@ -53,6 +63,8 @@ static grub_uint32_t real_mode_pages;
|
|||
static grub_uint32_t prot_mode_pages;
|
||||
static grub_uint32_t initrd_pages;
|
||||
static struct grub_relocator *relocator = NULL;
|
||||
static void *efi_mmap_buf;
|
||||
static grub_size_t efi_mmap_size;
|
||||
|
||||
/* FIXME */
|
||||
#if 0
|
||||
|
@ -244,6 +256,48 @@ page_align (grub_size_t size)
|
|||
return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
|
||||
}
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
/* Find the optimal number of pages for the memory map. Is it better to
|
||||
move this code to efi/mm.c? */
|
||||
static grub_efi_uintn_t
|
||||
find_efi_mmap_size (void)
|
||||
{
|
||||
static grub_efi_uintn_t mmap_size = 0;
|
||||
|
||||
if (mmap_size != 0)
|
||||
return mmap_size;
|
||||
|
||||
mmap_size = (1 << 12);
|
||||
while (1)
|
||||
{
|
||||
int ret;
|
||||
grub_efi_memory_descriptor_t *mmap;
|
||||
grub_efi_uintn_t desc_size;
|
||||
|
||||
mmap = grub_malloc (mmap_size);
|
||||
if (! mmap)
|
||||
return 0;
|
||||
|
||||
ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
|
||||
grub_free (mmap);
|
||||
|
||||
if (ret < 0)
|
||||
grub_fatal ("cannot get memory map");
|
||||
else if (ret > 0)
|
||||
break;
|
||||
|
||||
mmap_size += (1 << 12);
|
||||
}
|
||||
|
||||
/* Increase the size a bit for safety, because GRUB allocates more on
|
||||
later, and EFI itself may allocate more. */
|
||||
mmap_size += (1 << 12);
|
||||
|
||||
return page_align (mmap_size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Find the optimal number of pages for the memory map. */
|
||||
static grub_size_t
|
||||
find_mmap_size (void)
|
||||
|
@ -292,12 +346,18 @@ allocate_pages (grub_size_t prot_size)
|
|||
prot_size = page_align (prot_size);
|
||||
mmap_size = find_mmap_size ();
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
efi_mmap_size = find_efi_mmap_size ();
|
||||
#else
|
||||
efi_mmap_size = 0;
|
||||
#endif
|
||||
|
||||
grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
|
||||
(unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
|
||||
|
||||
/* Calculate the number of pages; Combine the real mode code with
|
||||
the memory map buffer for simplicity. */
|
||||
real_mode_pages = ((real_size + mmap_size) >> 12);
|
||||
real_mode_pages = ((real_size + mmap_size + efi_mmap_size) >> 12);
|
||||
prot_mode_pages = (prot_size >> 12);
|
||||
|
||||
/* Initialize the memory pointers with NULL for convenience. */
|
||||
|
@ -330,10 +390,10 @@ allocate_pages (grub_size_t prot_size)
|
|||
if (addr + size > 0x90000)
|
||||
size = 0x90000 - addr;
|
||||
|
||||
if (real_size + mmap_size > size)
|
||||
if (real_size + mmap_size + efi_mmap_size > size)
|
||||
return 0;
|
||||
|
||||
real_mode_target = ((addr + size) - (real_size + mmap_size));
|
||||
real_mode_target = ((addr + size) - (real_size + mmap_size + efi_mmap_size));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -348,11 +408,13 @@ allocate_pages (grub_size_t prot_size)
|
|||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &real_mode_mem,
|
||||
real_mode_target,
|
||||
(real_size + mmap_size));
|
||||
(real_size + mmap_size
|
||||
+ efi_mmap_size));
|
||||
if (err)
|
||||
goto fail;
|
||||
efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size;
|
||||
|
||||
prot_mode_target = 0x100000;
|
||||
prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR;
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &prot_mode_mem,
|
||||
prot_mode_target, prot_size);
|
||||
|
@ -393,17 +455,28 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static grub_err_t
|
||||
grub_linux_setup_video (struct linux_kernel_params *params)
|
||||
{
|
||||
struct grub_video_mode_info mode_info;
|
||||
void *framebuffer;
|
||||
int ret;
|
||||
grub_err_t err;
|
||||
|
||||
ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
|
||||
switch (grub_video_get_driver_id ())
|
||||
{
|
||||
case GRUB_VIDEO_DRIVER_VBE:
|
||||
params->have_vga = GRUB_VIDEO_LINUX_TYPE_VLFB;
|
||||
break;
|
||||
|
||||
if (ret)
|
||||
return 1;
|
||||
default:
|
||||
params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE_LFB;
|
||||
break;
|
||||
}
|
||||
|
||||
err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
params->lfb_width = mode_info.width;
|
||||
params->lfb_height = mode_info.height;
|
||||
|
@ -449,7 +522,7 @@ grub_linux_setup_video (struct linux_kernel_params *params)
|
|||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
@ -520,15 +593,15 @@ grub_linux_boot (void)
|
|||
if (modevar && *modevar != 0)
|
||||
{
|
||||
tmp = grub_malloc (grub_strlen (modevar)
|
||||
+ sizeof (";text"));
|
||||
+ sizeof (";" DEFAULT_VIDEO_MODE));
|
||||
if (! tmp)
|
||||
return grub_errno;
|
||||
grub_sprintf (tmp, "%s;text", modevar);
|
||||
grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
|
||||
err = grub_video_set_mode (tmp, 0);
|
||||
grub_free (tmp);
|
||||
}
|
||||
else
|
||||
err = grub_video_set_mode ("text", 0);
|
||||
err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0);
|
||||
|
||||
if (err)
|
||||
{
|
||||
|
@ -537,17 +610,26 @@ grub_linux_boot (void)
|
|||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (! grub_linux_setup_video (params))
|
||||
params->have_vga = GRUB_VIDEO_TYPE_VLFB;
|
||||
else
|
||||
err = grub_linux_setup_video (params);
|
||||
if (err)
|
||||
{
|
||||
params->have_vga = GRUB_VIDEO_TYPE_TEXT;
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
#if HAS_VGA_TEXT
|
||||
params->have_vga = GRUB_VIDEO_LINUX_TYPE_EGA_TEXT;
|
||||
params->video_mode = 0x3;
|
||||
params->video_width = 80;
|
||||
params->video_height = 25;
|
||||
#else
|
||||
params->have_vga = 0;
|
||||
params->video_mode = 0;
|
||||
params->video_width = 0;
|
||||
params->video_height = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Initialize these last, because terminal position could be affected by printfs above. */
|
||||
if (params->have_vga == GRUB_VIDEO_TYPE_TEXT)
|
||||
if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_EGA_TEXT)
|
||||
{
|
||||
grub_term_output_t term;
|
||||
int found = 0;
|
||||
|
@ -568,6 +650,40 @@ grub_linux_boot (void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
{
|
||||
grub_efi_uintn_t efi_map_key, efi_desc_size;
|
||||
grub_efi_uint32_t efi_desc_version;
|
||||
if (grub_efi_get_memory_map (&efi_mmap_size, efi_mmap_buf, &efi_map_key,
|
||||
&efi_desc_size, &efi_desc_version) <= 0)
|
||||
grub_fatal ("cannot get memory map");
|
||||
|
||||
if (! grub_efi_exit_boot_services (efi_map_key))
|
||||
grub_fatal ("cannot exit boot services");
|
||||
|
||||
/* Note that no boot services are available from here. */
|
||||
|
||||
/* Pass EFI parameters. */
|
||||
if (grub_le_to_cpu16 (params->version) >= 0x0206)
|
||||
{
|
||||
params->v0206.efi_mem_desc_size = efi_desc_size;
|
||||
params->v0206.efi_mem_desc_version = efi_desc_version;
|
||||
params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf;
|
||||
params->v0206.efi_mmap_size = efi_mmap_size;
|
||||
#ifdef __x86_64__
|
||||
params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) efi_mmap_buf >> 32);
|
||||
#endif
|
||||
}
|
||||
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
|
||||
{
|
||||
params->v0204.efi_mem_desc_size = efi_desc_size;
|
||||
params->v0204.efi_mem_desc_version = efi_desc_version;
|
||||
params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf;
|
||||
params->v0204.efi_mmap_size = efi_mmap_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME. */
|
||||
/* asm volatile ("lidt %0" : : "m" (idt_desc)); */
|
||||
state.ebx = 0;
|
||||
|
@ -675,7 +791,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
/* XXX Linux assumes that only elilo can boot Linux on EFI!!! */
|
||||
params->type_of_loader = (LINUX_LOADER_ID_ELILO << 4);
|
||||
#else
|
||||
params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
|
||||
#endif
|
||||
|
||||
/* These two are used (instead of cmd_line_ptr) by older versions of Linux,
|
||||
and otherwise ignored. */
|
||||
|
@ -698,14 +819,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
/* Ignored by Linux. */
|
||||
params->video_page = 0;
|
||||
|
||||
/* Must be non-zero even in text mode, or Linux will think there's no VGA. */
|
||||
params->video_mode = 0x3;
|
||||
|
||||
/* Only used when `video_mode == 0x7', otherwise ignored. */
|
||||
params->video_ega_bx = 0;
|
||||
|
||||
params->font_size = 16; /* XXX */
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
if (grub_le_to_cpu16 (params->version) >= 0x0206)
|
||||
{
|
||||
params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
|
||||
params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
|
||||
#ifdef __x86_64__
|
||||
params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
|
||||
#endif
|
||||
}
|
||||
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
|
||||
{
|
||||
params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
|
||||
params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The other parameters are filled when booting. */
|
||||
|
||||
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
|
||||
|
@ -859,7 +993,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
len = prot_size;
|
||||
if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
|
||||
if (grub_file_read (file, prot_mode_mem, len) != len)
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
|
|
Loading…
Reference in a new issue