Compare commits

...

1 Commits

Author SHA1 Message Date
Vladimir Serbinenko
d69064ad50 Some scribbles on EFI compression 2013-11-20 00:51:03 +01:00
12 changed files with 391 additions and 170 deletions

View File

@@ -163,6 +163,7 @@ kernel = {
efi = disk/efi/efidisk.c;
efi = kern/efi/efi.c;
efi = kern/efi/efi_core.c;
efi = kern/efi/init.c;
efi = kern/efi/mm.c;
efi = term/efi/console.c;
@@ -416,12 +417,22 @@ image = {
image = {
name = xz_decompress;
ia64_efi = kern/ia64/efi/startup.S;
i386_efi = kern/i386/efi/startup.S;
x86_64_efi = kern/x86_64/efi/startup.S;
arm_efi = kern/arm/efi/startup.S;
mips = boot/mips/startup_raw.S;
mips = boot/mips/scratch.c;
common = boot/decompressor/minilib.c;
common = boot/decompressor/xz.c;
common = lib/xzembed/xz_dec_bcj.c;
common = lib/xzembed/xz_dec_lzma2.c;
common = lib/xzembed/xz_dec_stream.c;
efi = boot/efi/decompressor.c;
efi = kern/efi/efi_core.c;
x86_64_efi = kern/x86_64/efi/callwrap.S;
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1';
@@ -430,6 +441,7 @@ image = {
ldadd = '$(TARGET_LIBGCC)';
cflags = '-Wno-unreachable-code $(TARGET_LDFLAGS_STATIC_LIBGCC)';
enable = mips;
enable = efi;
};
image = {

View File

@@ -79,24 +79,3 @@ void *memcpy (void *dest, const void *src, grub_size_t n)
void *grub_decompressor_scratch;
void
find_scratch (void *src, void *dst, unsigned long srcsize,
unsigned long dstsize)
{
#ifdef _mips
/* Decoding from ROM. */
if (((grub_addr_t) src & 0x10000000))
{
grub_decompressor_scratch = (void *) ALIGN_UP((grub_addr_t) dst + dstsize,
256);
return;
}
#endif
if ((char *) src + srcsize > (char *) dst + dstsize)
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) src + srcsize,
256);
else
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) dst + dstsize,
256);
return;
}

View File

@@ -0,0 +1,34 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/decompressor.h>
void
find_scratch (void *src, void *dst, unsigned long srcsize,
unsigned long dstsize)
{
if ((char *) src + srcsize > (char *) dst + dstsize)
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) src + srcsize,
256);
else
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) dst + dstsize,
256);
return;
}

View File

@@ -0,0 +1,116 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/kernel.h>
#include <grub/efi/efi.h>
#include <grub/decompressor.h>
/* The handle of GRUB itself. Filled in by the startup code. */
grub_efi_handle_t grub_efi_image_handle;
/* The pointer to a system table. Filled in by the startup code. */
grub_efi_system_table_t *grub_efi_system_table;
int
grub_strcmp (const char *s1, const char *s2)
{
while (*s1 && *s2)
{
if (*s1 != *s2)
break;
s1++;
s2++;
}
return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2;
}
static grub_size_t unc_pages, scratch_pages;
static void *unc;
void
grub_efi_fini (void)
{
if (unc)
grub_efi_free_pages ((grub_addr_t) unc, unc_pages);
if (grub_decompressor_scratch)
grub_efi_free_pages ((grub_addr_t) grub_decompressor_scratch,
scratch_pages);
}
void
find_scratch (void *src __attribute__ ((unused)),
void *dst __attribute__ ((unused)),
unsigned long srcsize __attribute__ ((unused)),
unsigned long dstsize __attribute__ ((unused)))
{
}
void __attribute__ ((noreturn))
grub_main (void)
{
grub_addr_t start;
grub_size_t sz;
grub_addr_t unc_size;
grub_efi_boot_services_t *b;
grub_efi_status_t status;
grub_efi_uintn_t exit_data_size;
grub_efi_char16_t *exit_data = 0;
grub_efi_handle_t image_handle;
grub_efi_loaded_image_t *image;
b = grub_efi_system_table->boot_services;
if (!grub_efi_get_section ("payload", &start, &sz)
|| sz < 12)
grub_exit ();
if (grub_memcmp ((void *) start, "COMPRESS", 8) != 0)
grub_exit ();
unc_size = grub_get_unaligned32 ((char *) start + 8);
unc_pages = (unc_size + 0xfff) >> 12;
unc = grub_efi_allocate_pages (0, unc_pages);
if (!unc)
grub_exit ();
scratch_pages = 0x200000 >> 12;
grub_decompressor_scratch = grub_efi_allocate_pages (0, scratch_pages);
if (!grub_decompressor_scratch)
grub_exit ();
grub_decompress_core ((char *) start + 12, unc, sz - 12,
unc_size);
image = grub_efi_get_loaded_image (grub_efi_image_handle);
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle,
image->file_path, unc, unc_size, &image_handle);
if (status != GRUB_EFI_SUCCESS)
efi_call_4 (grub_efi_system_table->boot_services->exit,
grub_efi_image_handle, status, 0, 0);
status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
efi_call_4 (grub_efi_system_table->boot_services->exit,
grub_efi_image_handle, status, exit_data_size, exit_data);
grub_exit ();
}

View File

@@ -0,0 +1,42 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/decompressor.h>
void
find_scratch (void *src, void *dst, unsigned long srcsize,
unsigned long dstsize)
{
/* Decoding from ROM. */
if (((grub_addr_t) src & 0x10000000))
{
grub_decompressor_scratch = (void *) ALIGN_UP((grub_addr_t) dst + dstsize,
256);
return;
}
if ((char *) src + srcsize > (char *) dst + dstsize)
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) src + srcsize,
256);
else
grub_decompressor_scratch = (void *) ALIGN_UP ((grub_addr_t) dst + dstsize,
256);
return;
}

View File

@@ -35,7 +35,6 @@ grub_efi_handle_t grub_efi_image_handle;
grub_efi_system_table_t *grub_efi_system_table;
static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
void *
@@ -94,28 +93,6 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
return buffer;
}
void *
grub_efi_open_protocol (grub_efi_handle_t handle,
grub_efi_guid_t *protocol,
grub_efi_uint32_t attributes)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
void *interface;
b = grub_efi_system_table->boot_services;
status = efi_call_6 (b->open_protocol, handle,
protocol,
&interface,
grub_efi_image_handle,
0,
attributes);
if (status != GRUB_EFI_SUCCESS)
return 0;
return interface;
}
int
grub_efi_set_text_mode (int on)
{
@@ -145,23 +122,6 @@ grub_efi_stall (grub_efi_uintn_t microseconds)
efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds);
}
grub_efi_loaded_image_t *
grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
{
return grub_efi_open_protocol (image_handle,
&loaded_image_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
}
void
grub_exit (void)
{
grub_efi_fini ();
efi_call_4 (grub_efi_system_table->boot_services->exit,
grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
for (;;) ;
}
grub_err_t
grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
grub_efi_uintn_t descriptor_size,
@@ -259,53 +219,6 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return NULL;
}
#pragma GCC diagnostic ignored "-Wcast-align"
/* Search the mods section from the PE32/PE32+ image. This code uses
a PE32 header, but should work with PE32+ as well. */
grub_addr_t
grub_efi_modules_addr (void)
{
grub_efi_loaded_image_t *image;
struct grub_pe32_header *header;
struct grub_pe32_coff_header *coff_header;
struct grub_pe32_section_table *sections;
struct grub_pe32_section_table *section;
struct grub_module_info *info;
grub_uint16_t i;
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (! image)
return 0;
header = image->image_base;
coff_header = &(header->coff_header);
sections
= (struct grub_pe32_section_table *) ((char *) coff_header
+ sizeof (*coff_header)
+ coff_header->optional_header_size);
for (i = 0, section = sections;
i < coff_header->num_sections;
i++, section++)
{
if (grub_strcmp (section->name, "mods") == 0)
break;
}
if (i == coff_header->num_sections)
return 0;
info = (struct grub_module_info *) ((char *) image->image_base
+ section->virtual_address);
if (info->magic != GRUB_MODULE_MAGIC)
return 0;
return (grub_addr_t) info;
}
#pragma GCC diagnostic error "-Wcast-align"
char *
grub_efi_get_filename (grub_efi_device_path_t *dp0)
{

View File

@@ -0,0 +1,172 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2009,2010,2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/efi/efi.h>
#include <grub/efi/pe32.h>
static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
void *
grub_efi_open_protocol (grub_efi_handle_t handle,
grub_efi_guid_t *protocol,
grub_efi_uint32_t attributes)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
void *interface;
b = grub_efi_system_table->boot_services;
status = efi_call_6 (b->open_protocol, handle,
protocol,
&interface,
grub_efi_image_handle,
0,
attributes);
if (status != GRUB_EFI_SUCCESS)
return 0;
return interface;
}
void
grub_exit (void)
{
grub_efi_fini ();
efi_call_4 (grub_efi_system_table->boot_services->exit,
grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
for (;;) ;
}
grub_efi_loaded_image_t *
grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
{
return grub_efi_open_protocol (image_handle,
&loaded_image_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
}
/* Allocate pages. Return the pointer to the first of allocated pages. */
void *
grub_efi_allocate_pages (grub_efi_physical_address_t address,
grub_efi_uintn_t pages)
{
grub_efi_allocate_type_t type;
grub_efi_status_t status;
grub_efi_boot_services_t *b;
#if 1
/* Limit the memory access to less than 4GB for 32-bit platforms. */
if (address > 0xffffffff)
return 0;
#endif
#if 1
if (address == 0)
{
type = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
address = 0xffffffff;
}
else
type = GRUB_EFI_ALLOCATE_ADDRESS;
#else
if (address == 0)
type = GRUB_EFI_ALLOCATE_ANY_PAGES;
else
type = GRUB_EFI_ALLOCATE_ADDRESS;
#endif
b = grub_efi_system_table->boot_services;
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
if (status != GRUB_EFI_SUCCESS)
return 0;
if (address == 0)
{
/* Uggh, the address 0 was allocated... This is too annoying,
so reallocate another one. */
address = 0xffffffff;
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
grub_efi_free_pages (0, pages);
if (status != GRUB_EFI_SUCCESS)
return 0;
}
return (void *) ((grub_addr_t) address);
}
/* Free pages starting from ADDRESS. */
void
grub_efi_free_pages (grub_efi_physical_address_t address,
grub_efi_uintn_t pages)
{
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
efi_call_2 (b->free_pages, address, pages);
}
#pragma GCC diagnostic ignored "-Wcast-align"
/* Search the mods section from the PE32/PE32+ image. This code uses
a PE32 header, but should work with PE32+ as well. */
int
grub_efi_get_section (const char *name,
grub_addr_t *start, grub_size_t *sz)
{
grub_efi_loaded_image_t *image;
struct grub_pe32_header *header;
struct grub_pe32_coff_header *coff_header;
struct grub_pe32_section_table *sections;
struct grub_pe32_section_table *section;
grub_uint16_t i;
*start = 0;
if (sz)
*sz = 0;
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (! image)
return 0;
header = image->image_base;
coff_header = &(header->coff_header);
sections
= (struct grub_pe32_section_table *) ((char *) coff_header
+ sizeof (*coff_header)
+ coff_header->optional_header_size);
for (i = 0, section = sections;
i < coff_header->num_sections;
i++, section++)
{
if (grub_strcmp (section->name, name) == 0)
break;
}
if (i == coff_header->num_sections)
return 0;
*start = ((grub_addr_t) image->image_base + section->virtual_address);
if (sz)
*sz = section->virtual_size;
return 1;
}
#pragma GCC diagnostic error "-Wcast-align"

View File

@@ -31,7 +31,10 @@ grub_addr_t grub_modbase;
void
grub_efi_init (void)
{
grub_modbase = grub_efi_modules_addr ();
if (!grub_efi_get_section ("mods", &grub_modbase, NULL)
|| ((struct grub_module_info *) grub_modbase)->magic != GRUB_MODULE_MAGIC)
grub_modbase = 0;
/* First of all, initialize the console so that GRUB can display
messages. */
grub_console_init ();

View File

@@ -47,66 +47,6 @@ static grub_efi_uintn_t finish_desc_size;
static grub_efi_uint32_t finish_desc_version;
int grub_efi_is_finished = 0;
/* Allocate pages. Return the pointer to the first of allocated pages. */
void *
grub_efi_allocate_pages (grub_efi_physical_address_t address,
grub_efi_uintn_t pages)
{
grub_efi_allocate_type_t type;
grub_efi_status_t status;
grub_efi_boot_services_t *b;
#if 1
/* Limit the memory access to less than 4GB for 32-bit platforms. */
if (address > 0xffffffff)
return 0;
#endif
#if 1
if (address == 0)
{
type = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
address = 0xffffffff;
}
else
type = GRUB_EFI_ALLOCATE_ADDRESS;
#else
if (address == 0)
type = GRUB_EFI_ALLOCATE_ANY_PAGES;
else
type = GRUB_EFI_ALLOCATE_ADDRESS;
#endif
b = grub_efi_system_table->boot_services;
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
if (status != GRUB_EFI_SUCCESS)
return 0;
if (address == 0)
{
/* Uggh, the address 0 was allocated... This is too annoying,
so reallocate another one. */
address = 0xffffffff;
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
grub_efi_free_pages (0, pages);
if (status != GRUB_EFI_SUCCESS)
return 0;
}
return (void *) ((grub_addr_t) address);
}
/* Free pages starting from ADDRESS. */
void
grub_efi_free_pages (grub_efi_physical_address_t address,
grub_efi_uintn_t pages)
{
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
efi_call_2 (b->free_pages, address, pages);
}
#if defined (__i386__) || defined (__x86_64__)
/* Helper for stop_broadcom. */

View File

@@ -22,6 +22,8 @@
#include <grub/mm.h>
#include <grub/misc.h>
#ifndef GRUB_EMBED_DECOMPRESSOR
static inline void
free (void *ptr)
{
@@ -46,6 +48,8 @@ realloc (void *ptr, grub_size_t size)
return grub_realloc (ptr, size);
}
#endif
static inline int
abs (int c)
{

View File

@@ -91,6 +91,10 @@ enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2, struct xz_buf *b);
/* Free the memory allocated for the BCJ filters. */
#ifndef GRUB_EMBED_DECOMPRESSOR
#define xz_dec_bcj_end(s) kfree(s)
#else
#define xz_dec_bcj_end(s)
#endif
#endif

View File

@@ -77,7 +77,9 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
char **device,
char **path);
grub_addr_t grub_efi_modules_addr (void);
int
grub_efi_get_section (const char *name,
grub_addr_t *start, grub_size_t *sz);
void grub_efi_mm_init (void);
void grub_efi_mm_fini (void);