diff mbox

[Xen-devel,V4,02/15] Move x86 specific funtions/variables to arch header

Message ID 1410310325-4509-3-git-send-email-roy.franz@linaro.org
State New
Headers show

Commit Message

Roy Franz Sept. 10, 2014, 12:51 a.m. UTC
Move the global variables and functions that can be moved as-is
from the common boot.c file to the x86 implementation header file.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
---
 xen/common/efi/boot.c          | 460 ++---------------------------------------
 xen/include/asm-x86/efi-boot.h | 451 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 464 insertions(+), 447 deletions(-)
 create mode 100644 xen/include/asm-x86/efi-boot.h

Comments

Jan Beulich Sept. 11, 2014, 2:03 p.m. UTC | #1
>>> On 10.09.14 at 02:51, <roy.franz@linaro.org> wrote:
> -/* Using SetVirtualAddressMap() is incompatible with kexec: */
> -#undef USE_SET_VIRTUAL_ADDRESS_MAP

In which way is this arch-specific?

> @@ -41,8 +31,10 @@ typedef struct {
>      EFI_SHIM_LOCK_VERIFY Verify;
>  } EFI_SHIM_LOCK_PROTOCOL;
>  
> -extern char start[];
> -extern u32 cpuid_ext_features;
> +static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer);
> +static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer);
> +static void __init DisplayUint(UINT64 Val, INTN Width);
> +static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s);

Why do you need these declarations? And if you need them, no
__init annotations here please (they only belong on the
definitions).

> -static void __init place_string(u32 *addr, const char *s)
> -{
> -    static char *__initdata alloc = start;
> -
> -    if ( s && *s )
> -    {
> -        size_t len1 = strlen(s) + 1;
> -        const char *old = (char *)(long)*addr;
> -        size_t len2 = *addr ? strlen(old) + 1 : 0;
> -
> -        alloc -= len1 + len2;
> -        /*
> -         * Insert new string before already existing one. This is needed
> -         * for options passed on the command line to override options from
> -         * the configuration file.
> -         */
> -        memcpy(alloc, s, len1);
> -        if ( *addr )
> -        {
> -            alloc[len1 - 1] = ' ';
> -            memcpy(alloc + len1, old, len2);
> -        }
> -    }
> -    *addr = (long)alloc;
> -}

How much of this is really arch-specific?

> -static void __init setup_efi_pci(void)

And this doesn't seem arch-specific either (it only depends on
HAS_PCI or some such).

> -static void __init relocate_image(unsigned long delta)

I can see that some of this may need an arch abstraction, but why
would you not want to do this on ARM (or elsewhere)? In fact - how
do you get away without?

> --- /dev/null
> +++ b/xen/include/asm-x86/efi-boot.h
> @@ -0,0 +1,451 @@
> +/*
> + * Architecture specific implementation for EFI boot code.  This file
> + * is intended to be included by XXX _only_, and therefore can define
> + * arch specific global variables.
> + */
> +#include <asm/e820.h>
> +#include <asm/edd.h>
> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */
> +#include <asm/fixmap.h>
> +#undef __ASSEMBLY__
> +#include <asm/msr.h>
> +#include <asm/processor.h>
> +
> +static struct file __initdata ucode;
> +static multiboot_info_t __initdata mbi = {
> +    .flags = MBI_MODULES | MBI_LOADERNAME
> +};
> +static module_t __initdata mb_modules[3];
> +
> +static void noreturn blexit(const CHAR16 *str);
> +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);

What are these two doing here?

> +void __init efi_init_memory(void)

Now that I look at it again, I think a good part of this is arch-
independent too.

Jan
Roy Franz Sept. 11, 2014, 5:33 p.m. UTC | #2
On Thu, Sep 11, 2014 at 7:03 AM, Jan Beulich <JBeulich@suse.com> wrote:
>>>> On 10.09.14 at 02:51, <roy.franz@linaro.org> wrote:
>> -/* Using SetVirtualAddressMap() is incompatible with kexec: */
>> -#undef USE_SET_VIRTUAL_ADDRESS_MAP
>
> In which way is this arch-specific?
The define is only used by the x86 specific code.  I can move it back
to the common code.


>
>> @@ -41,8 +31,10 @@ typedef struct {
>>      EFI_SHIM_LOCK_VERIFY Verify;
>>  } EFI_SHIM_LOCK_PROTOCOL;
>>
>> -extern char start[];
>> -extern u32 cpuid_ext_features;
>> +static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer);
>> +static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer);
>> +static void __init DisplayUint(UINT64 Val, INTN Width);
>> +static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s);
>
> Why do you need these declarations? And if you need them, no
> __init annotations here please (they only belong on the
> definitions).

These are forward declarations of functions provided by boot.c but
used in efi-boot.h.  I was trying to keep the
#include of efi-boot.h near the top of the file.  I can move it to
below where these functions are defined and remove
the forward declarations.
I will remove the __init if they stay.

>
>> -static void __init place_string(u32 *addr, const char *s)
>> -{
>> -    static char *__initdata alloc = start;
>> -
>> -    if ( s && *s )
>> -    {
>> -        size_t len1 = strlen(s) + 1;
>> -        const char *old = (char *)(long)*addr;
>> -        size_t len2 = *addr ? strlen(old) + 1 : 0;
>> -
>> -        alloc -= len1 + len2;
>> -        /*
>> -         * Insert new string before already existing one. This is needed
>> -         * for options passed on the command line to override options from
>> -         * the configuration file.
>> -         */
>> -        memcpy(alloc, s, len1);
>> -        if ( *addr )
>> -        {
>> -            alloc[len1 - 1] = ' ';
>> -            memcpy(alloc + len1, old, len2);
>> -        }
>> -    }
>> -    *addr = (long)alloc;
>> -}
>
> How much of this is really arch-specific?

This is only used by the x86 code, and this is the x86 specific memory
management that uses
memory allocated by the linker script before start.  The ARM boot code
does not use this.

>
>> -static void __init setup_efi_pci(void)
>
> And this doesn't seem arch-specific either (it only depends on
> HAS_PCI or some such).

This does scanning of PCI ROMS, which is unlikely to do anything
useful on ARM platforms.  I also have
no way to test this on ARM.
I can try to pull this back in, but I may run into dependency issues
such as those with VGA, where I did not
want to pull in otherwise unused (and likely unusable on ARM)
drivers/subsystems in order to keep a little more
code in the common EFI boot path.

>
>> -static void __init relocate_image(unsigned long delta)
>
> I can see that some of this may need an arch abstraction, but why
> would you not want to do this on ARM (or elsewhere)? In fact - how
> do you get away without?

This is done later in boot - I am not familiar with the details.
Maybe Ian can add something here.

>
>> --- /dev/null
>> +++ b/xen/include/asm-x86/efi-boot.h
>> @@ -0,0 +1,451 @@
>> +/*
>> + * Architecture specific implementation for EFI boot code.  This file
>> + * is intended to be included by XXX _only_, and therefore can define
>> + * arch specific global variables.
>> + */
>> +#include <asm/e820.h>
>> +#include <asm/edd.h>
>> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */
>> +#include <asm/fixmap.h>
>> +#undef __ASSEMBLY__
>> +#include <asm/msr.h>
>> +#include <asm/processor.h>
>> +
>> +static struct file __initdata ucode;
>> +static multiboot_info_t __initdata mbi = {
>> +    .flags = MBI_MODULES | MBI_LOADERNAME
>> +};
>> +static module_t __initdata mb_modules[3];
>> +
>> +static void noreturn blexit(const CHAR16 *str);
>> +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);
>
> What are these two doing here?

These are forward declarations.  I don't think that I can order
everything so that I don't need any forward declarations
anywhere.

>
>> +void __init efi_init_memory(void)
>
> Now that I look at it again, I think a good part of this is arch-
> independent too.
By "this" you mean the code in efi_init_memory?

>
> Jan
>
Jan Beulich Sept. 12, 2014, 7:04 a.m. UTC | #3
>>> On 11.09.14 at 19:33, <roy.franz@linaro.org> wrote:
> On Thu, Sep 11, 2014 at 7:03 AM, Jan Beulich <JBeulich@suse.com> wrote:
>>>>> On 10.09.14 at 02:51, <roy.franz@linaro.org> wrote:
>>> -/* Using SetVirtualAddressMap() is incompatible with kexec: */
>>> -#undef USE_SET_VIRTUAL_ADDRESS_MAP
>>
>> In which way is this arch-specific?
> The define is only used by the x86 specific code.  I can move it back
> to the common code.

Yes please, as the conflict with kexec is an arch-independent one.

>>> -static void __init place_string(u32 *addr, const char *s)
>>> -{
>>> -    static char *__initdata alloc = start;
>>> -
>>> -    if ( s && *s )
>>> -    {
>>> -        size_t len1 = strlen(s) + 1;
>>> -        const char *old = (char *)(long)*addr;
>>> -        size_t len2 = *addr ? strlen(old) + 1 : 0;
>>> -
>>> -        alloc -= len1 + len2;
>>> -        /*
>>> -         * Insert new string before already existing one. This is needed
>>> -         * for options passed on the command line to override options from
>>> -         * the configuration file.
>>> -         */
>>> -        memcpy(alloc, s, len1);
>>> -        if ( *addr )
>>> -        {
>>> -            alloc[len1 - 1] = ' ';
>>> -            memcpy(alloc + len1, old, len2);
>>> -        }
>>> -    }
>>> -    *addr = (long)alloc;
>>> -}
>>
>> How much of this is really arch-specific?
> 
> This is only used by the x86 code, and this is the x86 specific memory
> management that uses
> memory allocated by the linker script before start.  The ARM boot code
> does not use this.

I.e. the only arch-specific thing here is the initializer of "alloc". Or
are you saying that you don't need a place_string() function in
ARM at all? Is that because to stuff respective information into DT?

>>> -static void __init setup_efi_pci(void)
>>
>> And this doesn't seem arch-specific either (it only depends on
>> HAS_PCI or some such).
> 
> This does scanning of PCI ROMS, which is unlikely to do anything
> useful on ARM platforms.

Why not? Obviously if the ROMs contain x86 code, they're useless,
but in order to, say, do remote boot I suppose you need option
ROMs (with ARM code) on ARM too.

> I also have no way to test this on ARM.
> I can try to pull this back in, but I may run into dependency issues
> such as those with VGA, where I did not
> want to pull in otherwise unused (and likely unusable on ARM)
> drivers/subsystems in order to keep a little more
> code in the common EFI boot path.

The base line should be too keep everything here that is potentially
usable on more than one arch (without limiting our thinking to ARM
and x86). EFI's protocol based approach abstracts this quite nicely
- if something isn't available, you simply won't find th respective
protocol.

>>> --- /dev/null
>>> +++ b/xen/include/asm-x86/efi-boot.h
>>> @@ -0,0 +1,451 @@
>>> +/*
>>> + * Architecture specific implementation for EFI boot code.  This file
>>> + * is intended to be included by XXX _only_, and therefore can define
>>> + * arch specific global variables.
>>> + */
>>> +#include <asm/e820.h>
>>> +#include <asm/edd.h>
>>> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */
>>> +#include <asm/fixmap.h>
>>> +#undef __ASSEMBLY__
>>> +#include <asm/msr.h>
>>> +#include <asm/processor.h>
>>> +
>>> +static struct file __initdata ucode;
>>> +static multiboot_info_t __initdata mbi = {
>>> +    .flags = MBI_MODULES | MBI_LOADERNAME
>>> +};
>>> +static module_t __initdata mb_modules[3];
>>> +
>>> +static void noreturn blexit(const CHAR16 *str);
>>> +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);
>>
>> What are these two doing here?
> 
> These are forward declarations.  I don't think that I can order
> everything so that I don't need any forward declarations
> anywhere.

I realize you may need forward declarations. But you declare arch-
independent functions in an arch header here.

>>> +void __init efi_init_memory(void)
>>
>> Now that I look at it again, I think a good part of this is arch-
>> independent too.
> By "this" you mean the code in efi_init_memory?

Yes, at least everything up to and including the
SetVirtualAddressMap() call.

Jan
Ian Campbell Sept. 12, 2014, 9:43 a.m. UTC | #4
On Fri, 2014-09-12 at 08:04 +0100, Jan Beulich wrote:
> > This does scanning of PCI ROMS, which is unlikely to do anything
> > useful on ARM platforms.
> 
> Why not? Obviously if the ROMs contain x86 code, they're useless,
> but in order to, say, do remote boot I suppose you need option
> ROMs (with ARM code) on ARM too.

Doesn't that all happen at the UEFI layer, long before Xen gets
involved, even on x86?

Does Xen itself do network boot/loading or does it call some UEFI layer?

> > I also have no way to test this on ARM.
> > I can try to pull this back in, but I may run into dependency issues
> > such as those with VGA, where I did not
> > want to pull in otherwise unused (and likely unusable on ARM)
> > drivers/subsystems in order to keep a little more
> > code in the common EFI boot path.
> 
> The base line should be too keep everything here that is potentially
> usable on more than one arch (without limiting our thinking to ARM
> and x86). EFI's protocol based approach abstracts this quite nicely
> - if something isn't available, you simply won't find th respective
> protocol.

Irrespective of the above this seems like a sensible approach.

Ian.
Jan Beulich Sept. 12, 2014, 9:53 a.m. UTC | #5
>>> On 12.09.14 at 11:43, <Ian.Campbell@citrix.com> wrote:
> On Fri, 2014-09-12 at 08:04 +0100, Jan Beulich wrote:
>> > This does scanning of PCI ROMS, which is unlikely to do anything
>> > useful on ARM platforms.
>> 
>> Why not? Obviously if the ROMs contain x86 code, they're useless,
>> but in order to, say, do remote boot I suppose you need option
>> ROMs (with ARM code) on ARM too.
> 
> Doesn't that all happen at the UEFI layer, long before Xen gets
> involved, even on x86?

The purpose of the code here isn't for ourselves, but for onward
reporting to Dom0 (via XEN_FW_EFI_PCI_ROM).

> Does Xen itself do network boot/loading or does it call some UEFI layer?

Iiuc Xen would support remote boot right now only if there was a
file system protocol exposed allowing to read in the necessary
files. Anything requiring explicit awareness of that fact is currently
missing.

Jan
Ian Campbell Sept. 12, 2014, 9:58 a.m. UTC | #6
On Fri, 2014-09-12 at 10:53 +0100, Jan Beulich wrote:
> >>> On 12.09.14 at 11:43, <Ian.Campbell@citrix.com> wrote:
> > On Fri, 2014-09-12 at 08:04 +0100, Jan Beulich wrote:
> >> > This does scanning of PCI ROMS, which is unlikely to do anything
> >> > useful on ARM platforms.
> >> 
> >> Why not? Obviously if the ROMs contain x86 code, they're useless,
> >> but in order to, say, do remote boot I suppose you need option
> >> ROMs (with ARM code) on ARM too.
> > 
> > Doesn't that all happen at the UEFI layer, long before Xen gets
> > involved, even on x86?
> 
> The purpose of the code here isn't for ourselves, but for onward
> reporting to Dom0 (via XEN_FW_EFI_PCI_ROM).

Ah, makes sense.

> > Does Xen itself do network boot/loading or does it call some UEFI layer?
> 
> Iiuc Xen would support remote boot right now only if there was a
> file system protocol exposed allowing to read in the necessary
> files. Anything requiring explicit awareness of that fact is currently
> missing.

Right. So behind some UEFI layer.
Roy Franz Sept. 12, 2014, 4:52 p.m. UTC | #7
On Fri, Sep 12, 2014 at 12:04 AM, Jan Beulich <JBeulich@suse.com> wrote:

> >>> On 11.09.14 at 19:33, <roy.franz@linaro.org> wrote:
> > On Thu, Sep 11, 2014 at 7:03 AM, Jan Beulich <JBeulich@suse.com> wrote:
> >>>>> On 10.09.14 at 02:51, <roy.franz@linaro.org> wrote:
> >>> -/* Using SetVirtualAddressMap() is incompatible with kexec: */
> >>> -#undef USE_SET_VIRTUAL_ADDRESS_MAP
> >>
> >> In which way is this arch-specific?
> > The define is only used by the x86 specific code.  I can move it back
> > to the common code.
>
> Yes please, as the conflict with kexec is an arch-independent one.
>
> >>> -static void __init place_string(u32 *addr, const char *s)
> >>> -{
> >>> -    static char *__initdata alloc = start;
> >>> -
> >>> -    if ( s && *s )
> >>> -    {
> >>> -        size_t len1 = strlen(s) + 1;
> >>> -        const char *old = (char *)(long)*addr;
> >>> -        size_t len2 = *addr ? strlen(old) + 1 : 0;
> >>> -
> >>> -        alloc -= len1 + len2;
> >>> -        /*
> >>> -         * Insert new string before already existing one. This is
> needed
> >>> -         * for options passed on the command line to override options
> from
> >>> -         * the configuration file.
> >>> -         */
> >>> -        memcpy(alloc, s, len1);
> >>> -        if ( *addr )
> >>> -        {
> >>> -            alloc[len1 - 1] = ' ';
> >>> -            memcpy(alloc + len1, old, len2);
> >>> -        }
> >>> -    }
> >>> -    *addr = (long)alloc;
> >>> -}
> >>
> >> How much of this is really arch-specific?
> >
> > This is only used by the x86 code, and this is the x86 specific memory
> > management that uses
> > memory allocated by the linker script before start.  The ARM boot code
> > does not use this.
>
> I.e. the only arch-specific thing here is the initializer of "alloc". Or
> are you saying that you don't need a place_string() function in
> ARM at all? Is that because to stuff respective information into DT?
>
ARM doesn't use place_string() at all.  All the information is placed into
the DT that has EFI allocated memory for it.


>
> >>> -static void __init setup_efi_pci(void)
> >>
> >> And this doesn't seem arch-specific either (it only depends on
> >> HAS_PCI or some such).
> >
> > This does scanning of PCI ROMS, which is unlikely to do anything
> > useful on ARM platforms.
>
> Why not? Obviously if the ROMs contain x86 code, they're useless,
> but in order to, say, do remote boot I suppose you need option
> ROMs (with ARM code) on ARM too.
>

Yes, something like that may exist someday.  This can get moved back
with the #ifdef'ing of the runtime.c implementation.

>
> > I also have no way to test this on ARM.
> > I can try to pull this back in, but I may run into dependency issues
> > such as those with VGA, where I did not
> > want to pull in otherwise unused (and likely unusable on ARM)
> > drivers/subsystems in order to keep a little more
> > code in the common EFI boot path.
>
> The base line should be too keep everything here that is potentially
> usable on more than one arch (without limiting our thinking to ARM
> and x86). EFI's protocol based approach abstracts this quite nicely
> - if something isn't available, you simply won't find th respective
> protocol.
>

I'll take a look at just factoring out the VGA specific stuff - I agree that
is all that needs to be in the x86 specific file.



>
> >>> --- /dev/null
> >>> +++ b/xen/include/asm-x86/efi-boot.h
> >>> @@ -0,0 +1,451 @@
> >>> +/*
> >>> + * Architecture specific implementation for EFI boot code.  This file
> >>> + * is intended to be included by XXX _only_, and therefore can define
> >>> + * arch specific global variables.
> >>> + */
> >>> +#include <asm/e820.h>
> >>> +#include <asm/edd.h>
> >>> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with
> EFI) */
> >>> +#include <asm/fixmap.h>
> >>> +#undef __ASSEMBLY__
> >>> +#include <asm/msr.h>
> >>> +#include <asm/processor.h>
> >>> +
> >>> +static struct file __initdata ucode;
> >>> +static multiboot_info_t __initdata mbi = {
> >>> +    .flags = MBI_MODULES | MBI_LOADERNAME
> >>> +};
> >>> +static module_t __initdata mb_modules[3];
> >>> +
> >>> +static void noreturn blexit(const CHAR16 *str);
> >>> +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);
> >>
> >> What are these two doing here?
> >
> > These are forward declarations.  I don't think that I can order
> > everything so that I don't need any forward declarations
> > anywhere.
>
> I realize you may need forward declarations. But you declare arch-
> independent functions in an arch header here.
>
> >>> +void __init efi_init_memory(void)
> >>
> >> Now that I look at it again, I think a good part of this is arch-
> >> independent too.
> > By "this" you mean the code in efi_init_memory?
>
> Yes, at least everything up to and including the
> SetVirtualAddressMap() call.
>

This is only called from x86/mm.c, so it is currently unused on ARM.
If it causes compile problems on ARM I can #ifdef it, since this will need
to be dealt with as part
of adding runtime service support.

>
> Jan
>
diff mbox

Patch

diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index 14e2f46..ca604be 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -18,16 +18,6 @@ 
 #include <xen/string.h>
 #include <xen/stringify.h>
 #include <xen/vga.h>
-#include <asm/e820.h>
-#include <asm/edd.h>
-#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */
-#include <asm/fixmap.h>
-#undef __ASSEMBLY__
-#include <asm/msr.h>
-#include <asm/processor.h>
-
-/* Using SetVirtualAddressMap() is incompatible with kexec: */
-#undef USE_SET_VIRTUAL_ADDRESS_MAP
 
 #define SHIM_LOCK_PROTOCOL_GUID \
   { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
@@ -41,8 +31,10 @@  typedef struct {
     EFI_SHIM_LOCK_VERIFY Verify;
 } EFI_SHIM_LOCK_PROTOCOL;
 
-extern char start[];
-extern u32 cpuid_ext_features;
+static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer);
+static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer);
+static void __init DisplayUint(UINT64 Val, INTN Width);
+static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s);
 
 union string {
     CHAR16 *w;
@@ -69,19 +61,18 @@  static UINT32 __initdata mdesc_ver;
 static struct file __initdata cfg;
 static struct file __initdata kernel;
 static struct file __initdata ramdisk;
-static struct file __initdata ucode;
 static struct file __initdata xsm;
-
-static multiboot_info_t __initdata mbi = {
-    .flags = MBI_MODULES | MBI_LOADERNAME
-};
-static module_t __initdata mb_modules[3];
-
 static CHAR16 __initdata newline[] = L"\r\n";
 
 #define PrintStr(s) StdOut->OutputString(StdOut, s)
 #define PrintErr(s) StdErr->OutputString(StdErr, s)
 
+/*
+ * Include architecture specific implementation here, which references the
+ * static globals defined above.
+ */
+#include <asm/efi-boot.h>
+
 static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer)
 {
     if ( Val >= 10 )
@@ -255,32 +246,6 @@  static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode)
     blexit(mesg);
 }
 
-static void __init place_string(u32 *addr, const char *s)
-{
-    static char *__initdata alloc = start;
-
-    if ( s && *s )
-    {
-        size_t len1 = strlen(s) + 1;
-        const char *old = (char *)(long)*addr;
-        size_t len2 = *addr ? strlen(old) + 1 : 0;
-
-        alloc -= len1 + len2;
-        /*
-         * Insert new string before already existing one. This is needed
-         * for options passed on the command line to override options from
-         * the configuration file.
-         */
-        memcpy(alloc, s, len1);
-        if ( *addr )
-        {
-            alloc[len1 - 1] = ' ';
-            memcpy(alloc + len1, old, len2);
-        }
-    }
-    *addr = (long)alloc;
-}
-
 static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv,
                                     CHAR16 *cmdline, UINTN cmdsize)
 {
@@ -574,104 +539,6 @@  static void __init split_value(char *s)
     *s = 0;
 }
 
-static void __init edd_put_string(u8 *dst, size_t n, const char *src)
-{
-    while ( n-- && *src )
-       *dst++ = *src++;
-    if ( *src )
-       PrintErrMesg(L"Internal error populating EDD info",
-                    EFI_BUFFER_TOO_SMALL);
-    while ( n-- )
-       *dst++ = ' ';
-}
-#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s)
-
-static void __init setup_efi_pci(void)
-{
-    EFI_STATUS status;
-    EFI_HANDLE *handles;
-    static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL;
-    UINTN i, nr_pci, size = 0;
-    struct efi_pci_rom *last = NULL;
-
-    status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, NULL);
-    if ( status == EFI_BUFFER_TOO_SMALL )
-        status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles);
-    if ( !EFI_ERROR(status) )
-        status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size,
-                                      handles);
-    if ( EFI_ERROR(status) )
-        size = 0;
-
-    nr_pci = size / sizeof(*handles);
-    for ( i = 0; i < nr_pci; ++i )
-    {
-        EFI_PCI_IO *pci = NULL;
-        u64 attributes;
-        struct efi_pci_rom *rom, *va;
-        UINTN segment, bus, device, function;
-
-        status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci);
-        if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize )
-            continue;
-
-        status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0,
-                                 &attributes);
-        if ( EFI_ERROR(status) ||
-             !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) ||
-             EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device,
-                       &function)) )
-            continue;
-
-        DisplayUint(segment, 4);
-        PrintStr(L":");
-        DisplayUint(bus, 2);
-        PrintStr(L":");
-        DisplayUint(device, 2);
-        PrintStr(L".");
-        DisplayUint(function, 1);
-        PrintStr(L": ROM: ");
-        DisplayUint(pci->RomSize, 0);
-        PrintStr(L" bytes at ");
-        DisplayUint((UINTN)pci->RomImage, 0);
-        PrintStr(newline);
-
-        size = pci->RomSize + sizeof(*rom);
-        status = efi_bs->AllocatePool(EfiRuntimeServicesData, size,
-                                      (void **)&rom);
-        if ( EFI_ERROR(status) )
-            continue;
-
-        rom->next = NULL;
-        rom->size = pci->RomSize;
-
-        status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1,
-                               &rom->vendor);
-        if ( !EFI_ERROR(status) )
-            status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1,
-                                   &rom->devid);
-        if ( EFI_ERROR(status) )
-        {
-            efi_bs->FreePool(rom);
-            continue;
-        }
-
-        rom->segment = segment;
-        rom->bus = bus;
-        rom->devfn = (device << 3) | function;
-        memcpy(rom->data, pci->RomImage, pci->RomSize);
-
-        va = (void *)rom + DIRECTMAP_VIRT_START;
-        if ( last )
-            last->next = va;
-        else
-            efi_pci_roms = va;
-        last = rom;
-    }
-
-    efi_bs->FreePool(handles);
-}
-
 static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz)
 {
    if ( bpp < 0 )
@@ -687,82 +554,6 @@  static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz)
    return max(*pos + *sz, bpp);
 }
 
-extern const intpte_t __page_tables_start[], __page_tables_end[];
-#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \
-                           (intpte_t *)(v) < __page_tables_end)
-
-#define PE_BASE_RELOC_ABS      0
-#define PE_BASE_RELOC_HIGHLOW  3
-#define PE_BASE_RELOC_DIR64   10
-
-extern const struct pe_base_relocs {
-    u32 rva;
-    u32 size;
-    u16 entries[];
-} __base_relocs_start[], __base_relocs_end[];
-
-static void __init relocate_image(unsigned long delta)
-{
-    const struct pe_base_relocs *base_relocs;
-
-    for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; )
-    {
-        unsigned int i, n;
-
-        n = (base_relocs->size - sizeof(*base_relocs)) /
-            sizeof(*base_relocs->entries);
-        for ( i = 0; i < n; ++i )
-        {
-            unsigned long addr = xen_phys_start + base_relocs->rva +
-                                 (base_relocs->entries[i] & 0xfff);
-
-            switch ( base_relocs->entries[i] >> 12 )
-            {
-            case PE_BASE_RELOC_ABS:
-                break;
-            case PE_BASE_RELOC_HIGHLOW:
-                if ( delta )
-                {
-                    *(u32 *)addr += delta;
-                    if ( in_page_tables(addr) )
-                        *(u32 *)addr += xen_phys_start;
-                }
-                break;
-            case PE_BASE_RELOC_DIR64:
-                if ( delta )
-                {
-                    *(u64 *)addr += delta;
-                    if ( in_page_tables(addr) )
-                        *(intpte_t *)addr += xen_phys_start;
-                }
-                break;
-            default:
-                blexit(L"Unsupported relocation type");
-            }
-        }
-        base_relocs = (const void *)(base_relocs->entries + i + (i & 1));
-    }
-}
-
-extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[];
-extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[];
-
-static void __init relocate_trampoline(unsigned long phys)
-{
-    const s32 *trampoline_ptr;
-
-    trampoline_phys = phys;
-    /* Apply relocations to trampoline. */
-    for ( trampoline_ptr = __trampoline_rel_start;
-          trampoline_ptr < __trampoline_rel_stop;
-          ++trampoline_ptr )
-        *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys;
-    for ( trampoline_ptr = __trampoline_seg_start;
-          trampoline_ptr < __trampoline_seg_stop;
-          ++trampoline_ptr )
-        *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4;
-}
-
 void EFIAPI __init noreturn
 efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
 {
@@ -879,7 +670,7 @@  efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION)
              XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
 
-    relocate_image(0);
+    efi_arch_relocate_image(0);
 
     if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode,
                            &cols, &rows) == EFI_SUCCESS )
@@ -1258,7 +1049,7 @@  efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
         dmi_efi_get_table((void *)(long)efi.smbios);
 
     /* Collect PCI ROM contents. */
-    setup_efi_pci();
+    efi_arch_pci();
 
     /* Get snapshot of variable store parameters. */
     status = (efi_rs->Hdr.Revision >> 16) >= 2 ?
@@ -1460,7 +1251,7 @@  efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     efi_memmap = (void *)efi_memmap + DIRECTMAP_VIRT_START;
     efi_fw_vendor = (void *)efi_fw_vendor + DIRECTMAP_VIRT_START;
 
-    relocate_image(__XEN_VIRT_START - xen_phys_start);
+    efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start);
     memcpy((void *)trampoline_phys, trampoline_start, cfg.size);
 
     /* Set system registers and transfer control. */
@@ -1496,228 +1287,3 @@  efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     for( ; ; ); /* not reached */
 }
 
-#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
-static __init void copy_mapping(unsigned long mfn, unsigned long end,
-                                bool_t (*is_valid)(unsigned long smfn,
-                                                   unsigned long emfn))
-{
-    unsigned long next;
-
-    for ( ; mfn < end; mfn = next )
-    {
-        l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)];
-        l3_pgentry_t *l3src, *l3dst;
-        unsigned long va = (unsigned long)mfn_to_virt(mfn);
-
-        next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT));
-        if ( !is_valid(mfn, min(next, end)) )
-            continue;
-        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
-        {
-            l3dst = alloc_xen_pagetable();
-            BUG_ON(!l3dst);
-            clear_page(l3dst);
-            efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] =
-                l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR);
-        }
-        else
-            l3dst = l4e_to_l3e(l4e);
-        l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]);
-        l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)];
-    }
-}
-
-static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn)
-{
-    unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1;
-
-    return !(smfn & pfn_hole_mask) &&
-           find_next_bit(pdx_group_valid, sz,
-                         pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz;
-}
-
-static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn)
-{
-    return 1;
-}
-#endif
-
-#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \
-                                 (EFI_PAGE_SHIFT + BITS_PER_LONG - 32))
-
-void __init efi_init_memory(void)
-{
-    unsigned int i;
-#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
-    struct rt_extra {
-        struct rt_extra *next;
-        unsigned long smfn, emfn;
-        unsigned int prot;
-    } *extra, *extra_head = NULL;
-#endif
-
-    printk(XENLOG_INFO "EFI memory map:\n");
-    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
-    {
-        EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
-        u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
-        unsigned long smfn, emfn;
-        unsigned int prot = PAGE_HYPERVISOR;
-
-        printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64
-                           " type=%u attr=%016" PRIx64 "\n",
-               desc->PhysicalStart, desc->PhysicalStart + len - 1,
-               desc->Type, desc->Attribute);
-
-        if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) )
-            continue;
-
-        desc->VirtualStart = INVALID_VIRTUAL_ADDRESS;
-
-        smfn = PFN_DOWN(desc->PhysicalStart);
-        emfn = PFN_UP(desc->PhysicalStart + len);
-
-        if ( desc->Attribute & EFI_MEMORY_WB )
-            /* nothing */;
-        else if ( desc->Attribute & EFI_MEMORY_WT )
-            prot |= _PAGE_PWT | MAP_SMALL_PAGES;
-        else if ( desc->Attribute & EFI_MEMORY_WC )
-            prot |= _PAGE_PAT | MAP_SMALL_PAGES;
-        else if ( desc->Attribute & (EFI_MEMORY_UC | EFI_MEMORY_UCE) )
-            prot |= _PAGE_PWT | _PAGE_PCD | MAP_SMALL_PAGES;
-        else
-        {
-            printk(XENLOG_ERR "Unknown cachability for MFNs %#lx-%#lx\n",
-                   smfn, emfn - 1);
-            continue;
-        }
-
-        if ( desc->Attribute & EFI_MEMORY_WP )
-            prot &= _PAGE_RW;
-        if ( desc->Attribute & EFI_MEMORY_XP )
-            prot |= _PAGE_NX_BIT;
-
-        if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) &&
-             !(smfn & pfn_hole_mask) &&
-             !((smfn ^ (emfn - 1)) & ~pfn_pdx_bottom_mask) )
-        {
-            if ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END )
-                prot &= ~_PAGE_GLOBAL;
-            if ( map_pages_to_xen((unsigned long)mfn_to_virt(smfn),
-                                  smfn, emfn - smfn, prot) == 0 )
-                desc->VirtualStart =
-                    (unsigned long)maddr_to_virt(desc->PhysicalStart);
-            else
-                printk(XENLOG_ERR "Could not map MFNs %#lx-%#lx\n",
-                       smfn, emfn - 1);
-        }
-#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
-        else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) &&
-                  (extra = xmalloc(struct rt_extra)) != NULL )
-        {
-            extra->smfn = smfn;
-            extra->emfn = emfn;
-            extra->prot = prot & ~_PAGE_GLOBAL;
-            extra->next = extra_head;
-            extra_head = extra;
-            desc->VirtualStart = desc->PhysicalStart;
-        }
-#endif
-        else
-        {
-#ifdef USE_SET_VIRTUAL_ADDRESS_MAP
-            /* XXX allocate e.g. down from FIXADDR_START */
-#endif
-            printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n",
-                   smfn, emfn - 1);
-        }
-    }
-
-#ifdef USE_SET_VIRTUAL_ADDRESS_MAP
-    efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size,
-                                 mdesc_ver, efi_memmap);
-#else
-    /* Set up 1:1 page tables to do runtime calls in "physical" mode. */
-    efi_l4_pgtable = alloc_xen_pagetable();
-    BUG_ON(!efi_l4_pgtable);
-    clear_page(efi_l4_pgtable);
-
-    copy_mapping(0, max_page, ram_range_valid);
-
-    /* Insert non-RAM runtime mappings inside the direct map. */
-    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
-    {
-        const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
-
-        if ( (desc->Attribute & EFI_MEMORY_RUNTIME) &&
-             desc->VirtualStart != INVALID_VIRTUAL_ADDRESS &&
-             desc->VirtualStart != desc->PhysicalStart )
-            copy_mapping(PFN_DOWN(desc->PhysicalStart),
-                         PFN_UP(desc->PhysicalStart +
-                                (desc->NumberOfPages << EFI_PAGE_SHIFT)),
-                         rt_range_valid);
-    }
-
-    /* Insert non-RAM runtime mappings outside of the direct map. */
-    while ( (extra = extra_head) != NULL )
-    {
-        unsigned long addr = extra->smfn << PAGE_SHIFT;
-        l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)];
-        l3_pgentry_t *pl3e;
-        l2_pgentry_t *pl2e;
-        l1_pgentry_t *l1t;
-
-        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
-        {
-            pl3e = alloc_xen_pagetable();
-            BUG_ON(!pl3e);
-            clear_page(pl3e);
-            efi_l4_pgtable[l4_table_offset(addr)] =
-                l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR);
-        }
-        else
-            pl3e = l4e_to_l3e(l4e);
-        pl3e += l3_table_offset(addr);
-        if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
-        {
-            pl2e = alloc_xen_pagetable();
-            BUG_ON(!pl2e);
-            clear_page(pl2e);
-            *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR);
-        }
-        else
-        {
-            BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE);
-            pl2e = l3e_to_l2e(*pl3e);
-        }
-        pl2e += l2_table_offset(addr);
-        if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
-        {
-            l1t = alloc_xen_pagetable();
-            BUG_ON(!l1t);
-            clear_page(l1t);
-            *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR);
-        }
-        else
-        {
-            BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE);
-            l1t = l2e_to_l1e(*pl2e);
-        }
-        for ( i = l1_table_offset(addr);
-              i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn;
-              ++i, ++extra->smfn )
-            l1t[i] = l1e_from_pfn(extra->smfn, extra->prot);
-
-        if ( extra->smfn == extra->emfn )
-        {
-            extra_head = extra->next;
-            xfree(extra);
-        }
-    }
-
-    /* Insert Xen mappings. */
-    for ( i = l4_table_offset(HYPERVISOR_VIRT_START);
-          i < l4_table_offset(DIRECTMAP_VIRT_END); ++i )
-        efi_l4_pgtable[i] = idle_pg_table[i];
-#endif
-}
diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h
new file mode 100644
index 0000000..4ad83ca
--- /dev/null
+++ b/xen/include/asm-x86/efi-boot.h
@@ -0,0 +1,451 @@ 
+/*
+ * Architecture specific implementation for EFI boot code.  This file
+ * is intended to be included by XXX _only_, and therefore can define
+ * arch specific global variables.
+ */
+#include <asm/e820.h>
+#include <asm/edd.h>
+#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */
+#include <asm/fixmap.h>
+#undef __ASSEMBLY__
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+static struct file __initdata ucode;
+static multiboot_info_t __initdata mbi = {
+    .flags = MBI_MODULES | MBI_LOADERNAME
+};
+static module_t __initdata mb_modules[3];
+
+static void noreturn blexit(const CHAR16 *str);
+static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);
+
+/* Using SetVirtualAddressMap() is incompatible with kexec: */
+#undef USE_SET_VIRTUAL_ADDRESS_MAP
+extern char start[];
+extern u32 cpuid_ext_features;
+
+static void __init edd_put_string(u8 *dst, size_t n, const char *src)
+{
+    while ( n-- && *src )
+       *dst++ = *src++;
+    if ( *src )
+       PrintErrMesg(L"Internal error populating EDD info",
+                    EFI_BUFFER_TOO_SMALL);
+    while ( n-- )
+       *dst++ = ' ';
+}
+#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s)
+
+static void __init efi_arch_pci(void)
+{
+    EFI_STATUS status;
+    EFI_HANDLE *handles;
+    static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL;
+    UINTN i, nr_pci, size = 0;
+    struct efi_pci_rom *last = NULL;
+
+    status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, NULL);
+    if ( status == EFI_BUFFER_TOO_SMALL )
+        status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles);
+    if ( !EFI_ERROR(status) )
+        status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size,
+                                      handles);
+    if ( EFI_ERROR(status) )
+        size = 0;
+
+    nr_pci = size / sizeof(*handles);
+    for ( i = 0; i < nr_pci; ++i )
+    {
+        EFI_PCI_IO *pci = NULL;
+        u64 attributes;
+        struct efi_pci_rom *rom, *va;
+        UINTN segment, bus, device, function;
+
+        status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci);
+        if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize )
+            continue;
+
+        status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0,
+                                 &attributes);
+        if ( EFI_ERROR(status) ||
+             !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) ||
+             EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device,
+                       &function)) )
+            continue;
+
+        DisplayUint(segment, 4);
+        PrintStr(L":");
+        DisplayUint(bus, 2);
+        PrintStr(L":");
+        DisplayUint(device, 2);
+        PrintStr(L".");
+        DisplayUint(function, 1);
+        PrintStr(L": ROM: ");
+        DisplayUint(pci->RomSize, 0);
+        PrintStr(L" bytes at ");
+        DisplayUint((UINTN)pci->RomImage, 0);
+        PrintStr(newline);
+
+        size = pci->RomSize + sizeof(*rom);
+        status = efi_bs->AllocatePool(EfiRuntimeServicesData, size,
+                                      (void **)&rom);
+        if ( EFI_ERROR(status) )
+            continue;
+
+        rom->next = NULL;
+        rom->size = pci->RomSize;
+
+        status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1,
+                               &rom->vendor);
+        if ( !EFI_ERROR(status) )
+            status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1,
+                                   &rom->devid);
+        if ( EFI_ERROR(status) )
+        {
+            efi_bs->FreePool(rom);
+            continue;
+        }
+
+        rom->segment = segment;
+        rom->bus = bus;
+        rom->devfn = (device << 3) | function;
+        memcpy(rom->data, pci->RomImage, pci->RomSize);
+
+        va = (void *)rom + DIRECTMAP_VIRT_START;
+        if ( last )
+            last->next = va;
+        else
+            efi_pci_roms = va;
+        last = rom;
+    }
+
+    efi_bs->FreePool(handles);
+}
+
+extern const intpte_t __page_tables_start[], __page_tables_end[];
+#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \
+                           (intpte_t *)(v) < __page_tables_end)
+
+#define PE_BASE_RELOC_ABS      0
+#define PE_BASE_RELOC_HIGHLOW  3
+#define PE_BASE_RELOC_DIR64   10
+
+extern const struct pe_base_relocs {
+    u32 rva;
+    u32 size;
+    u16 entries[];
+} __base_relocs_start[], __base_relocs_end[];
+
+static void __init efi_arch_relocate_image(unsigned long delta)
+{
+    const struct pe_base_relocs *base_relocs;
+
+    for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; )
+    {
+        unsigned int i, n;
+
+        n = (base_relocs->size - sizeof(*base_relocs)) /
+            sizeof(*base_relocs->entries);
+        for ( i = 0; i < n; ++i )
+        {
+            unsigned long addr = xen_phys_start + base_relocs->rva +
+                                 (base_relocs->entries[i] & 0xfff);
+
+            switch ( base_relocs->entries[i] >> 12 )
+            {
+            case PE_BASE_RELOC_ABS:
+                break;
+            case PE_BASE_RELOC_HIGHLOW:
+                if ( delta )
+                {
+                    *(u32 *)addr += delta;
+                    if ( in_page_tables(addr) )
+                        *(u32 *)addr += xen_phys_start;
+                }
+                break;
+            case PE_BASE_RELOC_DIR64:
+                if ( delta )
+                {
+                    *(u64 *)addr += delta;
+                    if ( in_page_tables(addr) )
+                        *(intpte_t *)addr += xen_phys_start;
+                }
+                break;
+            default:
+                blexit(L"Unsupported relocation type");
+            }
+        }
+        base_relocs = (const void *)(base_relocs->entries + i + (i & 1));
+    }
+}
+
+extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[];
+extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[];
+
+static void __init relocate_trampoline(unsigned long phys)
+{
+    const s32 *trampoline_ptr;
+
+    trampoline_phys = phys;
+    /* Apply relocations to trampoline. */
+    for ( trampoline_ptr = __trampoline_rel_start;
+          trampoline_ptr < __trampoline_rel_stop;
+          ++trampoline_ptr )
+        *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys;
+    for ( trampoline_ptr = __trampoline_seg_start;
+          trampoline_ptr < __trampoline_seg_stop;
+          ++trampoline_ptr )
+        *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4;
+}
+
+#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
+static __init void copy_mapping(unsigned long mfn, unsigned long end,
+                                bool_t (*is_valid)(unsigned long smfn,
+                                                   unsigned long emfn))
+{
+    unsigned long next;
+
+    for ( ; mfn < end; mfn = next )
+    {
+        l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)];
+        l3_pgentry_t *l3src, *l3dst;
+        unsigned long va = (unsigned long)mfn_to_virt(mfn);
+
+        next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT));
+        if ( !is_valid(mfn, min(next, end)) )
+            continue;
+        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
+        {
+            l3dst = alloc_xen_pagetable();
+            BUG_ON(!l3dst);
+            clear_page(l3dst);
+            efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] =
+                l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR);
+        }
+        else
+            l3dst = l4e_to_l3e(l4e);
+        l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]);
+        l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)];
+    }
+}
+
+static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn)
+{
+    unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1;
+
+    return !(smfn & pfn_hole_mask) &&
+           find_next_bit(pdx_group_valid, sz,
+                         pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz;
+}
+
+static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn)
+{
+    return 1;
+}
+#endif
+
+#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \
+                                 (EFI_PAGE_SHIFT + BITS_PER_LONG - 32))
+void __init efi_init_memory(void)
+{
+    unsigned int i;
+#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
+    struct rt_extra {
+        struct rt_extra *next;
+        unsigned long smfn, emfn;
+        unsigned int prot;
+    } *extra, *extra_head = NULL;
+#endif
+
+    printk(XENLOG_INFO "EFI memory map:\n");
+    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+    {
+        EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+        u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+        unsigned long smfn, emfn;
+        unsigned int prot = PAGE_HYPERVISOR;
+
+        printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64
+                           " type=%u attr=%016" PRIx64 "\n",
+               desc->PhysicalStart, desc->PhysicalStart + len - 1,
+               desc->Type, desc->Attribute);
+
+        if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) )
+            continue;
+
+        desc->VirtualStart = INVALID_VIRTUAL_ADDRESS;
+
+        smfn = PFN_DOWN(desc->PhysicalStart);
+        emfn = PFN_UP(desc->PhysicalStart + len);
+
+        if ( desc->Attribute & EFI_MEMORY_WB )
+            /* nothing */;
+        else if ( desc->Attribute & EFI_MEMORY_WT )
+            prot |= _PAGE_PWT | MAP_SMALL_PAGES;
+        else if ( desc->Attribute & EFI_MEMORY_WC )
+            prot |= _PAGE_PAT | MAP_SMALL_PAGES;
+        else if ( desc->Attribute & (EFI_MEMORY_UC | EFI_MEMORY_UCE) )
+            prot |= _PAGE_PWT | _PAGE_PCD | MAP_SMALL_PAGES;
+        else
+        {
+            printk(XENLOG_ERR "Unknown cachability for MFNs %#lx-%#lx\n",
+                   smfn, emfn - 1);
+            continue;
+        }
+
+        if ( desc->Attribute & EFI_MEMORY_WP )
+            prot &= _PAGE_RW;
+        if ( desc->Attribute & EFI_MEMORY_XP )
+            prot |= _PAGE_NX_BIT;
+
+        if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) &&
+             !(smfn & pfn_hole_mask) &&
+             !((smfn ^ (emfn - 1)) & ~pfn_pdx_bottom_mask) )
+        {
+            if ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END )
+                prot &= ~_PAGE_GLOBAL;
+            if ( map_pages_to_xen((unsigned long)mfn_to_virt(smfn),
+                                  smfn, emfn - smfn, prot) == 0 )
+                desc->VirtualStart =
+                    (unsigned long)maddr_to_virt(desc->PhysicalStart);
+            else
+                printk(XENLOG_ERR "Could not map MFNs %#lx-%#lx\n",
+                       smfn, emfn - 1);
+        }
+#ifndef USE_SET_VIRTUAL_ADDRESS_MAP
+        else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) &&
+                  (extra = xmalloc(struct rt_extra)) != NULL )
+        {
+            extra->smfn = smfn;
+            extra->emfn = emfn;
+            extra->prot = prot & ~_PAGE_GLOBAL;
+            extra->next = extra_head;
+            extra_head = extra;
+            desc->VirtualStart = desc->PhysicalStart;
+        }
+#endif
+        else
+        {
+#ifdef USE_SET_VIRTUAL_ADDRESS_MAP
+            /* XXX allocate e.g. down from FIXADDR_START */
+#endif
+            printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n",
+                   smfn, emfn - 1);
+        }
+    }
+
+#ifdef USE_SET_VIRTUAL_ADDRESS_MAP
+    efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size,
+                                 mdesc_ver, efi_memmap);
+#else
+    /* Set up 1:1 page tables to do runtime calls in "physical" mode. */
+    efi_l4_pgtable = alloc_xen_pagetable();
+    BUG_ON(!efi_l4_pgtable);
+    clear_page(efi_l4_pgtable);
+
+    copy_mapping(0, max_page, ram_range_valid);
+
+    /* Insert non-RAM runtime mappings inside the direct map. */
+    for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+    {
+        const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+
+        if ( (desc->Attribute & EFI_MEMORY_RUNTIME) &&
+             desc->VirtualStart != INVALID_VIRTUAL_ADDRESS &&
+             desc->VirtualStart != desc->PhysicalStart )
+            copy_mapping(PFN_DOWN(desc->PhysicalStart),
+                         PFN_UP(desc->PhysicalStart +
+                                (desc->NumberOfPages << EFI_PAGE_SHIFT)),
+                         rt_range_valid);
+    }
+
+    /* Insert non-RAM runtime mappings outside of the direct map. */
+    while ( (extra = extra_head) != NULL )
+    {
+        unsigned long addr = extra->smfn << PAGE_SHIFT;
+        l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)];
+        l3_pgentry_t *pl3e;
+        l2_pgentry_t *pl2e;
+        l1_pgentry_t *l1t;
+
+        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
+        {
+            pl3e = alloc_xen_pagetable();
+            BUG_ON(!pl3e);
+            clear_page(pl3e);
+            efi_l4_pgtable[l4_table_offset(addr)] =
+                l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR);
+        }
+        else
+            pl3e = l4e_to_l3e(l4e);
+        pl3e += l3_table_offset(addr);
+        if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
+        {
+            pl2e = alloc_xen_pagetable();
+            BUG_ON(!pl2e);
+            clear_page(pl2e);
+            *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR);
+        }
+        else
+        {
+            BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE);
+            pl2e = l3e_to_l2e(*pl3e);
+        }
+        pl2e += l2_table_offset(addr);
+        if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
+        {
+            l1t = alloc_xen_pagetable();
+            BUG_ON(!l1t);
+            clear_page(l1t);
+            *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR);
+        }
+        else
+        {
+            BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE);
+            l1t = l2e_to_l1e(*pl2e);
+        }
+        for ( i = l1_table_offset(addr);
+              i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn;
+              ++i, ++extra->smfn )
+            l1t[i] = l1e_from_pfn(extra->smfn, extra->prot);
+
+        if ( extra->smfn == extra->emfn )
+        {
+            extra_head = extra->next;
+            xfree(extra);
+        }
+    }
+
+    /* Insert Xen mappings. */
+    for ( i = l4_table_offset(HYPERVISOR_VIRT_START);
+          i < l4_table_offset(DIRECTMAP_VIRT_END); ++i )
+        efi_l4_pgtable[i] = idle_pg_table[i];
+#endif
+}
+
+static void __init place_string(u32 *addr, const char *s)
+{
+    static char *__initdata alloc = start;
+
+    if ( s && *s )
+    {
+        size_t len1 = strlen(s) + 1;
+        const char *old = (char *)(long)*addr;
+        size_t len2 = *addr ? strlen(old) + 1 : 0;
+
+        alloc -= len1 + len2;
+        /*
+         * Insert new string before already existing one. This is needed
+         * for options passed on the command line to override options from
+         * the configuration file.
+         */
+        memcpy(alloc, s, len1);
+        if ( *addr )
+        {
+            alloc[len1 - 1] = ' ';
+            memcpy(alloc + len1, old, len2);
+        }
+    }
+    *addr = (long)alloc;
+}