On 20.07.2015 16:35, Daniel Kiper wrote:
> Add grub_relocator64_efi relocator. It will be used on EFI 64-bit platforms
> when multiboot2 compatible image requests MULTIBOOT_TAG_TYPE_EFI_BS. Relocator
> will set lower parts of %rax and %rbx accordingly to multiboot2 specification.
> On the other hand processor mode, just before jumping into loaded image, will
> be set accordingly to Unified Extensible Firmware Interface Specification,
> Version 2.4 Errata B, section 2.3.4, x64 Platforms, boot services. This way
> loaded image will be able to use EFI boot services without any issues.
> 
> If idea is accepted I will prepare grub_relocator32_efi relocator too.
> 
> Signed-off-by: Daniel Kiper <daniel.ki...@oracle.com>
> ---
>  grub-core/Makefile.core.def          |    1 +
>  grub-core/lib/i386/relocator.c       |   53 +++++++++++++++++++++++
>  grub-core/lib/i386/relocator64_efi.S |   77 
> ++++++++++++++++++++++++++++++++++
>  grub-core/loader/multiboot.c         |   29 +++++++++++--
>  grub-core/loader/multiboot_mbi2.c    |   19 +++++++--
>  include/grub/i386/multiboot.h        |   11 +++++
>  include/grub/i386/relocator.h        |   21 ++++++++++
>  include/multiboot2.h                 |    9 ++++
>  8 files changed, 213 insertions(+), 7 deletions(-)
>  create mode 100644 grub-core/lib/i386/relocator64_efi.S
> 
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index a6101de..d583549 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -1519,6 +1519,7 @@ module = {
>    x86 = lib/i386/relocator_common_c.c;
>    ieee1275 = lib/ieee1275/relocator.c;
>    efi = lib/efi/relocator.c;
> +  x86_64_efi = lib/i386/relocator64_efi.S;
>    mips = lib/mips/relocator_asm.S;
>    mips = lib/mips/relocator.c;
>    powerpc = lib/powerpc/relocator_asm.S;
> diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c
> index 71dd4f0..459027e 100644
> --- a/grub-core/lib/i386/relocator.c
> +++ b/grub-core/lib/i386/relocator.c
> @@ -69,6 +69,19 @@ extern grub_uint64_t grub_relocator64_rsi;
>  extern grub_addr_t grub_relocator64_cr3;
>  extern struct grub_i386_idt grub_relocator16_idt;
>  
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +extern grub_uint8_t grub_relocator64_efi_start;
> +extern grub_uint8_t grub_relocator64_efi_end;
> +extern grub_uint64_t grub_relocator64_efi_rax;
> +extern grub_uint64_t grub_relocator64_efi_rbx;
> +extern grub_uint64_t grub_relocator64_efi_rcx;
> +extern grub_uint64_t grub_relocator64_efi_rdx;
> +extern grub_uint64_t grub_relocator64_efi_rip;
> +extern grub_uint64_t grub_relocator64_efi_rsi;
> +#endif
> +#endif
> +
>  #define RELOCATOR_SIZEOF(x)  (&grub_relocator##x##_end - 
> &grub_relocator##x##_start)
>  
>  grub_err_t
> @@ -214,3 +227,43 @@ grub_relocator64_boot (struct grub_relocator *rel,
>    /* Not reached.  */
>    return GRUB_ERR_NONE;
>  }
> +
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +grub_err_t
> +grub_relocator64_efi_boot (struct grub_relocator *rel,
> +                        struct grub_relocator64_efi_state state)
> +{
> +  grub_err_t err;
> +  void *relst;
> +  grub_relocator_chunk_t ch;
> +
> +  err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
> +                                       0x40000000 - RELOCATOR_SIZEOF 
> (64_efi),
> +                                       RELOCATOR_SIZEOF (64_efi), 16,
> +                                       GRUB_RELOCATOR_PREFERENCE_NONE, 1);
> +  if (err)
> +    return err;
> +
> +  grub_relocator64_efi_rax = state.rax;
> +  grub_relocator64_efi_rbx = state.rbx;
> +  grub_relocator64_efi_rcx = state.rcx;
> +  grub_relocator64_efi_rdx = state.rdx;
> +  grub_relocator64_efi_rip = state.rip;
> +  grub_relocator64_efi_rsi = state.rsi;
> +
> +  grub_memmove (get_virtual_current_address (ch), 
> &grub_relocator64_efi_start,
> +             RELOCATOR_SIZEOF (64_efi));
> +
> +  err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
> +                                    &relst, NULL);
> +  if (err)
> +    return err;
> +
> +  ((void (*) (void)) relst) ();
> +
> +  /* Not reached.  */
> +  return GRUB_ERR_NONE;
> +}
> +#endif
> +#endif
> diff --git a/grub-core/lib/i386/relocator64_efi.S 
> b/grub-core/lib/i386/relocator64_efi.S
> new file mode 100644
> index 0000000..fcd1964
> --- /dev/null
> +++ b/grub-core/lib/i386/relocator64_efi.S
> @@ -0,0 +1,77 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2009,2010  Free Software Foundation, Inc.
> + *  Copyright (C) 2014,2015  Oracle Co.
> + *      Author: Daniel Kiper
> + *
> + *  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 "relocator_common.S"
> +
> +     .p2align        4       /* force 16-byte alignment */
> +
> +VARIABLE(grub_relocator64_efi_start)
> +     PREAMBLE
> +
> +     .code64
> +
> +     /* mov imm64, %rax */
> +     .byte   0x48
> +     .byte   0xb8
> +VARIABLE(grub_relocator64_efi_rsi)
> +     .quad   0
> +
> +     movq    %rax, %rsi
> +
> +     /* mov imm64, %rax */
> +     .byte   0x48
> +     .byte   0xb8
> +VARIABLE(grub_relocator64_efi_rax)
> +     .quad   0
> +
> +     /* mov imm64, %rbx */
> +     .byte   0x48
> +     .byte   0xbb
> +VARIABLE(grub_relocator64_efi_rbx)
> +     .quad   0
> +
> +     /* mov imm64, %rcx */
> +     .byte   0x48
> +     .byte   0xb9
> +VARIABLE(grub_relocator64_efi_rcx)
> +     .quad   0
> +
> +     /* mov imm64, %rdx */
> +     .byte   0x48
> +     .byte   0xba
> +VARIABLE(grub_relocator64_efi_rdx)
> +     .quad   0
> +
> +     /* Cleared direction flag is of no problem with any current
> +        payload and makes this implementation easier.  */
> +     cld
> +
> +#ifdef __APPLE__
> +     .byte 0xff, 0x25
> +     .quad 0
> +#else
> +     jmp *LOCAL(jump_addr) (%rip)
> +#endif
> +
> +LOCAL(jump_addr):
> +VARIABLE(grub_relocator64_efi_rip)
> +     .quad   0
> +
This repeats relocator64 almost exactly. Can we avoid code duplication?
It's fine to compile it twice but code duplication is bad.
> +VARIABLE(grub_relocator64_efi_end)
> diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
> index fd8f28e..ca7154f 100644
> --- a/grub-core/loader/multiboot.c
> +++ b/grub-core/loader/multiboot.c
> @@ -118,21 +118,44 @@ grub_multiboot_set_video_mode (void)
>    return err;
>  }
>  
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +#define grub_relocator_efi_boot      grub_relocator64_efi_boot
> +#endif
> +#endif
> +
>  static grub_err_t
>  grub_multiboot_boot (void)
>  {
>    grub_err_t err;
> +  grub_uint32_t target;
>    struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE;
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +  struct grub_relocator64_efi_state state_efi = MULTIBOOT_EFI_INITIAL_STATE;
> +#endif
> +#endif
>  
> -  state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip;
> -
> -  err = grub_multiboot_make_mbi (&state.MULTIBOOT_MBI_REGISTER);
> +  err = grub_multiboot_make_mbi (&target);
>  
>    if (err)
>      return err;
>  
> +  state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip;
> +  state.MULTIBOOT_MBI_REGISTER = target;
> +
>  #if defined (__i386__) || defined (__x86_64__)
> +#ifdef GRUB_MACHINE_EFI
> +  state_efi.MULTIBOOT_EFI_ENTRY_REGISTER = grub_multiboot_payload_eip;
> +  state_efi.MULTIBOOT_EFI_MBI_REGISTER = target;
> +
> +  if (grub_efi_is_finished)
> +    grub_relocator32_boot (grub_multiboot_relocator, state, 0);
> +  else
> +    grub_relocator_efi_boot (grub_multiboot_relocator, state_efi);
> +#else
>    grub_relocator32_boot (grub_multiboot_relocator, state, 0);
> +#endif
>  #else
>    grub_relocator32_boot (grub_multiboot_relocator, state);
>  #endif
This becomes hairy. I think it's time to split it into platform-specific
functions and/or use tricks like
#ifndef GRUB_MACHINE_EFI
#define grub_efi_is_finished 0
#endif
> diff --git a/grub-core/loader/multiboot_mbi2.c 
> b/grub-core/loader/multiboot_mbi2.c
> index d7c19bc..8d66e3f 100644
> --- a/grub-core/loader/multiboot_mbi2.c
> +++ b/grub-core/loader/multiboot_mbi2.c
> @@ -107,8 +107,8 @@ grub_multiboot_load (grub_file_t file, const char 
> *filename)
>    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;
> +  int entry_specified = 0, efi_entry_specified = 0;
> +  grub_addr_t entry = 0, efi_entry = 0;
>    grub_uint32_t console_required = 0;
>    struct multiboot_header_tag_framebuffer *fbtag = NULL;
>    int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
> @@ -192,6 +192,13 @@ grub_multiboot_load (grub_file_t file, const char 
> *filename)
>       entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
>       break;
>  
> +      case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64:
> +#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
> +     efi_entry_specified = 1;
> +     efi_entry = ((struct multiboot_header_tag_entry_address_efi64 *) 
> tag)->entry_addr;
> +#endif
> +     break;
> +
Why do we need separate handling of EFI entry point? Why can't we use
the same structure?
>        case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
>       if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
>           & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
> @@ -211,7 +218,9 @@ grub_multiboot_load (grub_file_t file, const char 
> *filename)
>       break;
>  
>        case MULTIBOOT_HEADER_TAG_EFI_BS:
> +#ifdef GRUB_MACHINE_EFI
>       keep_bs = 1;
> +#endif
>       break;
>  
>        default:
> @@ -224,7 +233,7 @@ grub_multiboot_load (grub_file_t file, const char 
> *filename)
>       break;
>        }
>  
> -  if (addr_tag && !entry_specified)
> +  if (addr_tag && !entry_specified && !(keep_bs && efi_entry_specified))
>      {
>        grub_free (buffer);
>        return grub_error (GRUB_ERR_UNKNOWN_OS,
> @@ -287,7 +296,9 @@ grub_multiboot_load (grub_file_t file, const char 
> *filename)
>       }
>      }
>  
> -  if (entry_specified)
> +  if (keep_bs && efi_entry_specified)
> +    grub_multiboot_payload_eip = efi_entry;
> +  else if (entry_specified)
>      grub_multiboot_payload_eip = entry;
>  
This seems redundant.
>    if (fbtag)
> diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h
> index a1b9488..807a1de 100644
> --- a/include/grub/i386/multiboot.h
> +++ b/include/grub/i386/multiboot.h
> @@ -30,6 +30,17 @@
>  #define MULTIBOOT_MBI_REGISTER ebx
>  #define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_I386
>  
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +#define MULTIBOOT_EFI_INITIAL_STATE  { .rax = MULTIBOOT_BOOTLOADER_MAGIC,    
> \
> +    .rcx = 0,                                                                
>         \
> +    .rdx = 0,                                                                
>         \
> +      }
> +#define MULTIBOOT_EFI_ENTRY_REGISTER rip
> +#define MULTIBOOT_EFI_MBI_REGISTER rbx
> +#endif
> +#endif
> +
>  #define MULTIBOOT_ELF32_MACHINE EM_386
>  #define MULTIBOOT_ELF64_MACHINE EM_X86_64
>  
> diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h
> index 5f89a7e..2a56c3b 100644
> --- a/include/grub/i386/relocator.h
> +++ b/include/grub/i386/relocator.h
> @@ -65,6 +65,20 @@ struct grub_relocator64_state
>    grub_addr_t cr3;
>  };
>  
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +struct grub_relocator64_efi_state
> +{
> +  grub_uint64_t rax;
> +  grub_uint64_t rbx;
> +  grub_uint64_t rcx;
> +  grub_uint64_t rdx;
> +  grub_uint64_t rip;
> +  grub_uint64_t rsi;
> +};
> +#endif
> +#endif
> +
>  grub_err_t grub_relocator16_boot (struct grub_relocator *rel,
>                                 struct grub_relocator16_state state);
>  
> @@ -76,4 +90,11 @@ grub_err_t grub_relocator64_boot (struct grub_relocator 
> *rel,
>                                 struct grub_relocator64_state state,
>                                 grub_addr_t min_addr, grub_addr_t max_addr);
>  
> +#ifdef GRUB_MACHINE_EFI
> +#ifdef __x86_64__
> +grub_err_t grub_relocator64_efi_boot (struct grub_relocator *rel,
> +                                   struct grub_relocator64_efi_state state);
> +#endif
> +#endif
> +
>  #endif /* ! GRUB_RELOCATOR_CPU_HEADER */
> diff --git a/include/multiboot2.h b/include/multiboot2.h
> index 9d48627..b3977e3 100644
> --- a/include/multiboot2.h
> +++ b/include/multiboot2.h
> @@ -69,6 +69,7 @@
>  #define MULTIBOOT_HEADER_TAG_FRAMEBUFFER  5
>  #define MULTIBOOT_HEADER_TAG_MODULE_ALIGN  6
>  #define MULTIBOOT_HEADER_TAG_EFI_BS  7
> +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64  9
>  
>  #define MULTIBOOT_ARCHITECTURE_I386  0
>  #define MULTIBOOT_ARCHITECTURE_MIPS32  4
> @@ -133,6 +134,14 @@ struct multiboot_header_tag_entry_address
>    multiboot_uint32_t entry_addr;
>  };
>  
> +struct multiboot_header_tag_entry_address_efi64
> +{
> +  multiboot_uint16_t type;
> +  multiboot_uint16_t flags;
> +  multiboot_uint32_t size;
> +  multiboot_uint32_t entry_addr;
> +};
> +
Ditto
>  struct multiboot_header_tag_console_flags
>  {
>    multiboot_uint16_t type;
> 


Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to